import (
"context"
- "encoding/json"
-
- "github.com/vapor/blockchain/signers"
- "github.com/vapor/blockchain/txbuilder"
- "github.com/vapor/common"
- "github.com/vapor/consensus"
- "github.com/vapor/crypto/ed25519/chainkd"
- "github.com/vapor/errors"
- "github.com/vapor/protocol/bc"
- "github.com/vapor/protocol/bc/types"
- "github.com/vapor/protocol/vm/vmutil"
+ stdjson "encoding/json"
+
+ "github.com/bytom/vapor/blockchain/signers"
+ "github.com/bytom/vapor/blockchain/txbuilder"
+ "github.com/bytom/vapor/common"
+ "github.com/bytom/vapor/consensus"
+ "github.com/bytom/vapor/crypto/ed25519/chainkd"
+ "github.com/bytom/vapor/encoding/json"
+ "github.com/bytom/vapor/errors"
+ "github.com/bytom/vapor/protocol/bc"
+ "github.com/bytom/vapor/protocol/bc/types"
+ "github.com/bytom/vapor/protocol/vm/vmutil"
)
var (
//chainTxUtxoNum maximum utxo quantity in a tx
- chainTxUtxoNum = 5
+ chainTxUtxoNum = 20
//chainTxMergeGas chain tx gas
- chainTxMergeGas = uint64(10000000)
+ chainTxMergeGas = uint64(0)
)
//DecodeSpendAction unmarshal JSON-encoded data of spend action
func (m *Manager) DecodeSpendAction(data []byte) (txbuilder.Action, error) {
a := &spendAction{accounts: m}
- return a, json.Unmarshal(data, a)
+ return a, stdjson.Unmarshal(data, a)
}
type spendAction struct {
utxos := []*UTXO{}
for gasAmount := uint64(0); reservedAmount < gasAmount+amount; gasAmount = calcMergeGas(len(utxos)) {
reserveAmount := amount + gasAmount - reservedAmount
- res, err := m.utxoKeeper.Reserve(accountID, consensus.BTMAssetID, reserveAmount, useUnconfirmed, builder.MaxTime())
+ res, err := m.utxoKeeper.Reserve(accountID, consensus.BTMAssetID, reserveAmount, useUnconfirmed, nil, builder.MaxTime())
if err != nil {
return nil, err
}
return utxos, nil
}
-func (m *Manager) buildBtmTxChain(utxos []*UTXO, signer *signers.Signer) ([]*txbuilder.Template, *UTXO, error) {
+func (m *Manager) BuildBtmTxChain(utxos []*UTXO, signer *signers.Signer) ([]*txbuilder.Template, *UTXO, error) {
if len(utxos) == 0 {
return nil, nil, errors.New("mergeSpendActionUTXO utxos num 0")
}
if !ok {
return nil, errors.New("fail to convert the spend action")
}
+
if *act.AssetId != *consensus.BTMAssetID {
return nil, errors.New("spend chain action only support BTM")
}
return nil, err
}
- tpls, utxo, err := act.accounts.buildBtmTxChain(utxos, acct.Signer)
+ tpls, utxo, err := act.accounts.BuildBtmTxChain(utxos, acct.Signer)
if err != nil {
return nil, err
}
return errors.Wrap(err, "get account info")
}
- res, err := a.accounts.utxoKeeper.Reserve(a.AccountID, a.AssetId, a.Amount, a.UseUnconfirmed, b.MaxTime())
+ res, err := a.accounts.utxoKeeper.Reserve(a.AccountID, a.AssetId, a.Amount, a.UseUnconfirmed, nil, b.MaxTime())
if err != nil {
return errors.Wrap(err, "reserving utxos")
}
//DecodeSpendUTXOAction unmarshal JSON-encoded data of spend utxo action
func (m *Manager) DecodeSpendUTXOAction(data []byte) (txbuilder.Action, error) {
a := &spendUTXOAction{accounts: m}
- return a, json.Unmarshal(data, a)
+ return a, stdjson.Unmarshal(data, a)
}
type spendUTXOAction struct {
// UtxoToInputs convert an utxo to the txinput
func UtxoToInputs(signer *signers.Signer, u *UTXO) (*types.TxInput, *txbuilder.SigningInstruction, error) {
- txInput := types.NewSpendInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram)
+ txInput := &types.TxInput{}
+ if u.Vote == nil {
+ txInput = types.NewSpendInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram)
+ } else {
+ txInput = types.NewVetoInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram, u.Vote)
+ }
sigInst := &txbuilder.SigningInstruction{}
if signer == nil {
return txInput, sigInst, nil
if err != nil {
return nil, nil, err
}
+
if u.Address == "" {
sigInst.AddWitnessKeys(signer.XPubs, path, signer.Quorum)
return txInput, sigInst, nil
if len(acps) == 0 {
return nil
}
+
return m.SaveControlPrograms(acps...)
})
}
+
+//DecodeVetoAction unmarshal JSON-encoded data of spend action
+func (m *Manager) DecodeVetoAction(data []byte) (txbuilder.Action, error) {
+ a := &vetoAction{accounts: m}
+ return a, stdjson.Unmarshal(data, a)
+}
+
+type vetoAction struct {
+ accounts *Manager
+ bc.AssetAmount
+ AccountID string `json:"account_id"`
+ Vote json.HexBytes `json:"vote"`
+ UseUnconfirmed bool `json:"use_unconfirmed"`
+}
+
+func (a *vetoAction) ActionType() string {
+ return "veto"
+}
+
+func (a *vetoAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) error {
+ var missing []string
+ if a.AccountID == "" {
+ missing = append(missing, "account_id")
+ }
+ if a.AssetId.IsZero() {
+ missing = append(missing, "asset_id")
+ }
+ if len(missing) > 0 {
+ return txbuilder.MissingFieldsError(missing...)
+ }
+
+ acct, err := a.accounts.FindByID(a.AccountID)
+ if err != nil {
+ return errors.Wrap(err, "get account info")
+ }
+
+ res, err := a.accounts.utxoKeeper.Reserve(a.AccountID, a.AssetId, a.Amount, a.UseUnconfirmed, a.Vote, b.MaxTime())
+ if err != nil {
+ return errors.Wrap(err, "reserving utxos")
+ }
+
+ // Cancel the reservation if the build gets rolled back.
+ b.OnRollback(func() { a.accounts.utxoKeeper.Cancel(res.id) })
+ for _, r := range res.utxos {
+ txInput, sigInst, err := UtxoToInputs(acct.Signer, r)
+ if err != nil {
+ return errors.Wrap(err, "creating inputs")
+ }
+
+ if err = b.AddInput(txInput, sigInst); err != nil {
+ return errors.Wrap(err, "adding inputs")
+ }
+ }
+
+ if res.change > 0 {
+ acp, err := a.accounts.CreateAddress(a.AccountID, true)
+ if err != nil {
+ return errors.Wrap(err, "creating control program")
+ }
+
+ // Don't insert the control program until callbacks are executed.
+ a.accounts.insertControlProgramDelayed(b, acp)
+ if err = b.AddOutput(types.NewVoteOutput(*a.AssetId, res.change, acp.ControlProgram, a.Vote)); err != nil {
+ return errors.Wrap(err, "adding change voteOutput")
+ }
+ }
+ return nil
+}