Skip to content

Commit

Permalink
Merge pull request #17 from vulcanize/transaction_execution
Browse files Browse the repository at this point in the history
Transaction execution
  • Loading branch information
i-norden authored Dec 11, 2019
2 parents a50d3c6 + 1937670 commit 0c8dcc0
Show file tree
Hide file tree
Showing 17 changed files with 392 additions and 87 deletions.
38 changes: 36 additions & 2 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,23 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
// state is modified during execution, make sure to copy it if necessary.
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) {
// Ensure message is initialized properly.
if call.GasPrice == nil {
// EIP1559 guards
if b.config.IsEIP1559Finalized(block.Number()) && (call.GasPremium == nil || call.FeeCap == nil || call.GasPrice != nil) {
return nil, 0, false, core.ErrTxNotEIP1559
}
if !b.config.IsEIP1559(block.Number()) && (call.GasPremium != nil || call.FeeCap != nil || call.GasPrice == nil) {
return nil, 0, false, core.ErrTxIsEIP1559
}
if call.GasPrice != nil && (call.GasPremium != nil || call.FeeCap != nil) {
return nil, 0, false, core.ErrTxSetsLegacyAndEIP1559Fields
}
if call.FeeCap != nil && call.GasPremium == nil {
return nil, 0, false, errors.New("if FeeCap is set, GasPremium must be set")
}
if call.GasPremium != nil && call.FeeCap == nil {
return nil, 0, false, errors.New("if GasPremium is set, FeeCap must be set")
}
if call.GasPrice == nil && call.GasPremium == nil {
call.GasPrice = big.NewInt(1)
}
if call.Gas == 0 {
Expand All @@ -319,8 +335,12 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
gaspool := new(core.GasPool).AddGas(math.MaxUint64)
var gp1559 *core.GasPool
if b.config.IsEIP1559(block.Number()) {
gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559)
}

return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
return core.NewStateTransition(vmenv, msg, gaspool, gp1559).TransitionDb()
}

// SendTransaction updates the pending block to include the given transaction.
Expand All @@ -329,6 +349,20 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
b.mu.Lock()
defer b.mu.Unlock()

// EIP1559 guards
if b.config.IsEIP1559Finalized(b.blockchain.CurrentBlock().Number()) && (tx.GasPremium() == nil || tx.FeeCap() == nil || tx.GasPrice() != nil) {
return core.ErrTxNotEIP1559
}
if !b.config.IsEIP1559(b.blockchain.CurrentBlock().Number()) && (tx.GasPremium() != nil || tx.FeeCap() != nil || tx.GasPrice() == nil) {
return core.ErrTxIsEIP1559
}
if tx.GasPrice() != nil && (tx.GasPremium() != nil || tx.FeeCap() != nil) {
return core.ErrTxSetsLegacyAndEIP1559Fields
}
if tx.GasPrice() == nil && (tx.GasPremium() == nil || tx.FeeCap() == nil) {
return core.ErrMissingGasFields
}

sender, err := types.Sender(types.NewEIP155Signer(b.config.ChainID), tx)
if err != nil {
panic(fmt.Errorf("invalid transaction: %v", err))
Expand Down
17 changes: 15 additions & 2 deletions cmd/geth/retesteth.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,10 @@ func (api *RetestethAPI) mineBlock() error {
misc.ApplyDAOHardFork(statedb)
}
gasPool := new(core.GasPool).AddGas(header.GasLimit)
var gp1559 *core.GasPool
if api.chainConfig.IsEIP1559(header.Number) {
gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559)
}
txCount := 0
var txs []*types.Transaction
var receipts []*types.Receipt
Expand All @@ -513,6 +517,7 @@ func (api *RetestethAPI) mineBlock() error {
api.blockchain,
&api.author,
gasPool,
gp1559,
statedb,
header, tx, &header.GasUsed, *api.blockchain.GetVMConfig(),
)
Expand Down Expand Up @@ -657,7 +662,11 @@ func (api *RetestethAPI) AccountRange(ctx context.Context,
context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil)
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{})
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
var gp1559 *core.GasPool
if vmenv.ChainConfig().IsEIP1559(block.Number()) {
gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559)
}
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), gp1559); err != nil {
return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
// Ensure any modifications are committed to the state
Expand Down Expand Up @@ -770,7 +779,11 @@ func (api *RetestethAPI) StorageRangeAt(ctx context.Context,
context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil)
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{})
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
var gp1559 *core.GasPool
if vmenv.ChainConfig().IsEIP1559(block.Number()) {
gp1559 = new(core.GasPool).AddGas(params.MaxGasEIP1559)
}
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), gp1559); err != nil {
return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
// Ensure any modifications are committed to the state
Expand Down
14 changes: 9 additions & 5 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ type BlockGen struct {
header *types.Header
statedb *state.StateDB

gasPool *GasPool
txs []*types.Transaction
receipts []*types.Receipt
uncles []*types.Header
gasPool *GasPool
gasPool1559 *GasPool
txs []*types.Transaction
receipts []*types.Receipt
uncles []*types.Header

config *params.ChainConfig
engine consensus.Engine
Expand Down Expand Up @@ -102,8 +103,11 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
if b.gasPool == nil {
b.SetCoinbase(common.Address{})
}
if b.gasPool1559 == nil && b.config.IsEIP1559(b.header.Number) {
b.gasPool1559 = new(GasPool).AddGas(params.MaxGasEIP1559)
}
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.gasPool1559, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
if err != nil {
panic(err)
}
Expand Down
1 change: 1 addition & 0 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
Difficulty: new(big.Int).Set(header.Difficulty),
GasLimit: header.GasLimit,
GasPrice: new(big.Int).Set(msg.GasPrice()),
BaseFee: header.BaseFee,
}
}

