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"`
34 func (a *DopsAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) error {
37 if a.AssetId.IsZero() {
38 missing = append(missing, "asset_id")
41 missing = append(missing, "from")
44 missing = append(missing, "to")
48 return txbuilder.MissingFieldsError(missing...)
50 res, err := a.Accounts.utxoKeeper.ReserveByAddress(a.From, a.AssetId, a.Amount, a.UseUnconfirmed, false)
52 return errors.Wrap(err, "reserving utxos")
55 // Cancel the reservation if the build gets rolled back.
56 b.OnRollback(func() { a.Accounts.utxoKeeper.Cancel(res.id) })
57 for _, r := range res.utxos {
58 txInput, sigInst, err := DposTx(a.From, a.To, a.Amount, r)
60 return errors.Wrap(err, "creating inputs")
62 if err = b.AddInput(txInput, sigInst); err != nil {
63 return errors.Wrap(err, "adding inputs")
67 res, err = a.Accounts.utxoKeeper.ReserveByAddress(a.From, a.AssetId, a.Fee, a.UseUnconfirmed, true)
69 return errors.Wrap(err, "reserving utxos")
72 // Cancel the reservation if the build gets rolled back.
73 b.OnRollback(func() { a.Accounts.utxoKeeper.Cancel(res.id) })
74 for _, r := range res.utxos {
75 txSpendInput, sigInst, err := spendInput(r)
77 return errors.Wrap(err, "creating inputs")
80 if err = b.AddInput(txSpendInput, sigInst); err != nil {
81 return errors.Wrap(err, "adding inputs")
85 address, err := common.DecodeAddress(a.From, &consensus.ActiveNetParams)
89 redeemContract := address.ScriptAddress()
90 program, err := vmutil.P2WPKHProgram(redeemContract)
94 if err = b.AddOutput(types.NewTxOutput(*consensus.BTMAssetID, res.change, program)); err != nil {
95 return errors.Wrap(err, "adding change output")
102 func (a *DopsAction) ActionType() string {
106 // DposInputs convert an utxo to the txinput
107 func DposTx(from, to string, stake uint64, u *UTXO) (*types.TxInput, *txbuilder.SigningInstruction, error) {
108 txInput := types.NewDpos(nil, from, to, u.SourceID, u.AssetID, stake, u.Amount, u.SourcePos, u.ControlProgram, types.Delegate)
109 sigInst := &txbuilder.SigningInstruction{}
110 var xpubs []chainkd.XPub
111 var xprv chainkd.XPrv
112 xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
113 xpubs = append(xpubs, xprv.XPub())
116 sigInst.AddWitnessKeysWithOutPath(xpubs, quorum)
117 return txInput, sigInst, nil
120 address, err := common.DecodeAddress(u.Address, &consensus.ActiveNetParams)
124 sigInst.AddRawWitnessKeysWithoutPath(xpubs, quorum)
125 switch address.(type) {
126 case *common.AddressWitnessPubKeyHash:
127 derivedPK := xpubs[0].PublicKey()
128 sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness([]byte(derivedPK)))
130 case *common.AddressWitnessScriptHash:
131 derivedXPubs := xpubs
132 derivedPKs := chainkd.XPubKeys(derivedXPubs)
133 script, err := vmutil.P2SPMultiSigProgram(derivedPKs, quorum)
137 sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness(script))
140 return nil, nil, errors.New("unsupport address type")
143 return txInput, sigInst, nil
146 // spendInput convert an utxo to the txinput
147 func spendInput(u *UTXO) (*types.TxInput, *txbuilder.SigningInstruction, error) {
148 txSpendInput := types.NewSpendInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram)
149 sigInst := &txbuilder.SigningInstruction{}
150 var xpubs []chainkd.XPub
151 var xprv chainkd.XPrv
152 xprv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
153 xpubs = append(xpubs, xprv.XPub())
156 sigInst.AddWitnessKeysWithOutPath(xpubs, quorum)
157 return txSpendInput, sigInst, nil
160 address, err := common.DecodeAddress(u.Address, &consensus.ActiveNetParams)
164 sigInst.AddRawWitnessKeysWithoutPath(xpubs, quorum)
165 switch address.(type) {
166 case *common.AddressWitnessPubKeyHash:
167 derivedPK := xpubs[0].PublicKey()
168 sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness([]byte(derivedPK)))
170 case *common.AddressWitnessScriptHash:
171 derivedXPubs := xpubs
172 derivedPKs := chainkd.XPubKeys(derivedXPubs)
173 script, err := vmutil.P2SPMultiSigProgram(derivedPKs, quorum)
177 sigInst.WitnessComponents = append(sigInst.WitnessComponents, txbuilder.DataWitness(script))
180 return nil, nil, errors.New("unsupport address type")
183 return txSpendInput, sigInst, nil