"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"
)
// 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)
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"},
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
}
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(),
StorageGasRate: int64(1),
VMGasRate: int64(200),
VotePendingBlockNumber: uint64(10000),
- CoinbasePendingBlockNumber: uint64(100),
+ CoinbasePendingBlockNumber: uint64(1200),
CoinbaseArbitrarySizeLimit: 128,
},
DPOSConfig: VaporDPOSConfig(),
StorageGasRate: int64(1),
VMGasRate: int64(200),
VotePendingBlockNumber: uint64(10000),
- CoinbasePendingBlockNumber: uint64(100),
+ CoinbasePendingBlockNumber: uint64(1200),
CoinbaseArbitrarySizeLimit: 128,
},
DPOSConfig: VaporDPOSConfig(),
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)
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
}
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
}
}
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
}
{
block: &bc.Block{
BlockHeader: &bc.BlockHeader{
- Height: 101,
+ Height: consensus.MainNetParams.CoinbasePendingBlockNumber + 1,
TransactionStatus: bc.NewTransactionStatus(),
},
Transactions: []*bc.Tx{
{
block: &bc.Block{
BlockHeader: &bc.BlockHeader{
- Height: 10001,
+ Height: consensus.MainNetParams.VotePendingBlockNumber + 1,
TransactionStatus: bc.NewTransactionStatus(),
},
Transactions: []*bc.Tx{
"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)
}
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)
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
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,
},
},
},
ControlProgram: []byte{0x52},
SourceID: bc.Hash{V0: 14680680172533616824, V1: 32429899179491316, V2: 15399988966960786775, V3: 17411722803888206567},
SourcePos: 1,
- ValidHeight: 100,
+ ValidHeight: consensus.MainNetParams.CoinbasePendingBlockNumber,
},
},
},