7 "github.com/vapor/config"
9 "github.com/vapor/blockchain/txbuilder"
10 "github.com/vapor/common"
11 "github.com/vapor/consensus"
12 "github.com/vapor/crypto/ed25519/chainkd"
13 "github.com/vapor/errors"
14 "github.com/vapor/protocol/bc"
15 "github.com/vapor/protocol/bc/types"
16 "github.com/vapor/protocol/vm/vmutil"
19 func (m *Manager) DecodeDposAction(data []byte) (txbuilder.Action, error) {
20 a := &DopsAction{Accounts: m}
21 err := json.Unmarshal(data, a)
25 type DopsAction struct {
28 From string `json:"from"`
30 Fee uint64 `json:"fee"`
31 UseUnconfirmed bool `json:"use_unconfirmed"`
32 TxType uint32 `json:"tx_type"`
33 Height uint64 `json:"height"`
36 func (a *DopsAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) error {
39 if a.AssetId.IsZero() {
40 missing = append(missing, "asset_id")
43 missing = append(missing, "from")
46 missing = append(missing, "to")
49 if types.TxType(a.TxType) < types.Binary || types.TxType(a.TxType) > types.ConfirmTx {
50 return errors.New("tx type of dpos is error")
53 txType := types.TxType(a.TxType)
56 return txbuilder.MissingFieldsError(missing...)
58 res, err := a.Accounts.utxoKeeper.ReserveByAddress(a.From, a.AssetId, a.Amount, a.UseUnconfirmed, false)
60 return errors.Wrap(err, "reserving utxos")
63 // Cancel the reservation if the build gets rolled back.
64 b.OnRollback(func() { a.Accounts.utxoKeeper.Cancel(res.id) })
65 for _, r := range res.utxos {
66 txInput, sigInst, err := DposTx(a.From, a.To, a.Amount, r, txType, a.Height)
68 return errors.Wrap(err, "creating inputs")
70 if err = b.AddInput(txInput, sigInst); err != nil {
71 return errors.Wrap(err, "adding inputs")
75 res, err = a.Accounts.utxoKeeper.ReserveByAddress(a.From, a.AssetId, a.Fee, a.UseUnconfirmed, true)
77 return errors.Wrap(err, "reserving utxos")
80 // Cancel the reservation if the build gets rolled back.
81 b.OnRollback(func() { a.Accounts.utxoKeeper.Cancel(res.id) })
82 for _, r := range res.utxos {
83 txSpendInput, sigInst, err := spendInput(r)
85 return errors.Wrap(err, "creating inputs")
88 if err = b.AddInput(txSpendInput, sigInst); err != nil {
89 return errors.Wrap(err, "adding inputs")
93 address, err := common.DecodeAddress(a.From, &consensus.ActiveNetParams)
97 redeemContract := address.ScriptAddress()
98 program, err := vmutil.P2WPKHProgram(redeemContract)
102 if err = b.AddOutput(types.NewTxOutput(*consensus.BTMAssetID, res.change, program)); err != nil {
103 return errors.Wrap(err, "adding change output")
110 func (a *DopsAction) ActionType() string {
114 // DposInputs convert an utxo to the txinput
115 func DposTx(from, to string, stake uint64, u *UTXO, txType types.TxType, h uint64) (*types.TxInput, *txbuilder.SigningInstruction, error) {
116 txInput := types.NewDpos(nil, from, to, u.SourceID, u.AssetID, stake, u.Amount, u.SourcePos, u.ControlProgram, txType, h)
117 sigInst := &txbuilder.SigningInstruction{}
118 var xpubs []chainkd.XPub
119 var xprv chainkd.XPrv
120 xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
121 xpubs = append(xpubs, xprv.XPub())
124 sigInst.AddWitnessKeysWithOutPath(xpubs, quorum)
125 return txInput, sigInst, nil
128 address, err := common.DecodeAddress(u.Address, &consensus.ActiveNetParams)
132 sigInst.AddRawWitnessKeysWithoutPath(xpubs, quorum)
133 switch address.(type) {
134 case *common.AddressWitnessPubKeyHash:
135 derivedPK := xpubs[0].PublicKey()
136 sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness([]byte(derivedPK)))
138 case *common.AddressWitnessScriptHash:
139 derivedXPubs := xpubs
140 derivedPKs := chainkd.XPubKeys(derivedXPubs)
141 script, err := vmutil.P2SPMultiSigProgram(derivedPKs, quorum)
145 sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness(script))
148 return nil, nil, errors.New("unsupport address type")
151 return txInput, sigInst, nil
154 // spendInput convert an utxo to the txinput
155 func spendInput(u *UTXO) (*types.TxInput, *txbuilder.SigningInstruction, error) {
156 txSpendInput := types.NewSpendInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram)
157 sigInst := &txbuilder.SigningInstruction{}
158 var xpubs []chainkd.XPub
159 var xprv chainkd.XPrv
160 xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
161 xpubs = append(xpubs, xprv.XPub())
164 sigInst.AddWitnessKeysWithOutPath(xpubs, quorum)
165 return txSpendInput, sigInst, nil
168 address, err := common.DecodeAddress(u.Address, &consensus.ActiveNetParams)
172 sigInst.AddRawWitnessKeysWithoutPath(xpubs, quorum)
173 switch address.(type) {
174 case *common.AddressWitnessPubKeyHash:
175 derivedPK := xpubs[0].PublicKey()
176 sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness([]byte(derivedPK)))
178 case *common.AddressWitnessScriptHash:
179 derivedXPubs := xpubs
180 derivedPKs := chainkd.XPubKeys(derivedXPubs)
181 script, err := vmutil.P2SPMultiSigProgram(derivedPKs, quorum)
185 sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness(script))
188 return nil, nil, errors.New("unsupport address type")
191 return txSpendInput, sigInst, nil