OSDN Git Service

modify utxo pending number and consensus node vote restrict (#285)
authoroysheng <33340252+oysheng@users.noreply.github.com>
Wed, 17 Jul 2019 01:47:22 +0000 (09:47 +0800)
committerPaladz <yzhu101@uottawa.ca>
Wed, 17 Jul 2019 01:47:22 +0000 (09:47 +0800)
* modify utxo pending number

* add consensus node vote restrict

* fix test

* modify validate vote tx

* modify config

* unit test

* add error

* optimise

* optimise

* optimise

* optimise config

* apply Tx

* delete

* optimise

api/errors.go
blockchain/txbuilder/finalize.go
consensus/general.go
proposal/proposal.go
protocol/state/consensus_result.go
protocol/state/utxo_view_test.go
protocol/tx.go
protocol/validation/tx.go
wallet/utxo_test.go

index 5391d07..5f8fe2f 100644 (file)
@@ -12,6 +12,7 @@ import (
        "github.com/vapor/errors"
        "github.com/vapor/net/http/httperror"
        "github.com/vapor/net/http/httpjson"
+       "github.com/vapor/protocol"
        "github.com/vapor/protocol/validation"
        "github.com/vapor/protocol/vm"
 )
@@ -56,22 +57,25 @@ var respErrFormatter = map[error]httperror.Info{
 
        // Transaction error namespace (7xx)
        // Build transaction error namespace (70x ~ 72x)
-       account.ErrInsufficient:         {400, "BTM700", "Funds of account are insufficient"},
-       account.ErrImmature:             {400, "BTM701", "Available funds of account are immature"},
-       account.ErrReserved:             {400, "BTM702", "Available UTXOs of account have been reserved"},
-       account.ErrMatchUTXO:            {400, "BTM703", "UTXO with given hash not found"},
-       ErrBadActionType:                {400, "BTM704", "Invalid action type"},
-       ErrBadAction:                    {400, "BTM705", "Invalid action object"},
-       ErrBadActionConstruction:        {400, "BTM706", "Invalid action construction"},
-       txbuilder.ErrMissingFields:      {400, "BTM707", "One or more fields are missing"},
-       txbuilder.ErrBadAmount:          {400, "BTM708", "Invalid asset amount"},
-       account.ErrFindAccount:          {400, "BTM709", "Account not found"},
-       asset.ErrFindAsset:              {400, "BTM710", "Asset not found"},
-       txbuilder.ErrBadContractArgType: {400, "BTM711", "Invalid contract argument type"},
-       txbuilder.ErrOrphanTx:           {400, "BTM712", "Transaction input UTXO not found"},
-       txbuilder.ErrExtTxFee:           {400, "BTM713", "Transaction fee exceeded max limit"},
-       txbuilder.ErrNoGasInput:         {400, "BTM714", "Transaction has no gas input"},
-       account.ErrVoteLock:             {400, "BTM715", "Locked by the vote"},
+       account.ErrInsufficient: {400, "BTM700", "Funds of account are insufficient"},
+       account.ErrImmature:     {400, "BTM701", "Available funds of account are immature"},
+       account.ErrReserved:     {400, "BTM702", "Available UTXOs of account have been reserved"},
+       account.ErrMatchUTXO:    {400, "BTM703", "UTXO with given hash not found"},
+       account.ErrVoteLock:     {400, "BTM704", "Locked by the vote"},
+       account.ErrFindAccount:  {400, "BTM705", "Account not found"},
+       asset.ErrFindAsset:      {400, "BTM706", "Asset not found"},
+
+       ErrBadActionType:                {400, "BTM710", "Invalid action type"},
+       ErrBadAction:                    {400, "BTM711", "Invalid action object"},
+       ErrBadActionConstruction:        {400, "BTM712", "Invalid action construction"},
+       txbuilder.ErrMissingFields:      {400, "BTM713", "One or more fields are missing"},
+       txbuilder.ErrBadAmount:          {400, "BTM714", "Invalid asset amount"},
+       txbuilder.ErrBadContractArgType: {400, "BTM715", "Invalid contract argument type"},
+       txbuilder.ErrOrphanTx:           {400, "BTM716", "Transaction input UTXO not found"},
+       txbuilder.ErrExtTxFee:           {400, "BTM717", "Transaction fee exceeded max limit"},
+       txbuilder.ErrNoGasInput:         {400, "BTM718", "Transaction has no gas input"},
+       txbuilder.ErrRejected:           {400, "BTM719", "Transaction rejected"},
+       protocol.ErrDustTx:              {400, "BTM720", "Dust Transaction"},
 
        // Submit transaction error namespace (73x ~ 79x)
        // Validation error (73x ~ 75x)
@@ -94,6 +98,7 @@ var respErrFormatter = map[error]httperror.Info{
        validation.ErrUnbalanced:                {400, "BTM746", "Unbalanced asset amount between input and output"},
        validation.ErrOverGasCredit:             {400, "BTM747", "Gas credit has been spent"},
        validation.ErrGasCalculate:              {400, "BTM748", "Gas usage calculate got a math error"},
+       validation.ErrVoteOutputAmount:          {400, "BTM749", "Invalid vote amount"},
 
        // VM error (76x ~ 78x)
        vm.ErrAltStackUnderflow:  {400, "BTM760", "Alt stack underflow"},
index 577830f..270bb3b 100644 (file)
@@ -55,12 +55,13 @@ func FinalizeTx(ctx context.Context, c *protocol.Chain, tx *types.Tx) error {
        tx.Tx.SerializedSize = uint64(len(data) / 2)
 
        isOrphan, err := c.ValidateTx(tx)
-       if errors.Root(err) == protocol.ErrBadTx {
-               return errors.Sub(ErrRejected, err)
-       }
        if err != nil {
-               return errors.WithDetail(err, "tx rejected: "+err.Error())
+               if errors.Root(err) == err {
+                       return errors.Sub(ErrRejected, err)
+               }
+               return err
        }
+
        if isOrphan {
                return ErrOrphanTx
        }
index fe8e7b4..bc311b2 100644 (file)
@@ -136,8 +136,8 @@ var MainNetParams = Params{
                DefaultGasCredit:           int64(160000),
                StorageGasRate:             int64(1),
                VMGasRate:                  int64(200),
-               VotePendingBlockNumber:     uint64(10000),
-               CoinbasePendingBlockNumber: uint64(100),
+               VotePendingBlockNumber:     uint64(3456000),
+               CoinbasePendingBlockNumber: uint64(7200),
                CoinbaseArbitrarySizeLimit: 128,
        },
        DPOSConfig:  VaporDPOSConfig(),
@@ -160,7 +160,7 @@ var TestNetParams = Params{
                StorageGasRate:             int64(1),
                VMGasRate:                  int64(200),
                VotePendingBlockNumber:     uint64(10000),
-               CoinbasePendingBlockNumber: uint64(100),
+               CoinbasePendingBlockNumber: uint64(1200),
                CoinbaseArbitrarySizeLimit: 128,
        },
        DPOSConfig:  VaporDPOSConfig(),
@@ -182,7 +182,7 @@ var SoloNetParams = Params{
                StorageGasRate:             int64(1),
                VMGasRate:                  int64(200),
                VotePendingBlockNumber:     uint64(10000),
-               CoinbasePendingBlockNumber: uint64(100),
+               CoinbasePendingBlockNumber: uint64(1200),
                CoinbaseArbitrarySizeLimit: 128,
        },
        DPOSConfig:  VaporDPOSConfig(),
index a4c51e4..35c021f 100644 (file)
@@ -108,6 +108,11 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager
        txs := txPool.GetTransactions()
        sort.Sort(byTime(txs))
 
+       consensusResult, err := c.GetConsensusResultByHash(&preBlockHash)
+       if err != nil {
+               return nil, err
+       }
+
        entriesTxs := []*bc.Tx{}
        for _, txDesc := range txs {
                entriesTxs = append(entriesTxs, txDesc.Tx.Tx)
@@ -142,6 +147,11 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager
                        continue
                }
 
+               if err := consensusResult.ApplyTransaction(txDesc.Tx); err != nil {
+                       blkGenSkipTxForErr(txPool, &tx.ID, err)
+                       continue
+               }
+
                if err := txStatus.SetStatus(len(b.Transactions), gasOnlyTx); err != nil {
                        return nil, err
                }
@@ -161,11 +171,6 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager
                return nil, errors.Wrap(err, "fail on createCoinbaseTx")
        }
 
-       consensusResult, err := c.GetConsensusResultByHash(&preBlockHash)
-       if err != nil {
-               return nil, err
-       }
-
        if err := consensusResult.AttachCoinbaseReward(b); err != nil {
                return nil, err
        }
index e124143..ff4a2a3 100644 (file)
@@ -109,39 +109,55 @@ func (c *ConsensusResult) ApplyBlock(block *types.Block) error {
        }
 
        for _, tx := range block.Transactions {
-               for _, input := range tx.Inputs {
-                       vetoInput, ok := input.TypedInput.(*types.VetoInput)
-                       if !ok {
-                               continue
-                       }
+               if err := c.ApplyTransaction(tx); err != nil {
+                       return err
+               }
+       }
 
-                       pubkey := hex.EncodeToString(vetoInput.Vote)
-                       c.NumOfVote[pubkey], ok = checked.SubUint64(c.NumOfVote[pubkey], vetoInput.Amount)
-                       if !ok {
-                               return checked.ErrOverflow
-                       }
+       c.BlockHash = block.Hash()
+       c.BlockHeight = block.Height
+       c.Seq = CalcVoteSeq(block.Height)
+       return nil
+}
 
-                       if c.NumOfVote[pubkey] == 0 {
-                               delete(c.NumOfVote, pubkey)
-                       }
+// ApplyTransaction calculate the consensus result for transaction
+func (c *ConsensusResult) ApplyTransaction(tx *types.Tx) error {
+       for _, input := range tx.Inputs {
+               vetoInput, ok := input.TypedInput.(*types.VetoInput)
+               if !ok {
+                       continue
                }
 
-               for _, output := range tx.Outputs {
-                       voteOutput, ok := output.TypedOutput.(*types.VoteOutput)
-                       if !ok {
-                               continue
-                       }
+               pubkey := hex.EncodeToString(vetoInput.Vote)
+               c.NumOfVote[pubkey], ok = checked.SubUint64(c.NumOfVote[pubkey], vetoInput.Amount)
+               if !ok {
+                       return checked.ErrOverflow
+               }
 
-                       pubkey := hex.EncodeToString(voteOutput.Vote)
-                       if c.NumOfVote[pubkey], ok = checked.AddUint64(c.NumOfVote[pubkey], voteOutput.Amount); !ok {
-                               return checked.ErrOverflow
-                       }
+               if c.NumOfVote[pubkey] == 0 {
+                       delete(c.NumOfVote, pubkey)
                }
        }
 
-       c.BlockHash = block.Hash()
-       c.BlockHeight = block.Height
-       c.Seq = CalcVoteSeq(block.Height)
+       for _, output := range tx.Outputs {
+               voteOutput, ok := output.TypedOutput.(*types.VoteOutput)
+               if !ok {
+                       continue
+               }
+
+               if voteOutput.Amount < consensus.ActiveNetParams.MinVoteOutputAmount {
+                       return errors.New("invalid vote transaction with vote amount less than MinVoteOutputAmount")
+               }
+
+               pubkey := hex.EncodeToString(voteOutput.Vote)
+               if _, ok := c.NumOfVote[pubkey]; !ok && voteOutput.Amount < consensus.ActiveNetParams.MinConsensusNodeVoteNum {
+                       return errors.New("invalid vote transaction with first vote amount less than MinConsensusNodeVoteNum")
+               }
+
+               if c.NumOfVote[pubkey], ok = checked.AddUint64(c.NumOfVote[pubkey], voteOutput.Amount); !ok {
+                       return checked.ErrOverflow
+               }
+       }
        return nil
 }
 
index a41285c..3cd4f4a 100644 (file)
@@ -166,7 +166,7 @@ func TestApplyBlock(t *testing.T) {
                {
                        block: &bc.Block{
                                BlockHeader: &bc.BlockHeader{
-                                       Height:            101,
+                                       Height:            consensus.MainNetParams.CoinbasePendingBlockNumber + 1,
                                        TransactionStatus: bc.NewTransactionStatus(),
                                },
                                Transactions: []*bc.Tx{
@@ -340,7 +340,7 @@ func TestApplyBlock(t *testing.T) {
                {
                        block: &bc.Block{
                                BlockHeader: &bc.BlockHeader{
-                                       Height:            10001,
+                                       Height:            consensus.MainNetParams.VotePendingBlockNumber + 1,
                                        TransactionStatus: bc.NewTransactionStatus(),
                                },
                                Transactions: []*bc.Tx{
index 966b292..f24f95a 100644 (file)
@@ -10,9 +10,6 @@ import (
        "github.com/vapor/protocol/validation"
 )
 
-// ErrBadTx is returned for transactions failing validation
-var ErrBadTx = errors.New("invalid transaction")
-
 // GetTransactionStatus return the transaction status of give block
 func (c *Chain) GetTransactionStatus(hash *bc.Hash) (*bc.TransactionStatus, error) {
        return c.store.GetTransactionStatus(hash)
@@ -48,6 +45,16 @@ func (c *Chain) validateTx(tx *types.Tx) (bool, error) {
        }
 
        bh := c.BestBlockHeader()
+       blockHash := bh.Hash()
+       consensusResult, err := c.GetConsensusResultByHash(&blockHash)
+       if err != nil {
+               return false, err
+       }
+
+       if err := consensusResult.ApplyTransaction(tx); err != nil {
+               return false, errors.Wrap(validation.ErrVoteOutputAmount, err)
+       }
+
        gasStatus, err := validation.ValidateTx(tx.Tx, types.MapBlock(&types.Block{BlockHeader: *bh}))
        if !gasStatus.GasValid {
                c.txPool.AddErrCache(&tx.ID, err)
index d52c105..9364455 100644 (file)
@@ -238,9 +238,6 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                if err = checkValidSrc(&vs2, e.Source); err != nil {
                        return errors.Wrap(err, "checking vote output source")
                }
-               if e.Source.Value.Amount < consensus.ActiveNetParams.MinVoteOutputAmount {
-                       return ErrVoteOutputAmount
-               }
 
        case *bc.Retirement:
                vs2 := *vs
index 2df108c..9588a04 100644 (file)
@@ -554,7 +554,7 @@ func TestTxOutToUtxos(t *testing.T) {
                                        ControlProgram: []byte{0x51},
                                        SourceID:       bc.NewHash([32]byte{0xb4, 0x7e, 0x94, 0x31, 0x88, 0xfe, 0xd3, 0xe9, 0xac, 0x99, 0x7c, 0xfc, 0x99, 0x6d, 0xd7, 0x4d, 0x04, 0x10, 0x77, 0xcb, 0x1c, 0xf8, 0x95, 0x14, 0x00, 0xe3, 0x42, 0x00, 0x8d, 0x05, 0xec, 0xdc}),
                                        SourcePos:      0,
-                                       ValidHeight:    198,
+                                       ValidHeight:    consensus.MainNetParams.CoinbasePendingBlockNumber + 98,
                                },
                        },
                },
@@ -745,7 +745,7 @@ func TestTxOutToUtxos(t *testing.T) {
                                        ControlProgram: []byte{0x52},
                                        SourceID:       bc.Hash{V0: 14680680172533616824, V1: 32429899179491316, V2: 15399988966960786775, V3: 17411722803888206567},
                                        SourcePos:      1,
-                                       ValidHeight:    100,
+                                       ValidHeight:    consensus.MainNetParams.CoinbasePendingBlockNumber,
                                },
                        },
                },