OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / account / builder.go
index ca3c2da..5f2448a 100644 (file)
@@ -2,13 +2,14 @@ package account
 
 import (
        "context"
-       "encoding/json"
+       stdjson "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/encoding/json"
        "github.com/vapor/errors"
        "github.com/vapor/protocol/bc"
        "github.com/vapor/protocol/bc/types"
@@ -25,7 +26,7 @@ var (
 //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 {
@@ -77,7 +78,7 @@ func (m *Manager) reserveBtmUtxoChain(builder *txbuilder.TemplateBuilder, accoun
        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
                }
@@ -122,7 +123,7 @@ func (m *Manager) buildBtmTxChain(utxos []*UTXO, signer *signers.Signer) ([]*txb
                }
 
                outAmount := buildAmount - chainTxMergeGas
-               output := types.NewTxOutput(*consensus.BTMAssetID, outAmount, acp.ControlProgram)
+               output := types.NewIntraChainOutput(*consensus.BTMAssetID, outAmount, acp.ControlProgram)
                if err := builder.AddOutput(output); err != nil {
                        return nil, nil, err
                }
@@ -132,7 +133,7 @@ func (m *Manager) buildBtmTxChain(utxos []*UTXO, signer *signers.Signer) ([]*txb
                        return nil, nil, err
                }
 
-               bcOut, err := tpl.Transaction.Output(*tpl.Transaction.ResultIds[0])
+               bcOut, err := tpl.Transaction.IntraChainOutput(*tpl.Transaction.ResultIds[0])
                if err != nil {
                        return nil, nil, err
                }
@@ -194,7 +195,7 @@ func SpendAccountChain(ctx context.Context, builder *txbuilder.TemplateBuilder,
        }
 
        if utxo.Amount > act.Amount {
-               if err = builder.AddOutput(types.NewTxOutput(*consensus.BTMAssetID, utxo.Amount-act.Amount, utxo.ControlProgram)); err != nil {
+               if err = builder.AddOutput(types.NewIntraChainOutput(*consensus.BTMAssetID, utxo.Amount-act.Amount, utxo.ControlProgram)); err != nil {
                        return nil, errors.Wrap(err, "adding change output")
                }
        }
@@ -218,7 +219,7 @@ func (a *spendAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) e
                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")
        }
@@ -244,7 +245,7 @@ func (a *spendAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) e
 
                // Don't insert the control program until callbacks are executed.
                a.accounts.insertControlProgramDelayed(b, acp)
-               if err = b.AddOutput(types.NewTxOutput(*a.AssetId, res.change, acp.ControlProgram)); err != nil {
+               if err = b.AddOutput(types.NewIntraChainOutput(*a.AssetId, res.change, acp.ControlProgram)); err != nil {
                        return errors.Wrap(err, "adding change output")
                }
        }
@@ -254,7 +255,7 @@ func (a *spendAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) e
 //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 {
@@ -308,7 +309,12 @@ func (a *spendUTXOAction) Build(ctx context.Context, b *txbuilder.TemplateBuilde
 
 // 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
@@ -379,3 +385,71 @@ func (m *Manager) insertControlProgramDelayed(b *txbuilder.TemplateBuilder, acp
                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
+}