Expand Down
10 changes: 7 additions & 3 deletions core/state_prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
var (
header = block.Header()
gaspool = new(GasPool).AddGas(block.GasLimit())
gp1559 *GasPool
)
if p.config.IsEIP1559(block.Number()) {
gp1559 = new(GasPool).AddGas(params.MaxGasEIP1559)
}
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
// If block precaching was interrupted, abort
Expand All @@ -61,7 +65,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
}
// Block precaching permitted to continue, execute the transaction
statedb.Prepare(tx.Hash(), block.Hash(), i)
if err := precacheTransaction(p.config, p.bc, nil, gaspool, statedb, header, tx, cfg); err != nil {
if err := precacheTransaction(p.config, p.bc, nil, gaspool, gp1559, statedb, header, tx, cfg); err != nil {
return // Ugh, something went horribly wrong, bail out
}
}
Expand All @@ -70,7 +74,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
// precacheTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. The goal is not to execute
// the transaction successfully, rather to warm up touched data slots.
func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gaspool *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cfg vm.Config) error {
func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gaspool, gp1559 *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cfg vm.Config) error {
// Convert the transaction into an executable message and pre-cache its sender
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
if err != nil {
Expand All @@ -80,6 +84,6 @@ func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *co
context := NewEVMContext(msg, header, bc, author)
vm := vm.NewEVM(context, statedb, config, cfg)

_, _, _, err = ApplyMessage(vm, msg, gaspool)
_, _, _, err = ApplyMessage(vm, msg, gaspool, gp1559)
return err
}
10 changes: 7 additions & 3 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,19 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
header = block.Header()
allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit())
gp1559 *GasPool
)
if p.config.IsEIP1559(block.Number()) {
gp1559 = new(GasPool).AddGas(params.MaxGasEIP1559)
}
// Mutate the block and state according to any hard-fork specs
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb)
}
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
receipt, err := ApplyTransaction(p.config, p.bc, nil, gp, gp1559, statedb, header, tx, usedGas, cfg)
if err != nil {
return nil, nil, 0, err
}
Expand All @@ -85,7 +89,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp, gp1559 *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
if err != nil {
return nil, err
Expand All @@ -96,7 +100,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, statedb, config, cfg)
// Apply the transaction to the current state (included in the env)
_, gas, failed, err := ApplyMessage(vmenv, msg, gp)
_, gas, failed, err := ApplyMessage(vmenv, msg, gp, gp1559)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 0c8dcc0

Please sign in to comment.