@ -728,15 +728,17 @@ func (pool *TxPool) validateTx(tx types.PoolTransaction, local bool) error {
if err != nil {
if err != nil {
return err
return err
}
}
if pool . currentState . GetBalance ( from ) . Cmp ( cost ) < 0 {
stakingTx , isStakingTx := tx . ( * staking . StakingTransaction )
return errors . Wrapf (
if ! isStakingTx || ( isStakingTx && stakingTx . StakingType ( ) != staking . DirectiveDelegate ) {
ErrInsufficientFunds ,
if pool . currentState . GetBalance ( from ) . Cmp ( cost ) < 0 {
"current shard-id: %d" ,
return errors . Wrapf (
pool . chain . CurrentBlock ( ) . ShardID ( ) ,
ErrInsufficientFunds ,
)
"current shard-id: %d" ,
pool . chain . CurrentBlock ( ) . ShardID ( ) ,
)
}
}
}
intrGas := uint64 ( 0 )
intrGas := uint64 ( 0 )
stakingTx , isStakingTx := tx . ( * staking . StakingTransaction )
if isStakingTx {
if isStakingTx {
intrGas , err = IntrinsicGas ( tx . Data ( ) , false , pool . homestead , stakingTx . StakingType ( ) == staking . DirectiveCreateValidator )
intrGas , err = IntrinsicGas ( tx . Data ( ) , false , pool . homestead , stakingTx . StakingType ( ) == staking . DirectiveCreateValidator )
} else {
} else {
@ -832,10 +834,7 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
if err != nil {
if err != nil {
return err
return err
}
}
pendingEpoch := pool . chain . CurrentBlock ( ) . Epoch ( )
pendingEpoch := pool . pendingEpoch ( )
if shard . Schedule . IsLastBlock ( pool . chain . CurrentBlock ( ) . Number ( ) . Uint64 ( ) ) {
pendingEpoch = new ( big . Int ) . Add ( pendingEpoch , big . NewInt ( 1 ) )
}
_ , _ , _ , err = VerifyAndDelegateFromMsg (
_ , _ , _ , err = VerifyAndDelegateFromMsg (
pool . currentState , pendingEpoch , stkMsg , delegations , pool . chainconfig . IsRedelegation ( pendingEpoch ) )
pool . currentState , pendingEpoch , stkMsg , delegations , pool . chainconfig . IsRedelegation ( pendingEpoch ) )
return err
return err
@ -851,12 +850,8 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
if from != stkMsg . DelegatorAddress {
if from != stkMsg . DelegatorAddress {
return errors . WithMessagef ( ErrInvalidSender , "staking transaction sender is %s" , b32 )
return errors . WithMessagef ( ErrInvalidSender , "staking transaction sender is %s" , b32 )
}
}
pendingEpoch := pool . chain . CurrentBlock ( ) . Epoch ( )
if shard . Schedule . IsLastBlock ( pool . chain . CurrentBlock ( ) . Number ( ) . Uint64 ( ) ) {
pendingEpoch = new ( big . Int ) . Add ( pendingEpoch , big . NewInt ( 1 ) )
}
_ , err = VerifyAndUndelegateFromMsg ( pool . currentState , pendingEpoch , stkMsg )
_ , err = VerifyAndUndelegateFromMsg ( pool . currentState , pool . pendingEpoch ( ) , stkMsg )
return err
return err
case staking . DirectiveCollectRewards :
case staking . DirectiveCollectRewards :
msg , err := staking . RLPDecodeStakeMsg ( tx . Data ( ) , staking . DirectiveCollectRewards )
msg , err := staking . RLPDecodeStakeMsg ( tx . Data ( ) , staking . DirectiveCollectRewards )
@ -887,6 +882,15 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
}
}
}
}
func ( pool * TxPool ) pendingEpoch ( ) * big . Int {
currentBlock := pool . chain . CurrentBlock ( )
pendingEpoch := currentBlock . Epoch ( )
if shard . Schedule . IsLastBlock ( currentBlock . Number ( ) . Uint64 ( ) ) {
pendingEpoch . Add ( pendingEpoch , big . NewInt ( 1 ) )
}
return pendingEpoch
}
// add validates a transaction and inserts it into the non-executable queue for
// add validates a transaction and inserts it into the non-executable queue for
// later pending promotion and execution. If the transaction is a replacement for
// later pending promotion and execution. If the transaction is a replacement for
// an already pending or queued one, it overwrites the previous and returns this
// an already pending or queued one, it overwrites the previous and returns this
@ -1297,7 +1301,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
// Do not report to error sink as old txs are on chain or meaningful error caught elsewhere.
// Do not report to error sink as old txs are on chain or meaningful error caught elsewhere.
}
}
// Drop all transactions that are too costly (low balance or out of gas)
// Drop all transactions that are too costly (low balance or out of gas)
drops , _ := list . FilterCost ( pool . currentState . GetBalance ( addr ) , pool . currentMaxGas )
drops , _ := list . FilterValid ( pool , addr )
for _ , tx := range drops {
for _ , tx := range drops {
hash := tx . Hash ( )
hash := tx . Hash ( )
pool . all . Remove ( hash )
pool . all . Remove ( hash )
@ -1470,18 +1474,7 @@ func (pool *TxPool) demoteUnexecutables() {
// Do not report to error sink as old txs are on chain or meaningful error caught elsewhere.
// Do not report to error sink as old txs are on chain or meaningful error caught elsewhere.
}
}
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops , invalids := list . FilterCost ( pool . currentState . GetBalance ( addr ) , pool . currentMaxGas )
drops , invalids := list . FilterValid ( pool , addr )
// Drop all staking transactions that are now invalid, queue any invalids back for later
stakingDrops , stakingInvalids := list . Filter ( func ( tx types . PoolTransaction ) bool {
if _ , ok := tx . ( * staking . StakingTransaction ) ; ! ok {
// Do not remove anything other than staking transactions
return false
}
err := pool . validateTx ( tx , false )
return err != nil
} )
drops = append ( drops , stakingDrops ... )
invalids = append ( invalids , stakingInvalids ... )
for _ , tx := range drops {
for _ , tx := range drops {
hash := tx . Hash ( )
hash := tx . Hash ( )
pool . all . Remove ( hash )
pool . all . Remove ( hash )