Skip to content
This repository has been archived by the owner on Oct 7, 2020. It is now read-only.

Commit

Permalink
Mirror validateTx logic from tx_pool.go. Move checkTxState updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrian Brink committed Aug 23, 2017
1 parent 70af8a1 commit 6e00ad4
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 24 deletions.
54 changes: 30 additions & 24 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
ethTypes "github.com/ethereum/go-ethereum/core/types"
Expand All @@ -28,7 +27,7 @@ type EthermintApplication struct {
// a closure to return the latest current state from the ethereum blockchain
getCurrentState func() (*state.StateDB, error)

cacheState *state.StateDB
checkTxState *state.StateDB

// an ethereum rpc client we can forward queries to
rpcClient *rpc.Client
Expand All @@ -53,7 +52,7 @@ func NewEthermintApplication(backend *ethereum.Backend,
backend: backend,
rpcClient: client,
getCurrentState: backend.Ethereum().BlockChain().State,
cacheState: state.Copy(),
checkTxState: state.Copy(),
strategy: strategy,
}

Expand Down Expand Up @@ -177,7 +176,8 @@ func (app *EthermintApplication) Commit() abciTypes.Result {
if err != nil {
app.logger.Error("Error getting latest state", "err", err) // nolint: errcheck
}
app.cacheState = state.Copy()

app.checkTxState = state.Copy()
return abciTypes.NewResultOK(blockHash[:], "")
}

Expand Down Expand Up @@ -205,22 +205,32 @@ func (app *EthermintApplication) Query(query abciTypes.RequestQuery) abciTypes.R
// validateTx checks the validity of a tx against the blockchain's current state.
// it duplicates the logic in ethereum's tx_pool
func (app *EthermintApplication) validateTx(tx *ethTypes.Transaction) abciTypes.Result {
currentState := app.cacheState
currentState := app.checkTxState

var signer ethTypes.Signer = ethTypes.FrontierSigner{}
if tx.Protected() {
signer = ethTypes.NewEIP155Signer(tx.ChainId())
}

// Make sure the transaction is signed properl
from, err := ethTypes.Sender(signer, tx)
if err != nil {
return abciTypes.ErrBaseInvalidSignature.
AppendLog(core.ErrInvalidSender.Error())
}

// Update ether balances
currentState.SubBalance(from, tx.Value())
currentState.AddBalance(*tx.To(), tx.Value())
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
if tx.Size() > 32*1024 {
return abciTypes.ErrInternalError.
AppendLog(core.ErrOversizedData.Error())
}

// Transactions can't be negative. This may never happen using RLP decoded
// transactions but may occur if you create a transaction using the RPC.
if tx.Value().Sign() < 0 {
return abciTypes.ErrBaseInvalidInput.
AppendLog(core.ErrNegativeValue.Error())
}

// Make sure the account exist. Non existent accounts
// haven't got funds and well therefor never pass.
Expand All @@ -229,34 +239,25 @@ func (app *EthermintApplication) validateTx(tx *ethTypes.Transaction) abciTypes.
AppendLog(core.ErrInvalidSender.Error())
}

// Check for nonce errors
currentNonce := currentState.GetNonce(from)
if currentNonce > tx.Nonce() {
return abciTypes.ErrBadNonce.
AppendLog(fmt.Sprintf("Got: %d, Current: %d", tx.Nonce(), currentNonce))
}

// Check the transaction doesn't exceed the current block limit gas.
gasLimit := app.backend.GasLimit()
if gasLimit.Cmp(tx.Gas()) < 0 {
return abciTypes.ErrInternalError.AppendLog(core.ErrGasLimitReached.Error())
return abciTypes.ErrInternalError.
AppendLog(core.ErrGasLimitReached.Error())
}

// Transactions can't be negative. This may never happen
// using RLP decoded transactions but may occur if you create
// a transaction using the RPC for example.
if tx.Value().Cmp(common.Big0) < 0 {
return abciTypes.ErrBaseInvalidInput.
SetLog(core.ErrNegativeValue.Error())
// Check for nonce errors
if currentState.GetNonce(from) > tx.Nonce() {
return abciTypes.ErrBadNonce.
AppendLog(core.ErrNonceTooLow.Error())
}

// Transactor should have enough funds to cover the costs
// cost == V + GP * GL
currentBalance := currentState.GetBalance(from)
if currentBalance.Cmp(tx.Cost()) < 0 {
return abciTypes.ErrInsufficientFunds.
AppendLog(fmt.Sprintf("Current balance: %s, tx cost: %s", currentBalance, tx.Cost()))

AppendLog(core.ErrInsufficientFunds.Error())
}

intrGas := core.IntrinsicGas(tx.Data(), tx.To() == nil, true) // homestead == true
Expand All @@ -265,5 +266,10 @@ func (app *EthermintApplication) validateTx(tx *ethTypes.Transaction) abciTypes.
SetLog(core.ErrIntrinsicGas.Error())
}

// Update ether balances
// amount + gasprice * gaslimit
currentState.SubBalance(from, tx.Cost())
currentState.AddBalance(*tx.To(), tx.Value())

return abciTypes.OK
}
1 change: 1 addition & 0 deletions app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func TestBumpingNonces(t *testing.T) {
stack.Stop() // nolint: errcheck
}

// TestMultipleTxOneAcc sends multiple TXs from the same account in the same block
func TestMultipleTxOneAcc(t *testing.T) {
// generate key
privateKey, err := crypto.GenerateKey()
Expand Down

0 comments on commit 6e00ad4

Please sign in to comment.