OSDN Git Service

add ipfs client
[bytom/vapor.git] / blockchain / txbuilder / actions.go
1 package txbuilder
2
3 import (
4         "context"
5         stdjson "encoding/json"
6         "errors"
7         "fmt"
8         "io"
9         "os"
10         "strings"
11
12         ipfs "github.com/ipfs/go-ipfs-api"
13         "github.com/vapor/common"
14         "github.com/vapor/consensus"
15         "github.com/vapor/encoding/json"
16         "github.com/vapor/protocol/bc"
17         "github.com/vapor/protocol/bc/types"
18         "github.com/vapor/protocol/vm/vmutil"
19 )
20
21 // DecodeControlAddressAction convert input data to action struct
22 func DecodeControlAddressAction(data []byte) (Action, error) {
23         a := new(controlAddressAction)
24         err := stdjson.Unmarshal(data, a)
25         return a, err
26 }
27
28 type controlAddressAction struct {
29         bc.AssetAmount
30         Address string `json:"address"`
31 }
32
33 func (a *controlAddressAction) Build(ctx context.Context, b *TemplateBuilder) error {
34         var missing []string
35         if a.Address == "" {
36                 missing = append(missing, "address")
37         }
38         if a.AssetId.IsZero() {
39                 missing = append(missing, "asset_id")
40         }
41         if a.Amount == 0 {
42                 missing = append(missing, "amount")
43         }
44         if len(missing) > 0 {
45                 return MissingFieldsError(missing...)
46         }
47
48         address, err := common.DecodeAddress(a.Address, &consensus.ActiveNetParams)
49         if err != nil {
50                 return err
51         }
52         redeemContract := address.ScriptAddress()
53         program := []byte{}
54
55         switch address.(type) {
56         case *common.AddressWitnessPubKeyHash:
57                 program, err = vmutil.P2WPKHProgram(redeemContract)
58         case *common.AddressWitnessScriptHash:
59                 program, err = vmutil.P2WSHProgram(redeemContract)
60         default:
61                 return errors.New("unsupport address type")
62         }
63         if err != nil {
64                 return err
65         }
66
67         out := types.NewTxOutput(*a.AssetId, a.Amount, program)
68         return b.AddOutput(out)
69 }
70
71 func (a *controlAddressAction) ActionType() string {
72         return "control_address"
73 }
74
75 // DecodeControlProgramAction convert input data to action struct
76 func DecodeControlProgramAction(data []byte) (Action, error) {
77         a := new(controlProgramAction)
78         err := stdjson.Unmarshal(data, a)
79         return a, err
80 }
81
82 type controlProgramAction struct {
83         bc.AssetAmount
84         Program json.HexBytes `json:"control_program"`
85 }
86
87 func (a *controlProgramAction) Build(ctx context.Context, b *TemplateBuilder) error {
88         var missing []string
89         if len(a.Program) == 0 {
90                 missing = append(missing, "control_program")
91         }
92         if a.AssetId.IsZero() {
93                 missing = append(missing, "asset_id")
94         }
95         if a.Amount == 0 {
96                 missing = append(missing, "amount")
97         }
98         if len(missing) > 0 {
99                 return MissingFieldsError(missing...)
100         }
101
102         out := types.NewTxOutput(*a.AssetId, a.Amount, a.Program)
103         return b.AddOutput(out)
104 }
105
106 func (a *controlProgramAction) ActionType() string {
107         return "control_program"
108 }
109
110 // DecodeRetireAction convert input data to action struct
111 func DecodeRetireAction(data []byte) (Action, error) {
112         a := new(retireAction)
113         err := stdjson.Unmarshal(data, a)
114         return a, err
115 }
116
117 type retireAction struct {
118         bc.AssetAmount
119         Arbitrary json.HexBytes `json:"arbitrary"`
120 }
121
122 func (a *retireAction) Build(ctx context.Context, b *TemplateBuilder) error {
123         var missing []string
124         if a.AssetId.IsZero() {
125                 missing = append(missing, "asset_id")
126         }
127         if a.Amount == 0 {
128                 missing = append(missing, "amount")
129         }
130         if len(missing) > 0 {
131                 return MissingFieldsError(missing...)
132         }
133
134         program, err := vmutil.RetireProgram(a.Arbitrary)
135         if err != nil {
136                 return err
137         }
138         out := types.NewTxOutput(*a.AssetId, a.Amount, program)
139         return b.AddOutput(out)
140 }
141
142 func (a *retireAction) ActionType() string {
143         return "retire"
144 }
145
146 const (
147         file uint32 = iota
148         data
149 )
150
151 type dataAction struct {
152         Type uint32 `json:"type"`
153         Data string `json:"data"`
154 }
155
156 func (a *dataAction) Build(ctx context.Context, b *TemplateBuilder) error {
157
158         var r io.Reader
159
160         switch a.Type {
161         case file:
162                 // 检查文件是否存在
163                 fi, err := os.Stat(a.Data)
164                 if os.IsNotExist(err) {
165                         return err
166                 }
167                 if fi.IsDir() {
168                         return fmt.Errorf("data [%s] is directory", a.Data)
169                 }
170                 r, err = os.Open(a.Data)
171                 if err != nil {
172                         return err
173                 }
174
175         case data:
176                 if a.Data == "" {
177                         return errors.New("data is empty")
178                 }
179                 // 生成文件对象
180                 r = strings.NewReader(a.Data)
181         default:
182         }
183
184         // 连接ipfs节点
185         sh := ipfs.NewShell("localhost:5001")
186         cid, err := sh.Add(r)
187         if err != nil {
188                 return err
189         }
190
191         fmt.Println(cid)
192
193         return nil
194 }