OSDN Git Service

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