diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/bench_test.go | 11 | ||||
-rw-r--r-- | core/block_validator_test.go | 19 | ||||
-rw-r--r-- | core/blockchain.go | 15 | ||||
-rw-r--r-- | core/blockchain_test.go | 89 | ||||
-rw-r--r-- | core/chain_makers.go | 5 | ||||
-rw-r--r-- | core/chain_makers_test.go | 7 | ||||
-rw-r--r-- | core/dao_test.go | 27 | ||||
-rw-r--r-- | core/dexon_chain_makers.go | 5 | ||||
-rw-r--r-- | core/evm.go | 7 | ||||
-rw-r--r-- | core/genesis_test.go | 7 | ||||
-rw-r--r-- | core/state_processor.go | 14 | ||||
-rw-r--r-- | core/state_transition.go | 37 | ||||
-rw-r--r-- | core/types.go | 4 | ||||
-rw-r--r-- | core/vm/evm/evm.go | 114 | ||||
-rw-r--r-- | core/vm/evm/evm_test.go | 13 | ||||
-rw-r--r-- | core/vm/evm/gas_table.go | 16 | ||||
-rw-r--r-- | core/vm/evm/instructions.go | 196 | ||||
-rw-r--r-- | core/vm/evm/instructions_test.go | 102 | ||||
-rw-r--r-- | core/vm/evm/interpreter.go | 51 | ||||
-rw-r--r-- | core/vm/evm/logger_test.go | 7 | ||||
-rw-r--r-- | core/vm/evm/oracle_contracts_test.go | 9 | ||||
-rw-r--r-- | core/vm/evm/runtime/env.go | 10 | ||||
-rw-r--r-- | core/vm/evm/runtime/runtime.go | 20 | ||||
-rw-r--r-- | core/vm/evm/runtime/runtime_test.go | 50 | ||||
-rw-r--r-- | core/vm/intpool.go | 19 | ||||
-rw-r--r-- | core/vm/sqlvm/sqlvm.go | 41 | ||||
-rw-r--r-- | core/vm/stateDB.go | 19 | ||||
-rw-r--r-- | core/vm/vm.go | 112 |
28 files changed, 593 insertions, 433 deletions
diff --git a/core/bench_test.go b/core/bench_test.go index 98d46176a..30200ae17 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -28,7 +28,8 @@ import ( "github.com/dexon-foundation/dexon/consensus/ethash" "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -175,7 +176,9 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -287,7 +290,9 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vmConfig, nil) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 5ae85c796..667959cd5 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -23,7 +23,8 @@ import ( "github.com/dexon-foundation/dexon/consensus/ethash" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) @@ -42,7 +43,9 @@ func TestHeaderVerification(t *testing.T) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vmConfig, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { @@ -106,11 +109,15 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { var results <-chan error if valid { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vmConfig, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } else { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vmConfig, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } @@ -173,7 +180,9 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { defer runtime.GOMAXPROCS(old) // Start the verifications and immediately abort - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vmConfig, nil) defer chain.Stop() abort, results := chain.engine.VerifyHeaders(chain, headers, seals) diff --git a/core/blockchain.go b/core/blockchain.go index 8037834c1..489959691 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -41,7 +41,8 @@ import ( "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/event" @@ -139,7 +140,7 @@ type BlockChain struct { engine consensus.Engine processor Processor // block processor interface validator Validator // block and state validator interface - vmConfig vm.Config + vmConfig [vm.NUMS]interface{} badBlocks *lru.Cache // Bad block cache shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. @@ -154,7 +155,7 @@ type BlockChain struct { // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator and // Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) { +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig [vm.NUMS]interface{}, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = &CacheConfig{ TrieCleanLimit: 256, @@ -272,8 +273,8 @@ func (bc *BlockChain) getProcInterrupt() bool { } // GetVMConfig returns the block chain VM config. -func (bc *BlockChain) GetVMConfig() *vm.Config { - return &bc.vmConfig +func (bc *BlockChain) GetVMConfig() [vm.NUMS]interface{} { + return bc.vmConfig } // loadLastState loads the last known chain state from the database. This method @@ -1931,7 +1932,7 @@ func (bc *BlockChain) GetGovStateByHash(hash common.Hash) (*types.GovState, erro if err != nil { return nil, err } - return state.GetGovState(statedb, header, vm.GovernanceContractAddress) + return state.GetGovState(statedb, header, evm.GovernanceContractAddress) } func (bc *BlockChain) GetGovStateByNumber(number uint64) (*types.GovState, error) { @@ -1953,7 +1954,7 @@ func (bc *BlockChain) GetGovStateByNumber(number uint64) (*types.GovState, error if err != nil { return nil, err } - return state.GetGovState(statedb, header, vm.GovernanceContractAddress) + return state.GetGovState(statedb, header, evm.GovernanceContractAddress) } // reorg takes two blocks, an old chain and a new chain and will reconstruct the diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 349bf698f..dedfacda8 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -34,7 +34,8 @@ import ( "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/core/vm/tools" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" @@ -63,7 +64,9 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B genesis := g.MustCommit(db) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vmConfig, nil) // Create and inject the requested chain if n == 0 { return db, blockchain, nil @@ -163,7 +166,9 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } - receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, vm.Config{}) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, vmConfig) if err != nil { blockchain.reportBlock(block, receipts, err) return err @@ -534,7 +539,10 @@ func testReorgBadHashes(t *testing.T, full bool) { blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil) + + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vmConfig, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -646,7 +654,9 @@ func TestFastVsFullChains(t *testing.T) { // Import the chain as an archive node for the comparison baseline archiveDb := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -655,7 +665,9 @@ func TestFastVsFullChains(t *testing.T) { // Fast import the chain as a non-archive node to test fastDb := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig = [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -733,7 +745,9 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveDb := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -746,7 +760,9 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig = [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -767,7 +783,9 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { lightDb := ethdb.NewMemDatabase() gspec.MustCommit(lightDb) - light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig = [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -836,7 +854,9 @@ func TestChainTxReorgs(t *testing.T) { } }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -906,7 +926,10 @@ func TestLogReorgs(t *testing.T) { signer = types.NewEIP155Signer(gspec.Config.ChainID) ) code = tools.PatchBinary(code) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -983,7 +1006,9 @@ func TestLogRebirth(t *testing.T) { } } - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer blockchain.Stop() logsCh := make(chan []*types.Log) @@ -1105,7 +1130,9 @@ func TestSideLogRebirth(t *testing.T) { } } - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer blockchain.Stop() logsCh := make(chan []*types.Log) @@ -1160,7 +1187,9 @@ func TestReorgSideEvent(t *testing.T) { signer = types.NewEIP155Signer(gspec.Config.ChainID) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer blockchain.Stop() chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) @@ -1290,7 +1319,9 @@ func TestEIP155Transition(t *testing.T) { genesis := gspec.MustCommit(db) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { @@ -1399,7 +1430,9 @@ func TestEIP161AccountRemoval(t *testing.T) { gspec.Config.Dexcon = params.TestChainConfig.Dexcon genesis := gspec.MustCommit(db) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) { @@ -1477,7 +1510,9 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { diskdb := ethdb.NewMemDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vmConfig, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1524,7 +1559,9 @@ func TestTrieForkGC(t *testing.T) { diskdb := ethdb.NewMemDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vmConfig, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1566,7 +1603,9 @@ func TestLargeReorgTrieGC(t *testing.T) { diskdb := ethdb.NewMemDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vmConfig, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1645,7 +1684,9 @@ func TestProcessBlock(t *testing.T) { engine := &dexconTest{ blockReward: big.NewInt(1e18), } - chain, err := NewBlockChain(db, nil, chainConfig, engine, vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, err := NewBlockChain(db, nil, chainConfig, engine, vmConfig, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1847,7 +1888,9 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in diskdb := ethdb.NewMemDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vmConfig, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -1936,7 +1979,9 @@ func TestLowDiffLongChain(t *testing.T) { diskdb := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vmConfig, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 50a537964..e1683a04f 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -27,6 +27,7 @@ import ( "github.com/dexon-foundation/dexon/consensus/misc" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -103,7 +104,9 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { b.SetCoinbase(common.Address{}) } 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, evm.Config{}) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig) if err != nil { panic(err) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 78c242df1..2b3643f43 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -22,7 +22,8 @@ import ( "github.com/dexon-foundation/dexon/consensus/ethash" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -79,7 +80,9 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vmConfig, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index 7e437c1d9..b07a6bc07 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -21,7 +21,8 @@ import ( "testing" "github.com/dexon-foundation/dexon/consensus/ethash" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) @@ -46,7 +47,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { proConf.DAOForkBlock = forkBlock proConf.DAOForkSupport = true - proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vmConfig, nil) defer proBc.Stop() conDb := ethdb.NewMemDatabase() @@ -56,7 +59,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { conConf.DAOForkBlock = forkBlock conConf.DAOForkSupport = false - conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) + vmConfig = [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vmConfig, nil) defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { @@ -70,7 +75,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a pro-fork block, and try to feed into the no-fork chain db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vmConfig, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -95,7 +102,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a no-fork block, and try to feed into the pro-fork chain db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) + vmConfig = [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vmConfig, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) @@ -121,7 +130,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that contra-forkers accept pro-fork extra-datas after forking finishes db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil) + vmConfig = [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vmConfig, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -141,7 +152,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that pro-forkers accept contra-fork extra-datas after forking finishes db = ethdb.NewMemDatabase() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil) + vmConfig = [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vmConfig, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) diff --git a/core/dexon_chain_makers.go b/core/dexon_chain_makers.go index 6901a8bc2..e12c5921b 100644 --- a/core/dexon_chain_makers.go +++ b/core/dexon_chain_makers.go @@ -28,6 +28,7 @@ import ( "github.com/dexon-foundation/dexon/consensus" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -110,7 +111,9 @@ func (b *DexonBlockGen) ProcessTransactions(c ChainContext) { for _, tx := range b.txs { b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) // TODO: fix the chain context parameter - receipt, _, err := ApplyTransaction(b.config, c, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, evm.Config{}) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + receipt, _, err := ApplyTransaction(b.config, c, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig) if err != nil { panic(err) } diff --git a/core/evm.go b/core/evm.go index a2b61c535..6adf59881 100644 --- a/core/evm.go +++ b/core/evm.go @@ -45,8 +45,8 @@ type ChainContext interface { GetRoundHeight(uint64) (uint64, bool) } -// NewEVMContext creates a new context for use in the EVM. -func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) vm.Context { +// NewVMContext creates a new context for use in the EVM. +func NewVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) *vm.Context { // If we don't have an explicit author (i.e. not mining), extract from the header var beneficiary common.Address if author == nil { @@ -55,7 +55,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author beneficiary = *author } - return vm.Context{ + return &vm.Context{ CanTransfer: CanTransfer, Transfer: Transfer, GetHash: GetHashFn(header, chain), @@ -70,6 +70,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author Round: new(big.Int).SetUint64(header.Round), GasLimit: header.GasLimit, GasPrice: new(big.Int).Set(msg.GasPrice()), + IntPool: vm.NewIntPool(), } } diff --git a/core/genesis_test.go b/core/genesis_test.go index 718f65e9d..f0fd26701 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -25,7 +25,8 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/consensus/ethash" "github.com/dexon-foundation/dexon/core/rawdb" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) @@ -140,7 +141,9 @@ func TestSetupGenesis(t *testing.T) { // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = evm.Config{} + bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vmConfig, nil) defer bc.Stop() blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) diff --git a/core/state_processor.go b/core/state_processor.go index ff2d5fbe4..20046c77a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -22,7 +22,7 @@ import ( "github.com/dexon-foundation/dexon/consensus/misc" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" ) @@ -53,7 +53,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg [vm.NUMS]interface{}) (types.Receipts, []*types.Log, uint64, error) { var ( receipts types.Receipts usedGas = new(uint64) @@ -85,18 +85,18 @@ 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, uint64, error) { +func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, vmConfig [vm.NUMS]interface{}) (*types.Receipt, uint64, error) { msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { return nil, 0, err } // Create a new context to be used in the EVM environment - context := NewEVMContext(msg, header, bc, author) + context := NewVMContext(msg, header, bc, author) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. - vmenv := vm.NewEVM(context, statedb, config, cfg) + pack := vm.NewExecPack(context, statedb, config, vmConfig) // Apply the transaction to the current state (included in the env) - _, gas, failed, err := ApplyMessage(vmenv, msg, gp) + _, gas, failed, err := ApplyMessage(&pack, msg, gp) if err != nil { return nil, 0, err } @@ -116,7 +116,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo receipt.GasUsed = gas // if the transaction created a contract, store the creation address in the receipt. if msg.To() == nil { - receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) + receipt.ContractAddress = crypto.CreateAddress(pack.Context.Origin, tx.Nonce()) } // Set the receipt logs and create a bloom for filtering receipt.Logs = statedb.GetLogs(tx.Hash()) diff --git a/core/state_transition.go b/core/state_transition.go index 32589da90..7b5c782ed 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -71,7 +71,7 @@ type StateTransition struct { value *big.Int data []byte state vm.StateDB - evm *evm.EVM + execPack *vm.ExecPack } // Message represents a message sent to a contract. @@ -123,15 +123,15 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) } // NewStateTransition initialises and returns a new state transition object. -func NewStateTransition(evm *evm.EVM, msg Message, gp *GasPool) *StateTransition { +func NewStateTransition(pack *vm.ExecPack, msg Message, gp *GasPool) *StateTransition { return &StateTransition{ gp: gp, - evm: evm, + execPack: pack, msg: msg, gasPrice: msg.GasPrice(), value: msg.Value(), data: msg.Data(), - state: evm.StateDB, + state: pack.StateDB, } } @@ -142,8 +142,8 @@ func NewStateTransition(evm *evm.EVM, msg Message, gp *GasPool) *StateTransition // the gas used (which includes gas refunds) and an error if it failed. An error always // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. -func ApplyMessage(evm *evm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { - return NewStateTransition(evm, msg, gp).TransitionDb() +func ApplyMessage(pack *vm.ExecPack, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { + return NewStateTransition(pack, msg, gp).TransitionDb() } // to returns the recipient of the message. @@ -201,14 +201,14 @@ func (st *StateTransition) inExtendedRound() bool { if h := lastInExtendedRoundResultCache.Load(); h != nil { res := h.(*lastInExtendedRoundResultType) - if res.Height == st.evm.BlockNumber.Uint64() { + if res.Height == st.execPack.Context.BlockNumber.Uint64() { return res.Result } } gs := evm.GovernanceState{st.state} - round := st.evm.Round.Uint64() + round := st.execPack.Context.Round.Uint64() if round < dexCore.ConfigRoundShift { round = 0 } else { @@ -216,23 +216,23 @@ func (st *StateTransition) inExtendedRound() bool { } configHeight := gs.RoundHeight(new(big.Int).SetUint64(round)) - state, err := st.evm.StateAtNumber(configHeight.Uint64()) + state, err := st.execPack.Context.StateAtNumber(configHeight.Uint64()) if err != nil { panic(err) } rgs := evm.GovernanceState{state} - roundEnd := gs.RoundHeight(st.evm.Round).Uint64() + rgs.RoundLength().Uint64() + roundEnd := gs.RoundHeight(st.execPack.Context.Round).Uint64() + rgs.RoundLength().Uint64() // Round 0 starts and height 0 instead of height 1. if round == 0 { - roundEnd += 1 + roundEnd++ } - res := st.evm.BlockNumber.Uint64() >= roundEnd + res := st.execPack.Context.BlockNumber.Uint64() >= roundEnd lastInExtendedRoundResultCache.Store(&lastInExtendedRoundResultType{ - Height: st.evm.BlockNumber.Uint64(), + Height: st.execPack.Context.BlockNumber.Uint64(), Result: res, }) return res @@ -247,7 +247,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } msg := st.msg sender := vm.AccountRef(msg.From()) - homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) + homestead := st.execPack.ChainConfig.IsHomestead(st.execPack.Context.BlockNumber) contractCreation := msg.To() == nil // Pay intrinsic gas @@ -266,13 +266,14 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo // error. vmerr error ) - i := st.evm.Interpreter().(*evm.EVMInterpreter) if contractCreation { - ret, _, st.gas, vmerr = vm.Create(sender, st.data, st.gas, st.value, i) + ret, _, st.gas, vmerr = vm.Create(sender, st.data, st.gas, + st.value, st.execPack) } else { // Increment the nonce for the next transaction st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) - ret, st.gas, vmerr = vm.Call(sender, st.to(), st.data, st.gas, st.value, i) + ret, st.gas, vmerr = vm.Call(sender, st.to(), st.data, st.gas, + st.value, st.execPack) } if vmerr != nil { log.Debug("VM returned with error", "err", vmerr) @@ -290,7 +291,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo st.dexonRefundGas() } - receiver := st.evm.Coinbase + receiver := st.execPack.Context.Coinbase if !*legacyEvm && st.inExtendedRound() { gs := evm.GovernanceState{st.state} receiver = gs.Owner() diff --git a/core/types.go b/core/types.go index b020a5df7..be0d4401c 100644 --- a/core/types.go +++ b/core/types.go @@ -20,7 +20,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" ) // Validator is an interface which defines the standard for block validation. It @@ -46,5 +46,5 @@ type Validator interface { // of gas used in the process and return an error if any of the internal rules // failed. type Processor interface { - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) + Process(block *types.Block, statedb *state.StateDB, vmConfig [vm.NUMS]interface{}) (types.Receipts, []*types.Log, uint64, error) } diff --git a/core/vm/evm/evm.go b/core/vm/evm/evm.go index e1c8c02ed..679d70b64 100644 --- a/core/vm/evm/evm.go +++ b/core/vm/evm/evm.go @@ -32,54 +32,7 @@ import ( var emptyCodeHash = crypto.Keccak256Hash(nil) func init() { - vm.Register(vm.EVM, &EVMImplement{}) -} - -type EVMImplement struct{} - -func (evmImpl *EVMImplement) Create(caller vm.ContractRef, code []byte, gas uint64, - value *big.Int, interpreter vm.Interpreter) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - i := interpreter.(*EVMInterpreter) - return i.evm.Create(caller, code, gas, value) -} - -func (evmImpl *EVMImplement) Create2(caller vm.ContractRef, code []byte, gas uint64, - endowment *big.Int, salt *big.Int, - interpreter vm.Interpreter) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - - i := interpreter.(*EVMInterpreter) - return i.evm.Create2(caller, code, gas, endowment, salt) -} - -func (evmImpl *EVMImplement) Call(caller vm.ContractRef, addr common.Address, - input []byte, gas uint64, value *big.Int, - interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) { - i := interpreter.(*EVMInterpreter) - return i.evm.Call(caller, addr, input, gas, value) - -} -func (evmImpl *EVMImplement) CallCode(caller vm.ContractRef, addr common.Address, - input []byte, gas uint64, value *big.Int, - interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) { - - i := interpreter.(*EVMInterpreter) - return i.evm.CallCode(caller, addr, input, gas, value) -} - -func (evmImpl *EVMImplement) DelegateCall(caller vm.ContractRef, addr common.Address, - input []byte, gas uint64, - interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) { - - i := interpreter.(*EVMInterpreter) - return i.evm.DelegateCall(caller, addr, input, gas) -} - -func (evmImpl *EVMImplement) StaticCall(caller vm.ContractRef, addr common.Address, - input []byte, gas uint64, - interpreter vm.Interpreter) (ret []byte, leftovergas uint64, err error) { - - i := interpreter.(*EVMInterpreter) - return i.evm.StaticCall(caller, addr, input, gas) + vm.Register(vm.EVM, NewEVM) } // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. @@ -123,11 +76,9 @@ func run(evm *EVM, contract *vm.Contract, input []byte, readOnly bool) ([]byte, // The EVM should never be reused and is not thread safe. type EVM struct { // Context provides auxiliary blockchain related information - vm.Context + *vm.Context // StateDB gives access to the underlying state StateDB vm.StateDB - // Depth is the current call stack - depth int // chainConfig contains information about the current chain chainConfig *params.ChainConfig @@ -143,19 +94,16 @@ type EVM struct { // abort is used to abort the EVM calling operations // NOTE: must be set atomically abort int32 - // callGasTemp holds the gas available for the current call. This is needed because the - // available gas is calculated in gasCall* according to the 63/64 rule and later - // applied in opCall*. - callGasTemp uint64 } // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM(ctx vm.Context, statedb vm.StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { +func NewEVM(ctx *vm.Context, statedb vm.StateDB, chainConfig *params.ChainConfig, vmConfig interface{}) vm.VM { + cfg := vmConfig.(Config) evm := &EVM{ Context: ctx, StateDB: statedb, - vmConfig: vmConfig, + vmConfig: cfg, chainConfig: chainConfig, chainRules: chainConfig.Rules(ctx.BlockNumber), interpreters: make([]Interpreter, 0, 1), @@ -179,7 +127,7 @@ func NewEVM(ctx vm.Context, statedb vm.StateDB, chainConfig *params.ChainConfig, // vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here // as we always want to have the built-in EVM as the failover option. - evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig)) + evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, cfg)) evm.interpreter = evm.interpreters[0] return evm @@ -200,17 +148,17 @@ func (evm *EVM) Interpreter() Interpreter { // parameters. It also handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. -func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { - if evm.vmConfig.NoRecursion && evm.depth > 0 { +func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, pack *vm.ExecPack) (ret []byte, leftOverGas uint64, err error) { + if evm.NoRecursion && evm.Depth > 0 { return nil, gas, nil } // Fail if we're trying to execute above the call depth limit - if evm.depth > int(params.CallCreateDepth) { + if evm.Depth > int(params.CallCreateDepth) { return nil, gas, vm.ErrDepth } // Fail if we're trying to transfer more than the available balance - if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, vm.ErrInsufficientBalance } @@ -226,7 +174,7 @@ func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, g if precompiles[addr] == nil && OracleContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { // Calling a non existing account, don't do anything, but ping the tracer - if evm.vmConfig.Debug && evm.depth == 0 { + if evm.vmConfig.Debug && evm.Depth == 0 { evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) } @@ -248,7 +196,7 @@ func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, g start := time.Now() // Capture the tracer start/end events in debug mode - if evm.vmConfig.Debug && evm.depth == 0 { + if evm.vmConfig.Debug && evm.Depth == 0 { evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) defer func() { // Lazy evaluation of the parameters @@ -276,13 +224,13 @@ func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, g // // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. -func (evm *EVM) CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { - if evm.vmConfig.NoRecursion && evm.depth > 0 { +func (evm *EVM) CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, pack *vm.ExecPack) (ret []byte, leftOverGas uint64, err error) { + if evm.NoRecursion && evm.Depth > 0 { return nil, gas, nil } // Fail if we're trying to execute above the call depth limit - if evm.depth > int(params.CallCreateDepth) { + if evm.Depth > int(params.CallCreateDepth) { return nil, gas, vm.ErrDepth } // Fail if we're trying to transfer more than the available balance @@ -320,12 +268,12 @@ func (evm *EVM) CallCode(caller vm.ContractRef, addr common.Address, input []byt // // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. -func (evm *EVM) DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { - if evm.vmConfig.NoRecursion && evm.depth > 0 { +func (evm *EVM) DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, pack *vm.ExecPack) (ret []byte, leftOverGas uint64, err error) { + if evm.NoRecursion && evm.Depth > 0 { return nil, gas, nil } // Fail if we're trying to execute above the call depth limit - if evm.depth > int(params.CallCreateDepth) { + if evm.Depth > int(params.CallCreateDepth) { return nil, gas, vm.ErrDepth } @@ -357,12 +305,17 @@ func (evm *EVM) DelegateCall(caller vm.ContractRef, addr common.Address, input [ // as parameters while disallowing any modifications to the state during the call. // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. -func (evm *EVM) StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { - if evm.vmConfig.NoRecursion && evm.depth > 0 { +func (evm *EVM) StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, pack *vm.ExecPack) (ret []byte, leftOverGas uint64, err error) { + oldReadOnly := pack.Context.ReadOnly + pack.Context.ReadOnly = true + defer func() { + pack.Context.ReadOnly = oldReadOnly + }() + if evm.NoRecursion && evm.Depth > 0 { return nil, gas, nil } // Fail if we're trying to execute above the call depth limit - if evm.depth > int(params.CallCreateDepth) { + if evm.Depth > int(params.CallCreateDepth) { return nil, gas, vm.ErrDepth } @@ -404,7 +357,7 @@ func (evm *EVM) StaticCall(caller vm.ContractRef, addr common.Address, input []b func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { // Depth check execution. Fail if we're trying to execute above the // limit. - if evm.depth > int(params.CallCreateDepth) { + if evm.Depth > int(params.CallCreateDepth) { return nil, common.Address{}, gas, vm.ErrDepth } if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { @@ -432,11 +385,11 @@ func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas u contract := vm.NewContract(caller, vm.AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) - if evm.vmConfig.NoRecursion && evm.depth > 0 { + if evm.NoRecursion && evm.Depth > 0 { return nil, address, gas, nil } - if evm.vmConfig.Debug && evm.depth == 0 { + if evm.vmConfig.Debug && evm.Depth == 0 { evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.Code, gas, value) } start := time.Now() @@ -470,7 +423,7 @@ func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas u if maxCodeSizeExceeded && err == nil { err = errMaxCodeSizeExceeded } - if evm.vmConfig.Debug && evm.depth == 0 { + if evm.vmConfig.Debug && evm.Depth == 0 { evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) } return ret, address, contract.Gas, err @@ -478,7 +431,7 @@ func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas u } // Create creates a new contract using code as deployment code. -func (evm *EVM) Create(caller vm.ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { +func (evm *EVM) Create(caller vm.ContractRef, code []byte, gas uint64, value *big.Int, pack *vm.ExecPack) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) return evm.create(caller, &vm.CodeAndHash{Code: code}, gas, value, contractAddr) } @@ -487,7 +440,7 @@ func (evm *EVM) Create(caller vm.ContractRef, code []byte, gas uint64, value *bi // // The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:] // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. -func (evm *EVM) Create2(caller vm.ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { +func (evm *EVM) Create2(caller vm.ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int, pack *vm.ExecPack) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { codeAndHash := &vm.CodeAndHash{Code: code} contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes()) return evm.create(caller, codeAndHash, gas, endowment, contractAddr) @@ -496,5 +449,8 @@ func (evm *EVM) Create2(caller vm.ContractRef, code []byte, gas uint64, endowmen // ChainConfig returns the environment's chain configuration func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } +// VMConfig returns the vm configuration. +func (evm *EVM) VMConfig() Config { return evm.vmConfig } + // IsBlockProposer returns whether or not we are a block proposer. func (evm *EVM) IsBlockProposer() bool { return evm.vmConfig.IsBlockProposer } diff --git a/core/vm/evm/evm_test.go b/core/vm/evm/evm_test.go index ef5e8a6b0..7fee1d435 100644 --- a/core/vm/evm/evm_test.go +++ b/core/vm/evm/evm_test.go @@ -91,15 +91,14 @@ func newTestVM() *testVM { Time: big.NewInt(time.Now().UnixNano() / 1000000000), BlockNumber: big.NewInt(0), } - - env := NewEVM(context, stateDB, params.TestChainConfig, Config{}) - evmInterpreter := NewEVMInterpreter(env, env.vmConfig) - - env.interpreter = evmInterpreter + vmConfig := [vmlib.NUMS]interface{}{} + vmConfig[vmlib.EVM] = Config{} + p := vmlib.NewExecPack(&context, stateDB, params.TestChainConfig, vmConfig) + evm := p.VMList[vmlib.EVM].(*EVM) return &testVM{ - evm: env, - interpreter: evmInterpreter, + evm: evm, + interpreter: NewEVMInterpreter(evm, evm.vmConfig), } } diff --git a/core/vm/evm/gas_table.go b/core/vm/evm/gas_table.go index 242494537..f0bf26726 100644 --- a/core/vm/evm/gas_table.go +++ b/core/vm/evm/gas_table.go @@ -415,11 +415,11 @@ func gasCall(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stac return 0, errGasUintOverflow } - evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.CallGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + if gas, overflow = math.SafeAdd(gas, evm.CallGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil @@ -439,11 +439,11 @@ func gasCallCode(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm. return 0, errGasUintOverflow } - evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.CallGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + if gas, overflow = math.SafeAdd(gas, evm.CallGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil @@ -493,11 +493,11 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *vm.Contract, stack return 0, errGasUintOverflow } - evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.CallGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + if gas, overflow = math.SafeAdd(gas, evm.CallGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil @@ -513,11 +513,11 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *v return 0, errGasUintOverflow } - evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.CallGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + if gas, overflow = math.SafeAdd(gas, evm.CallGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil diff --git a/core/vm/evm/instructions.go b/core/vm/evm/instructions.go index ce95d2446..23e59aa4b 100644 --- a/core/vm/evm/instructions.go +++ b/core/vm/evm/instructions.go @@ -55,7 +55,7 @@ func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor x, y := stack.Pop(), stack.Peek() math.U256(y.Add(x, y)) - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -63,7 +63,7 @@ func opSub(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor x, y := stack.Pop(), stack.Peek() math.U256(y.Sub(x, y)) - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -71,7 +71,7 @@ func opMul(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor x, y := stack.Pop(), stack.Pop() stack.Push(math.U256(x.Mul(x, y))) - interpreter.intPool.Put(y) + interpreter.evm.IntPool.Put(y) return nil, nil } @@ -83,13 +83,13 @@ func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor } else { y.SetUint64(0) } - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := math.S256(stack.Pop()), math.S256(stack.Pop()) - res := interpreter.intPool.GetZero() + res := interpreter.evm.IntPool.GetZero() if y.Sign() == 0 || x.Sign() == 0 { stack.Push(res) @@ -102,7 +102,7 @@ func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo } stack.Push(math.U256(res)) } - interpreter.intPool.Put(x, y) + interpreter.evm.IntPool.Put(x, y) return nil, nil } @@ -113,13 +113,13 @@ func opMod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor } else { stack.Push(math.U256(x.Mod(x, y))) } - interpreter.intPool.Put(y) + interpreter.evm.IntPool.Put(y) return nil, nil } func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := math.S256(stack.Pop()), math.S256(stack.Pop()) - res := interpreter.intPool.GetZero() + res := interpreter.evm.IntPool.GetZero() if y.Sign() == 0 { stack.Push(res) @@ -132,7 +132,7 @@ func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo } stack.Push(math.U256(res)) } - interpreter.intPool.Put(x, y) + interpreter.evm.IntPool.Put(x, y) return nil, nil } @@ -140,12 +140,12 @@ func opExp(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor base, exponent := stack.Pop(), stack.Pop() if base.Cmp(big2) == 0 && exponent.Cmp(big256) == -1 { exp := exponent.Int64() - stack.Push(interpreter.intPool.Get().Set(power2[exp])) + stack.Push(interpreter.evm.IntPool.Get().Set(power2[exp])) } else { stack.Push(math.Exp(base, exponent)) } - interpreter.intPool.Put(base, exponent) + interpreter.evm.IntPool.Put(base, exponent) return nil, nil } @@ -166,7 +166,7 @@ func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract stack.Push(math.U256(num)) } - interpreter.intPool.Put(back) + interpreter.evm.IntPool.Put(back) return nil, nil } @@ -183,7 +183,7 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory } else { y.SetUint64(0) } - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -194,7 +194,7 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory } else { y.SetUint64(0) } - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -218,7 +218,7 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor y.SetUint64(0) } } - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -242,7 +242,7 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor y.SetUint64(0) } } - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -253,7 +253,7 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory } else { y.SetUint64(0) } - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -271,7 +271,7 @@ func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor x, y := stack.Pop(), stack.Pop() stack.Push(x.And(x, y)) - interpreter.intPool.Put(y) + interpreter.evm.IntPool.Put(y) return nil, nil } @@ -279,7 +279,7 @@ func opOr(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory x, y := stack.Pop(), stack.Peek() y.Or(x, y) - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -287,7 +287,7 @@ func opXor(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor x, y := stack.Pop(), stack.Peek() y.Xor(x, y) - interpreter.intPool.Put(x) + interpreter.evm.IntPool.Put(x) return nil, nil } @@ -299,7 +299,7 @@ func opByte(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo } else { val.SetUint64(0) } - interpreter.intPool.Put(th) + interpreter.evm.IntPool.Put(th) return nil, nil } @@ -312,7 +312,7 @@ func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me } else { stack.Push(x.SetUint64(0)) } - interpreter.intPool.Put(y, z) + interpreter.evm.IntPool.Put(y, z) return nil, nil } @@ -325,7 +325,7 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me } else { stack.Push(x.SetUint64(0)) } - interpreter.intPool.Put(y, z) + interpreter.evm.IntPool.Put(y, z) return nil, nil } @@ -335,7 +335,7 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := math.U256(stack.Pop()), math.U256(stack.Peek()) - defer interpreter.intPool.Put(shift) // First operand back into the pool + defer interpreter.evm.IntPool.Put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { value.SetUint64(0) @@ -353,7 +353,7 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := math.U256(stack.Pop()), math.U256(stack.Peek()) - defer interpreter.intPool.Put(shift) // First operand back into the pool + defer interpreter.evm.IntPool.Put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { value.SetUint64(0) @@ -371,7 +371,7 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memor func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one shift, value := math.U256(stack.Pop()), math.S256(stack.Pop()) - defer interpreter.intPool.Put(shift) // First operand back into the pool + defer interpreter.evm.IntPool.Put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { if value.Sign() >= 0 { @@ -405,9 +405,9 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo if evm.vmConfig.EnablePreimageRecording { evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } - stack.Push(interpreter.intPool.Get().SetBytes(interpreter.hasherBuf[:])) + stack.Push(interpreter.evm.IntPool.Get().SetBytes(interpreter.hasherBuf[:])) - interpreter.intPool.Put(offset, size) + interpreter.evm.IntPool.Put(offset, size) return nil, nil } @@ -421,7 +421,7 @@ func opRand(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo binaryUsedIndex := make([]byte, binary.MaxVarintLen64) binary.PutUvarint(binaryUsedIndex, evm.RandCallIndex) - evm.RandCallIndex += 1 + evm.RandCallIndex++ hash := crypto.Keccak256( evm.Randomness, @@ -429,7 +429,7 @@ func opRand(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo binaryOriginNonce, binaryUsedIndex) - stack.Push(interpreter.intPool.Get().SetBytes(hash)) + stack.Push(interpreter.evm.IntPool.Get().SetBytes(hash)) return nil, nil } @@ -455,17 +455,17 @@ func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me } func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().Set(contract.Value)) + stack.Push(interpreter.evm.IntPool.Get().Set(contract.Value)) return nil, nil } func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().SetBytes(vm.GetDataBig(contract.Input, stack.Pop(), big32))) + stack.Push(interpreter.evm.IntPool.Get().SetBytes(vm.GetDataBig(contract.Input, stack.Pop(), big32))) return nil, nil } func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().SetInt64(int64(len(contract.Input)))) + stack.Push(interpreter.evm.IntPool.Get().SetInt64(int64(len(contract.Input)))) return nil, nil } @@ -477,12 +477,12 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contra ) memory.Set(memOffset.Uint64(), length.Uint64(), vm.GetDataBig(contract.Input, dataOffset, length)) - interpreter.intPool.Put(memOffset, dataOffset, length) + interpreter.evm.IntPool.Put(memOffset, dataOffset, length) return nil, nil } func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().SetUint64(uint64(len(interpreter.returnData)))) + stack.Push(interpreter.evm.IntPool.Get().SetUint64(uint64(len(interpreter.returnData)))) return nil, nil } @@ -491,9 +491,9 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Cont memOffset = stack.Pop() dataOffset = stack.Pop() length = stack.Pop() - end = interpreter.intPool.Get().Add(dataOffset, length) + end = interpreter.evm.IntPool.Get().Add(dataOffset, length) ) - defer interpreter.intPool.Put(memOffset, dataOffset, length, end) + defer interpreter.evm.IntPool.Put(memOffset, dataOffset, length, end) if end.BitLen() > 64 || uint64(len(interpreter.returnData)) < end.Uint64() { return nil, errReturnDataOutOfBounds @@ -511,7 +511,7 @@ func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contrac } func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - l := interpreter.intPool.Get().SetInt64(int64(len(contract.Code))) + l := interpreter.evm.IntPool.Get().SetInt64(int64(len(contract.Code))) stack.Push(l) return nil, nil @@ -526,7 +526,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, codeCopy := vm.GetDataBig(contract.Code, codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - interpreter.intPool.Put(memOffset, codeOffset, length) + interpreter.evm.IntPool.Put(memOffset, codeOffset, length) return nil, nil } @@ -540,7 +540,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contrac codeCopy := vm.GetDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - interpreter.intPool.Put(memOffset, codeOffset, length) + interpreter.evm.IntPool.Put(memOffset, codeOffset, length) return nil, nil } @@ -582,20 +582,20 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contrac } func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().Set(interpreter.evm.GasPrice)) + stack.Push(interpreter.evm.IntPool.Get().Set(interpreter.evm.GasPrice)) return nil, nil } func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { num := stack.Pop() - n := interpreter.intPool.Get().Sub(interpreter.evm.BlockNumber, common.Big257) + n := interpreter.evm.IntPool.Get().Sub(interpreter.evm.BlockNumber, common.Big257) if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 { stack.Push(interpreter.evm.GetHash(num.Uint64()).Big()) } else { - stack.Push(interpreter.intPool.GetZero()) + stack.Push(interpreter.evm.IntPool.GetZero()) } - interpreter.intPool.Put(num, n) + interpreter.evm.IntPool.Put(num, n) return nil, nil } @@ -605,36 +605,36 @@ func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, } func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.Time))) + stack.Push(math.U256(interpreter.evm.IntPool.Get().Set(interpreter.evm.Time))) return nil, nil } func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.BlockNumber))) + stack.Push(math.U256(interpreter.evm.IntPool.Get().Set(interpreter.evm.BlockNumber))) return nil, nil } func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.Difficulty))) + stack.Push(math.U256(interpreter.evm.IntPool.Get().Set(interpreter.evm.Difficulty))) return nil, nil } func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(math.U256(interpreter.intPool.Get().SetUint64(interpreter.evm.GasLimit))) + stack.Push(math.U256(interpreter.evm.IntPool.Get().SetUint64(interpreter.evm.GasLimit))) return nil, nil } func opPop(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - interpreter.intPool.Put(stack.Pop()) + interpreter.evm.IntPool.Put(stack.Pop()) return nil, nil } func opMload(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { offset := stack.Pop() - val := interpreter.intPool.Get().SetBytes(memory.Get(offset.Int64(), 32)) + val := interpreter.evm.IntPool.Get().SetBytes(memory.Get(offset.Int64(), 32)) stack.Push(val) - interpreter.intPool.Put(offset) + interpreter.evm.IntPool.Put(offset) return nil, nil } @@ -643,7 +643,7 @@ func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me mStart, val := stack.Pop(), stack.Pop() memory.Set32(mStart.Uint64(), val) - interpreter.intPool.Put(mStart, val) + interpreter.evm.IntPool.Put(mStart, val) return nil, nil } @@ -666,7 +666,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me val := stack.Pop() interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) - interpreter.intPool.Put(val) + interpreter.evm.IntPool.Put(val) return nil, nil } @@ -678,7 +678,7 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo } *pc = pos.Uint64() - interpreter.intPool.Put(pos) + interpreter.evm.IntPool.Put(pos) return nil, nil } @@ -694,7 +694,7 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, mem *pc++ } - interpreter.intPool.Put(pos, cond) + interpreter.evm.IntPool.Put(pos, cond) return nil, nil } @@ -703,17 +703,17 @@ func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, } func opPc(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().SetUint64(*pc)) + stack.Push(interpreter.evm.IntPool.Get().SetUint64(*pc)) return nil, nil } func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().SetInt64(int64(memory.Len()))) + stack.Push(interpreter.evm.IntPool.Get().SetInt64(int64(memory.Len()))) return nil, nil } func opGas(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().SetUint64(contract.Gas)) + stack.Push(interpreter.evm.IntPool.Get().SetUint64(contract.Gas)) return nil, nil } @@ -729,20 +729,20 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me gas -= gas / 64 } contract.UseGas(gas) - res, addr, returnGas, suberr := vm.Create(contract, input, gas, value, interpreter) + res, addr, returnGas, suberr := vm.Create(contract, input, gas, value, interpreter.evm.ExecPack) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. if interpreter.evm.ChainConfig().IsHomestead(interpreter.evm.BlockNumber) && suberr == vm.ErrCodeStoreOutOfGas { - stack.Push(interpreter.intPool.GetZero()) + stack.Push(interpreter.evm.IntPool.GetZero()) } else if suberr != nil && suberr != vm.ErrCodeStoreOutOfGas { - stack.Push(interpreter.intPool.GetZero()) + stack.Push(interpreter.evm.IntPool.GetZero()) } else { stack.Push(addr.Big()) } contract.Gas += returnGas - interpreter.intPool.Put(value, offset, size) + interpreter.evm.IntPool.Put(value, offset, size) if suberr == errExecutionReverted { return res, nil @@ -762,15 +762,15 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, m // Apply EIP150 gas -= gas / 64 contract.UseGas(gas) - res, addr, returnGas, suberr := vm.Create2(contract, input, gas, endowment, salt, interpreter) + res, addr, returnGas, suberr := vm.Create2(contract, input, gas, endowment, salt, interpreter.evm.ExecPack) // Push item on the stack based on the returned error. if suberr != nil { - stack.Push(interpreter.intPool.GetZero()) + stack.Push(interpreter.evm.IntPool.GetZero()) } else { stack.Push(addr.Big()) } contract.Gas += returnGas - interpreter.intPool.Put(endowment, offset, size, salt) + interpreter.evm.IntPool.Put(endowment, offset, size, salt) if suberr == errExecutionReverted { return res, nil @@ -779,9 +779,9 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, m } func opCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - // Pop gas. The actual gas in interpreter.evm.callGasTemp. - interpreter.intPool.Put(stack.Pop()) - gas := interpreter.evm.callGasTemp + // Pop gas. The actual gas in interpreter.evm.CallGasTemp. + interpreter.evm.IntPool.Put(stack.Pop()) + gas := interpreter.evm.CallGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() toAddr := common.BigToAddress(addr) @@ -792,25 +792,25 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memo if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := vm.Call(contract, toAddr, args, gas, value, interpreter) + ret, returnGas, err := vm.Call(contract, toAddr, args, gas, value, interpreter.evm.ExecPack) if err != nil { - stack.Push(interpreter.intPool.GetZero()) + stack.Push(interpreter.evm.IntPool.GetZero()) } else { - stack.Push(interpreter.intPool.Get().SetUint64(1)) + stack.Push(interpreter.evm.IntPool.Get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - interpreter.intPool.Put(addr, value, inOffset, inSize, retOffset, retSize) + interpreter.evm.IntPool.Put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.Put(stack.Pop()) - gas := interpreter.evm.callGasTemp + // Pop gas. The actual gas is in interpreter.evm.CallGasTemp. + interpreter.evm.IntPool.Put(stack.Pop()) + gas := interpreter.evm.CallGasTemp // Pop other call parameters. addr, value, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() toAddr := common.BigToAddress(addr) @@ -821,68 +821,68 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := vm.CallCode(contract, toAddr, args, gas, value, interpreter) + ret, returnGas, err := vm.CallCode(contract, toAddr, args, gas, value, interpreter.evm.ExecPack) if err != nil { - stack.Push(interpreter.intPool.GetZero()) + stack.Push(interpreter.evm.IntPool.GetZero()) } else { - stack.Push(interpreter.intPool.Get().SetUint64(1)) + stack.Push(interpreter.evm.IntPool.Get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - interpreter.intPool.Put(addr, value, inOffset, inSize, retOffset, retSize) + interpreter.evm.IntPool.Put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.Put(stack.Pop()) - gas := interpreter.evm.callGasTemp + // Pop gas. The actual gas is in interpreter.evm.CallGasTemp. + interpreter.evm.IntPool.Put(stack.Pop()) + gas := interpreter.evm.CallGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := vm.DelegateCall(contract, toAddr, args, gas, interpreter) + ret, returnGas, err := vm.DelegateCall(contract, toAddr, args, gas, interpreter.evm.ExecPack) if err != nil { - stack.Push(interpreter.intPool.GetZero()) + stack.Push(interpreter.evm.IntPool.GetZero()) } else { - stack.Push(interpreter.intPool.Get().SetUint64(1)) + stack.Push(interpreter.evm.IntPool.Get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - interpreter.intPool.Put(addr, inOffset, inSize, retOffset, retSize) + interpreter.evm.IntPool.Put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.Put(stack.Pop()) - gas := interpreter.evm.callGasTemp + // Pop gas. The actual gas is in interpreter.evm.CallGasTemp. + interpreter.evm.IntPool.Put(stack.Pop()) + gas := interpreter.evm.CallGasTemp // Pop other call parameters. addr, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := vm.StaticCall(contract, toAddr, args, gas, interpreter) + ret, returnGas, err := vm.StaticCall(contract, toAddr, args, gas, interpreter.evm.ExecPack) if err != nil { - stack.Push(interpreter.intPool.GetZero()) + stack.Push(interpreter.evm.IntPool.GetZero()) } else { - stack.Push(interpreter.intPool.Get().SetUint64(1)) + stack.Push(interpreter.evm.IntPool.Get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - interpreter.intPool.Put(addr, inOffset, inSize, retOffset, retSize) + interpreter.evm.IntPool.Put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } @@ -890,7 +890,7 @@ func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me offset, size := stack.Pop(), stack.Pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) - interpreter.intPool.Put(offset, size) + interpreter.evm.IntPool.Put(offset, size) return ret, nil } @@ -898,7 +898,7 @@ func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, me offset, size := stack.Pop(), stack.Pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) - interpreter.intPool.Put(offset, size) + interpreter.evm.IntPool.Put(offset, size) return ret, nil } @@ -935,7 +935,7 @@ func makeLog(size int) executionFunc { BlockNumber: interpreter.evm.BlockNumber.Uint64(), }) - interpreter.intPool.Put(mStart, mSize) + interpreter.evm.IntPool.Put(mStart, mSize) return nil, nil } } @@ -955,7 +955,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { endMin = startMin + pushByteSize } - integer := interpreter.intPool.Get() + integer := interpreter.evm.IntPool.Get() stack.Push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize))) *pc += size @@ -966,7 +966,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { // make dup instruction function func makeDup(size int64) executionFunc { return func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Dup(interpreter.intPool, int(size)) + stack.Dup(interpreter.evm.IntPool, int(size)) return nil, nil } } diff --git a/core/vm/evm/instructions_test.go b/core/vm/evm/instructions_test.go index bd3df271d..78d175aa9 100644 --- a/core/vm/evm/instructions_test.go +++ b/core/vm/evm/instructions_test.go @@ -35,14 +35,15 @@ type twoOperandTest struct { func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error)) { var ( - env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) - stack = NewStack() - pc = uint64(0) - evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + stack = NewStack() + pc = uint64(0) ) - - env.interpreter = evmInterpreter - evmInterpreter.intPool = vm.PoolOfIntPools.Get() + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = Config{} + vmctx := &vm.Context{IntPool: vm.NewIntPool()} + pack := vm.NewExecPack(vmctx, nil, params.TestChainConfig, vmConfig) + evm := pack.VMList[vm.EVM].(*EVM) + evmInterpreter := NewEVMInterpreter(evm, vmConfig[vm.EVM].(Config)) for i, test := range tests { x := new(big.Int).SetBytes(common.Hex2Bytes(test.x)) shift := new(big.Int).SetBytes(common.Hex2Bytes(test.y)) @@ -57,13 +58,13 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64 // Check pool usage // 1.pool is not allowed to contain anything on the stack // 2.pool is not allowed to contain the same pointers twice - if evmInterpreter.intPool.Pool.Len() > 0 { + if evm.IntPool.Pool.Len() > 0 { poolvals := make(map[*big.Int]struct{}) poolvals[actual] = struct{}{} - for evmInterpreter.intPool.Pool.Len() > 0 { - key := evmInterpreter.intPool.Get() + for evm.IntPool.Pool.Len() > 0 { + key := evm.IntPool.Get() if _, exist := poolvals[key]; exist { t.Errorf("Testcase %d, pool contains double-entry", i) } @@ -71,18 +72,19 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64 } } } - vm.PoolOfIntPools.Put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evm.IntPool) } func TestByteOp(t *testing.T) { var ( - env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) - stack = NewStack() - evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + stack = NewStack() ) - - env.interpreter = evmInterpreter - evmInterpreter.intPool = vm.PoolOfIntPools.Get() + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = Config{} + vmctx := &vm.Context{IntPool: vm.NewIntPool()} + pack := vm.NewExecPack(vmctx, nil, params.TestChainConfig, vmConfig) + evm := pack.VMList[vm.EVM].(*EVM) + evmInterpreter := NewEVMInterpreter(evm, vmConfig[vm.EVM].(Config)) tests := []struct { v string th uint64 @@ -109,7 +111,7 @@ func TestByteOp(t *testing.T) { t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.v, test.th, test.expected, actual) } } - vm.PoolOfIntPools.Put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evm.IntPool) } func TestSHL(t *testing.T) { @@ -211,13 +213,15 @@ func TestSLT(t *testing.T) { func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error), args ...string) { var ( - env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) - stack = NewStack() - evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + stack = NewStack() ) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = Config{} + vmctx := &vm.Context{IntPool: vm.NewIntPool()} + pack := vm.NewExecPack(vmctx, nil, params.TestChainConfig, vmConfig) + evm := pack.VMList[vm.EVM].(*EVM) + evmInterpreter := NewEVMInterpreter(evm, vmConfig[vm.EVM].(Config)) - env.interpreter = evmInterpreter - evmInterpreter.intPool = vm.PoolOfIntPools.Get() // convert args byteArgs := make([][]byte, len(args)) for i, arg := range args { @@ -233,7 +237,7 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpret op(&pc, evmInterpreter, nil, nil, stack) stack.Pop() } - vm.PoolOfIntPools.Put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evm.IntPool) } func BenchmarkOpAdd64(b *testing.B) { @@ -446,14 +450,16 @@ func BenchmarkOpIsZero(b *testing.B) { func TestOpMstore(t *testing.T) { var ( - env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) - stack = NewStack() - mem = vm.NewMemory() - evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + stack = NewStack() + mem = vm.NewMemory() ) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = Config{} + ctx := &vm.Context{IntPool: vm.NewIntPool()} + pack := vm.NewExecPack(ctx, nil, params.TestChainConfig, vmConfig) + evm := pack.VMList[vm.EVM].(*EVM) + evmInterpreter := NewEVMInterpreter(evm, vmConfig[vm.EVM].(Config)) - env.interpreter = evmInterpreter - evmInterpreter.intPool = vm.PoolOfIntPools.Get() mem.Resize(64) pc := uint64(0) v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" @@ -467,19 +473,22 @@ func TestOpMstore(t *testing.T) { if common.Bytes2Hex(mem.Get(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { t.Fatalf("Mstore failed to overwrite previous value") } - vm.PoolOfIntPools.Put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evm.IntPool) } func BenchmarkOpMstore(bench *testing.B) { var ( - env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) - stack = NewStack() - mem = vm.NewMemory() - evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + stack = NewStack() + mem = vm.NewMemory() ) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = Config{} + vmctx := &vm.Context{} + vmctx.IntPool = vm.NewIntPool() + pack := vm.NewExecPack(vmctx, nil, params.TestChainConfig, vmConfig) + evm := pack.VMList[vm.EVM].(*EVM) + evmInterpreter := NewEVMInterpreter(evm, vmConfig[vm.EVM].(Config)) - env.interpreter = evmInterpreter - evmInterpreter.intPool = vm.PoolOfIntPools.Get() mem.Resize(64) pc := uint64(0) memStart := big.NewInt(0) @@ -490,18 +499,21 @@ func BenchmarkOpMstore(bench *testing.B) { stack.PushN(value, memStart) opMstore(&pc, evmInterpreter, nil, mem, stack) } - vm.PoolOfIntPools.Put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evm.Context.IntPool) } func BenchmarkOpSHA3(bench *testing.B) { var ( - env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) - stack = NewStack() - mem = vm.NewMemory() - evmInterpreter = NewEVMInterpreter(env, env.vmConfig) + stack = NewStack() + mem = vm.NewMemory() ) - env.interpreter = evmInterpreter - evmInterpreter.intPool = vm.PoolOfIntPools.Get() + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = Config{} + vmctx := &vm.Context{} + vmctx.IntPool = vm.NewIntPool() + pack := vm.NewExecPack(vmctx, nil, params.TestChainConfig, vmConfig) + evm := pack.VMList[vm.EVM].(*EVM) + evmInterpreter := NewEVMInterpreter(evm, vmConfig[vm.EVM].(Config)) mem.Resize(32) pc := uint64(0) start := big.NewInt(0) @@ -511,7 +523,7 @@ func BenchmarkOpSHA3(bench *testing.B) { stack.PushN(big.NewInt(32), start) opSha3(&pc, evmInterpreter, nil, mem, stack) } - vm.PoolOfIntPools.Put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evm.IntPool) } func TestCreate2Addreses(t *testing.T) { diff --git a/core/vm/evm/interpreter.go b/core/vm/evm/interpreter.go index 9ed647c00..bcbd8b024 100644 --- a/core/vm/evm/interpreter.go +++ b/core/vm/evm/interpreter.go @@ -27,15 +27,11 @@ import ( "github.com/dexon-foundation/dexon/params" ) -// Config are the configuration options for the Interpreter type Config struct { // Debug enabled debugging Interpreter options Debug bool // Tracer is the op code logger Tracer Tracer - // NoRecursion disabled Interpreter call, callcode, - // delegate call and create. - NoRecursion bool // Enable recording of SHA3/keccak preimages EnablePreimageRecording bool // JumpTable contains the EVM instruction table. This @@ -88,12 +84,9 @@ type EVMInterpreter struct { cfg Config gasTable params.GasTable - intPool *vm.IntPool - hasher keccakState // Keccak256 hasher instance shared across opcodes hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes - readOnly bool // Whether to throw on stateful modifications returnData []byte // Last CALL's return data for subsequent reuse } @@ -114,17 +107,16 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { cfg.JumpTable = frontierInstructionSet } } - return &EVMInterpreter{ evm: evm, - cfg: cfg, gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), + cfg: cfg, } } func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *vm.Stack) error { if in.evm.chainRules.IsByzantium { - if in.readOnly { + if in.evm.ReadOnly { // If the interpreter is operating in readonly mode, make sure no // state-modifying operation is performed. The 3rd stack item // for a call operation is the value. Transferring value from one @@ -145,23 +137,23 @@ func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, st // considered a revert-and-consume-all-gas operation except for // errExecutionReverted which means revert-and-keep-gas-left. func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool) (ret []byte, err error) { - if in.intPool == nil { - in.intPool = vm.PoolOfIntPools.Get() + if in.evm.IntPool == nil { + in.evm.IntPool = vm.PoolOfIntPools.Get() defer func() { - vm.PoolOfIntPools.Put(in.intPool) - in.intPool = nil + vm.PoolOfIntPools.Put(in.evm.IntPool) + in.evm.IntPool = nil }() } // Increment the call depth which is restricted to 1024 - in.evm.depth++ - defer func() { in.evm.depth-- }() + in.evm.Depth++ + defer func() { in.evm.Depth-- }() // Make sure the readOnly is only set if we aren't in readOnly yet. // This makes also sure that the readOnly flag isn't removed for child calls. - if readOnly && !in.readOnly { - in.readOnly = true - defer func() { in.readOnly = false }() + if readOnly && !in.evm.ReadOnly { + in.evm.ReadOnly = true + defer func() { in.evm.ReadOnly = false }() } // Reset the previous call's return data. It's unimportant to preserve the old buffer @@ -189,17 +181,17 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool contract.Input = input // Reclaim the stack as an int pool when the execution stops defer func() { - in.intPool.Put(stack.Data...) + in.evm.IntPool.Put(stack.Data...) Recyclestack(stack) }() - if in.cfg.Debug { + if in.evm.vmConfig.Debug { defer func() { if err != nil { if !logged { - in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) + in.evm.vmConfig.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.Depth, err) } else { - in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) + in.evm.vmConfig.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.Depth, err) } } }() @@ -209,7 +201,7 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool // the execution of one of the operations or until the done flag is set by the // parent context. for atomic.LoadInt32(&in.evm.abort) == 0 { - if in.cfg.Debug { + if in.evm.vmConfig.Debug { // Capture pre-execution values for tracing. logged, pcCopy, gasCopy = false, pc, contract.Gas } @@ -254,8 +246,8 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool mem.Resize(memorySize) } - if in.cfg.Debug { - in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) + if in.evm.vmConfig.Debug { + in.evm.vmConfig.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.Depth, err) logged = true } @@ -264,7 +256,7 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool // verifyPool is a build flag. Pool verification makes sure the integrity // of the integer pool by comparing values to a default value. if vm.VerifyPool { - vm.VerifyIntegerPool(in.intPool) + vm.VerifyIntegerPool(in.evm.IntPool) } // if the operation clears the return data (e.g. it has returning data) // set the last return to the result of the operation. @@ -292,8 +284,3 @@ func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool func (in *EVMInterpreter) CanRun(code []byte) bool { return true } - -// StateDB return StateDB stored in evm -func (in *EVMInterpreter) StateDB() vm.StateDB { - return in.evm.StateDB -} diff --git a/core/vm/evm/logger_test.go b/core/vm/evm/logger_test.go index 3a293675b..782fcd11f 100644 --- a/core/vm/evm/logger_test.go +++ b/core/vm/evm/logger_test.go @@ -51,16 +51,19 @@ func (*dummyStatedb) GetRefund() uint64 { return 1337 } func TestStoreCapture(t *testing.T) { var ( - env = NewEVM(vm.Context{}, &dummyStatedb{}, params.TestChainConfig, Config{}) logger = NewStructLogger(nil) mem = vm.NewMemory() stack = NewStack() contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0) ) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = Config{} + vmctx := &vm.Context{IntPool: vm.NewIntPool()} + pack := vm.NewExecPack(vmctx, &dummyStatedb{}, params.TestChainConfig, vmConfig) stack.Push(big.NewInt(1)) stack.Push(big.NewInt(0)) var index common.Hash - logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil) + logger.CaptureState(pack.VMList[vm.EVM].(*EVM), 0, SSTORE, 0, 0, mem, stack, contract, 0, nil) if len(logger.changedValues[contract.Address()]) == 0 { t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()])) } diff --git a/core/vm/evm/oracle_contracts_test.go b/core/vm/evm/oracle_contracts_test.go index 41bf0fb58..55a011f33 100644 --- a/core/vm/evm/oracle_contracts_test.go +++ b/core/vm/evm/oracle_contracts_test.go @@ -249,8 +249,11 @@ func (g *OracleContractsTestSuite) call( g.context.Time = big.NewInt(time.Now().UnixNano() / 1000000) - evm := NewEVM(g.context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) - ret, _, err := evm.Call(vm.AccountRef(caller), contractAddr, input, 10000000, value) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = Config{IsBlockProposer: true} + pack := vm.NewExecPack(&g.context, g.stateDB, params.TestChainConfig, vmConfig) + evm := pack.VMList[vm.EVM].(*EVM) + ret, _, err := evm.Call(vm.AccountRef(caller), contractAddr, input, 10000000, value, &pack) return ret, err } @@ -1102,7 +1105,7 @@ func (g *OracleContractsTestSuite) TestResetDKG() { g.s.PutDKGSuccess(addr, true) g.s.IncDKGSuccessesCount() } - i += 1 + i++ } dkgSetSize := len(dkgSet) g.Require().Len(g.s.DKGMasterPublicKeys(), dkgSetSize) diff --git a/core/vm/evm/runtime/env.go b/core/vm/evm/runtime/env.go index 92cc8681c..a7a8f6b6c 100644 --- a/core/vm/evm/runtime/env.go +++ b/core/vm/evm/runtime/env.go @@ -20,15 +20,14 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core" "github.com/dexon-foundation/dexon/core/vm" - "github.com/dexon-foundation/dexon/core/vm/evm" ) -func NewEnv(cfg *Config) *evm.EVM { +// NewExecPack is a wrapper for creating ExecPack. +func NewExecPack(cfg *Config) vm.ExecPack { context := vm.Context{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, GetHash: func(uint64) common.Hash { return common.Hash{} }, - Origin: cfg.Origin, Coinbase: cfg.Coinbase, BlockNumber: cfg.BlockNumber, @@ -37,6 +36,7 @@ func NewEnv(cfg *Config) *evm.EVM { GasLimit: cfg.GasLimit, GasPrice: cfg.GasPrice, } - - return evm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) + vmConfig := [vm.NUMS]interface{}{} + vmConfig[vm.EVM] = cfg.EVMConfig + return vm.NewExecPack(&context, cfg.State, cfg.ChainConfig, vmConfig) } diff --git a/core/vm/evm/runtime/runtime.go b/core/vm/evm/runtime/runtime.go index c89f9dd11..3745f001b 100644 --- a/core/vm/evm/runtime/runtime.go +++ b/core/vm/evm/runtime/runtime.go @@ -5,8 +5,7 @@ // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, +// // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. @@ -104,19 +103,20 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { } var ( address = common.BytesToAddress([]byte("contract")) - vmenv = NewEnv(cfg) + pack = NewExecPack(cfg) sender = vm.AccountRef(cfg.Origin) ) cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. cfg.State.SetCode(address, code) // Call the code with the given configuration. - ret, _, err := vmenv.Call( + ret, _, err := pack.VMList[vm.EVM].(*evm.EVM).Call( sender, common.BytesToAddress([]byte("contract")), input, cfg.GasLimit, cfg.Value, + &pack, ) return ret, cfg.State, err @@ -133,16 +133,17 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) } var ( - vmenv = NewEnv(cfg) + pack = NewExecPack(cfg) sender = vm.AccountRef(cfg.Origin) ) // Call the code with the given configuration. - code, address, leftOverGas, err := vmenv.Create( + code, address, leftOverGas, err := pack.VMList[vm.EVM].(*evm.EVM).Create( sender, input, cfg.GasLimit, cfg.Value, + &pack, ) return code, address, leftOverGas, err } @@ -155,16 +156,17 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { setDefaults(cfg) - vmenv := NewEnv(cfg) - + pack := NewExecPack(cfg) + e := pack.VMList[vm.EVM].(*evm.EVM) sender := cfg.State.GetOrNewStateObject(cfg.Origin) // Call the code with the given configuration. - ret, leftOverGas, err := vmenv.Call( + ret, leftOverGas, err := e.Call( sender, address, input, cfg.GasLimit, cfg.Value, + &pack, ) return ret, leftOverGas, err diff --git a/core/vm/evm/runtime/runtime_test.go b/core/vm/evm/runtime/runtime_test.go index 762f3601d..46e4a934d 100644 --- a/core/vm/evm/runtime/runtime_test.go +++ b/core/vm/evm/runtime/runtime_test.go @@ -29,6 +29,7 @@ import ( "github.com/dexon-foundation/dexon/core/vm/tools" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" + "github.com/stretchr/testify/assert" ) func TestDefaults(t *testing.T) { @@ -121,6 +122,55 @@ func TestCall(t *testing.T) { } } +func TestStaticCallAndRand(t *testing.T) { + state, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) + address := common.HexToAddress("0x0a") + address2 := common.HexToAddress("0x0b") + code := []byte{ + byte(vm.EVM), + byte(evm.PUSH1), 0, // StaticCall retSize + byte(evm.PUSH1), 0, // StaticCall retOffset + byte(evm.PUSH1), 0, // StaticCall inputSize + byte(evm.PUSH1), 0, // StaticCall inputOffset + byte(evm.PUSH20), + } + code = append(code, address2.Bytes()...) + code = append(code, + byte(evm.PUSH1), 0xff, // StaticCall gas + byte(evm.STATICCALL), + byte(evm.RAND), + byte(evm.RETURN), + ) + state.SetCode(address, code) + + state.SetCode(address2, []byte{ + byte(vm.EVM), + byte(evm.RAND), + byte(evm.RETURN), + }) + + cfg := &Config{ + State: state, + } + setDefaults(cfg) + cfg.ChainConfig.ByzantiumBlock = new(big.Int).SetUint64(0) + + pack := NewExecPack(cfg) + e := pack.VMList[vm.EVM] + sender := cfg.State.GetOrNewStateObject(cfg.Origin) + _, _, err := e.Call( + sender, + address, + nil, + cfg.GasLimit, + cfg.Value, + &pack, + ) + assert.Equal(t, nil, err) + assert.Equal(t, uint64(2), pack.Context.RandCallIndex) + assert.Equal(t, false, pack.Context.ReadOnly) +} + func BenchmarkCall(b *testing.B) { var definition = `[{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[],"name":"Aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"PurchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"ItemReceived","type":"event"},{"anonymous":false,"inputs":[],"name":"Refunded","type":"event"}]` diff --git a/core/vm/intpool.go b/core/vm/intpool.go index 9e73b8b71..5a2d6383f 100644 --- a/core/vm/intpool.go +++ b/core/vm/intpool.go @@ -23,6 +23,7 @@ import ( var checkVal = big.NewInt(-42) +// PoolLimit is the size of stack of IntPool const PoolLimit = 256 // IntPool is a Pool of big integers that @@ -31,11 +32,12 @@ type IntPool struct { Pool *Stack } -func newIntPool() *IntPool { +// NewIntPool return an IntPool instance. +func NewIntPool() *IntPool { return &IntPool{Pool: &Stack{Data: make([]*big.Int, 0, 1024)}} } -// get retrieves a big int from the Pool, allocating one if the Pool is empty. +// Get retrieves a big int from the Pool, allocating one if the Pool is empty. // Note, the returned int's value is arbitrary and will not be zeroed! func (p *IntPool) Get() *big.Int { if p.Pool.Len() > 0 { @@ -44,7 +46,7 @@ func (p *IntPool) Get() *big.Int { return new(big.Int) } -// getZero retrieves a big int from the Pool, setting it to zero or allocating +// GetZero retrieves a big int from the Pool, setting it to zero or allocating // a new one if the Pool is empty. func (p *IntPool) GetZero() *big.Int { if p.Pool.Len() > 0 { @@ -53,7 +55,7 @@ func (p *IntPool) GetZero() *big.Int { return new(big.Int) } -// put returns an allocated big int to the Pool to be later reused by get calls. +// Put returns an allocated big int to the Pool to be later reused by get calls. // Note, the values as saved as is; neither put nor get zeroes the ints out! func (p *IntPool) Put(is ...*big.Int) { if len(p.Pool.Data) > PoolLimit { @@ -69,7 +71,7 @@ func (p *IntPool) Put(is ...*big.Int) { } } -// The IntPool Pool's default capacity +// PoolDefaultCap is the IntPool Pool's default capacity const PoolDefaultCap = 25 // IntPoolPool manages a Pool of IntPools. @@ -78,11 +80,12 @@ type IntPoolPool struct { lock sync.Mutex } +// PoolOfIntPools is an instance of IntPoolPool. var PoolOfIntPools = &IntPoolPool{ Pools: make([]*IntPool, 0, PoolDefaultCap), } -// get is looking for an available Pool to return. +// Get is looking for an available Pool to return. func (ipp *IntPoolPool) Get() *IntPool { ipp.lock.Lock() defer ipp.lock.Unlock() @@ -92,10 +95,10 @@ func (ipp *IntPoolPool) Get() *IntPool { ipp.Pools = ipp.Pools[:len(ipp.Pools)-1] return ip } - return newIntPool() + return NewIntPool() } -// put a Pool that has been allocated with get. +// Put a Pool that has been allocated with get. func (ipp *IntPoolPool) Put(ip *IntPool) { ipp.lock.Lock() defer ipp.lock.Unlock() diff --git a/core/vm/sqlvm/sqlvm.go b/core/vm/sqlvm/sqlvm.go index fe2eee42b..26aeeab0b 100644 --- a/core/vm/sqlvm/sqlvm.go +++ b/core/vm/sqlvm/sqlvm.go @@ -8,60 +8,65 @@ import ( "github.com/dexon-foundation/dexon/params" ) +// SQLVM implements the required VM interface. type SQLVM struct { // Context provides auxiliary blockchain related information - vm.Context + *vm.Context // StateDB gives access to the underlying state StateDB vm.StateDB - // Depth is the current call stack - depth int - // chainConfig contains information about the current chain - chainConfig *params.ChainConfig - // chain rules contains the chain rules for the current epoch - chainRules params.Rules // abort is used to abort the SQLVM calling operations // NOTE: must be set atomically abort int32 - // callGasTemp holds the gas available for the current call. This is needed because the - // available gas is calculated in gasCall* according to the 63/64 rule and later - // applied in opCall*. - callGasTemp uint64 } func init() { - vm.Register(vm.SQLVM, &SQLVM{}) + vm.Register(vm.SQLVM, NewSQLVM) } +// NewSQLVM is the SQLVM constructor. +func NewSQLVM(context *vm.Context, stateDB vm.StateDB, chainConfig *params.ChainConfig, vmConfig interface{}) vm.VM { + return &SQLVM{Context: context, StateDB: stateDB} +} + +// Create creates SQL contract. func (sqlvm *SQLVM) Create(caller vm.ContractRef, code []byte, gas uint64, value *big.Int, - in vm.Interpreter) ([]byte, common.Address, uint64, error) { + pack *vm.ExecPack) ([]byte, common.Address, uint64, error) { // todo (jm) need to implemnt return nil, common.Address{}, gas, nil } +// Create2 mock interface. func (sqlvm *SQLVM) Create2(caller vm.ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int, - in vm.Interpreter) ([]byte, common.Address, uint64, error) { + pack *vm.ExecPack) ([]byte, common.Address, uint64, error) { // todo (jm) need to implemnt return nil, common.Address{}, gas, nil } + +// Call is the entry to call SQLVM contract. func (sqlvm *SQLVM) Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, - in vm.Interpreter) ([]byte, uint64, error) { + pack *vm.ExecPack) ([]byte, uint64, error) { // todo (jm) need to implemnt return nil, gas, nil } + +// CallCode mock interface. func (sqlvm *SQLVM) CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, - value *big.Int, in vm.Interpreter) ([]byte, uint64, error) { + value *big.Int, pack *vm.ExecPack) ([]byte, uint64, error) { // todo (jm) need to implemnt return nil, gas, nil } +// DelegateCall mock interface. func (sqlvm *SQLVM) DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, - in vm.Interpreter) ([]byte, uint64, error) { + pack *vm.ExecPack) ([]byte, uint64, error) { // todo (jm) need to implemnt return nil, gas, nil } + +// StaticCall is the entry for read-only call on SQL contract. func (sqlvm *SQLVM) StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, - in vm.Interpreter) ([]byte, uint64, error) { + pack *vm.ExecPack) ([]byte, uint64, error) { // todo (jm) need to implemnt return nil, gas, nil } diff --git a/core/vm/stateDB.go b/core/vm/stateDB.go index 753b04247..7d8aed69b 100644 --- a/core/vm/stateDB.go +++ b/core/vm/stateDB.go @@ -16,7 +16,7 @@ type ( // GetHashFunc returns the nth block hash in the blockchain // and is used by the BLOCKHASH EVM op code. GetHashFunc func(uint64) common.Hash - // StateAtFunc returns the statedb given a root hash. + // StateAtNumberFunc returns the statedb given a root hash. StateAtNumberFunc func(uint64) (*state.StateDB, error) // GetRoundHeightFunc returns the round height. GetRoundHeightFunc func(uint64) (uint64, bool) @@ -50,7 +50,22 @@ type Context struct { Difficulty *big.Int // Provides information for DIFFICULTY Round *big.Int // Current round number. - RandCallIndex uint64 // Number of times opRand is called + // NoRecursion disabled Interpreter call, callcode, + // delegate call and create. + NoRecursion bool + // Depth is the current call stack + Depth int + // Whether to throw on stateful modifications + ReadOnly bool + // Number of times opRand is called + RandCallIndex uint64 + IntPool *IntPool + // CallGasTemp holds the gas available for the current call. This is needed because the + // available gas is calculated in gasCall* according to the 63/64 rule and later + // applied in opCall*. + CallGasTemp uint64 + + ExecPack *ExecPack } // StateDB is an EVM database for full state querying. diff --git a/core/vm/vm.go b/core/vm/vm.go index 99ab2ed90..780320d2b 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -4,93 +4,131 @@ import ( "math/big" "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/params" ) const ( - EVM = byte(iota) + // EVM enum + EVM = uint8(iota) + + // SQLVM enum SQLVM ) var ( + // MULTIVM flag MULTIVM = true ) +// NUMS represents the number of supported VM type. +const NUMS = 2 + +// VM Create and Call interface. type VM interface { Create(ContractRef, []byte, uint64, *big.Int, - Interpreter) ([]byte, common.Address, uint64, error) + *ExecPack) ([]byte, common.Address, uint64, error) Create2(ContractRef, []byte, uint64, *big.Int, *big.Int, - Interpreter) ([]byte, common.Address, uint64, error) + *ExecPack) ([]byte, common.Address, uint64, error) Call(ContractRef, common.Address, []byte, uint64, *big.Int, - Interpreter) ([]byte, uint64, error) + *ExecPack) ([]byte, uint64, error) CallCode(ContractRef, common.Address, []byte, uint64, - *big.Int, Interpreter) ([]byte, uint64, error) + *big.Int, *ExecPack) ([]byte, uint64, error) DelegateCall(ContractRef, common.Address, []byte, uint64, - Interpreter) ([]byte, uint64, error) + *ExecPack) ([]byte, uint64, error) StaticCall(ContractRef, common.Address, []byte, uint64, - Interpreter) ([]byte, uint64, error) + *ExecPack) ([]byte, uint64, error) } -type Interpreter interface { - StateDB() StateDB +type createFunc func(*Context, StateDB, *params.ChainConfig, interface{}) VM + +// ExecPack contains runtime context, stateDB, chain config, VM list and VM configs. +type ExecPack struct { + Context *Context + StateDB StateDB + ChainConfig *params.ChainConfig + VMList [NUMS]VM + VMConfig [NUMS]interface{} } -var vmList map[byte]VM +var createFuncs [NUMS]createFunc -func init() { - vmList = make(map[byte]VM) +// Register registers VM create function. +func Register(idx uint8, c createFunc) { + createFuncs[idx] = c } -func Register(vmType byte, vm VM) { - vmList[vmType] = vm + +// NewExecPack creates a ExecPack instance, and create all VM instance. +func NewExecPack(context *Context, stateDB StateDB, chainConfig *params.ChainConfig, vmConfigs [NUMS]interface{}) ExecPack { + p := ExecPack{ + Context: context, + StateDB: stateDB, + ChainConfig: chainConfig, + VMConfig: vmConfigs, + } + context.ExecPack = &p + for i := 0; i < NUMS; i++ { + if createFuncs[i] != nil { + p.VMList[i] = createFuncs[i](context, stateDB, chainConfig, vmConfigs[i]) + } + } + return p } + +// Create is the entry for multiple VMs' Create. func Create(caller ContractRef, code []byte, gas uint64, value *big.Int, - interpreter Interpreter) (ret []byte, contractAddr common.Address, + p *ExecPack) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - name, code := getVMAndCode(code) - return vmList[name].Create(caller, code, gas, value, interpreter) + v, code := getVMAndCode(code) + return p.VMList[v].Create(caller, code, gas, value, p) } +// Create2 is the entry for multiple VMs' Create2. func Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, - salt *big.Int, interpreter Interpreter) (ret []byte, + salt *big.Int, p *ExecPack) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - name, code := getVMAndCode(code) - return vmList[name].Create2(caller, code, gas, endowment, salt, interpreter) + v, code := getVMAndCode(code) + return p.VMList[v].Create2(caller, code, gas, endowment, salt, p) } +// Call is the entry for multiple VMs' Call. func Call(caller ContractRef, addr common.Address, input []byte, gas uint64, - value *big.Int, interpreter Interpreter) (ret []byte, leftOverGas uint64, err error) { + value *big.Int, p *ExecPack) (ret []byte, leftOverGas uint64, err error) { - code := interpreter.StateDB().GetCode(addr) - name, _ := getVMAndCode(code) - return vmList[name].Call(caller, addr, input, gas, value, interpreter) + code := p.StateDB.GetCode(addr) + v, _ := getVMAndCode(code) + return p.VMList[v].Call(caller, addr, input, gas, value, p) } +// CallCode is the entry for multiple VMs' CallCode. func CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, - value *big.Int, interpreter Interpreter) (ret []byte, leftOverGas uint64, err error) { + value *big.Int, p *ExecPack) (ret []byte, leftOverGas uint64, err error) { - code := interpreter.StateDB().GetCode(addr) - name, _ := getVMAndCode(code) - return vmList[name].CallCode(caller, addr, input, gas, value, interpreter) + code := p.StateDB.GetCode(addr) + v, _ := getVMAndCode(code) + return p.VMList[v].CallCode(caller, addr, input, gas, value, p) } +// DelegateCall is the entry for multiple VMs' DelegateCall. func DelegateCall(caller ContractRef, addr common.Address, input []byte, - gas uint64, interpreter Interpreter) (ret []byte, leftOverGas uint64, err error) { + gas uint64, p *ExecPack) (ret []byte, leftOverGas uint64, err error) { - code := interpreter.StateDB().GetCode(addr) - name, _ := getVMAndCode(code) - return vmList[name].DelegateCall(caller, addr, input, gas, interpreter) + code := p.StateDB.GetCode(addr) + v, _ := getVMAndCode(code) + return p.VMList[v].DelegateCall(caller, addr, input, gas, p) } +// StaticCall is the entry for multiple VMs' StaticCall. func StaticCall(caller ContractRef, addr common.Address, input []byte, - gas uint64, interpreter Interpreter) (ret []byte, leftOverGas uint64, err error) { + gas uint64, p *ExecPack) (ret []byte, leftOverGas uint64, err error) { - code := interpreter.StateDB().GetCode(addr) - name, _ := getVMAndCode(code) - return vmList[name].StaticCall(caller, addr, input, gas, interpreter) + code := p.StateDB.GetCode(addr) + v, _ := getVMAndCode(code) + return p.VMList[v].StaticCall(caller, addr, input, gas, p) } -func getVMAndCode(code []byte) (byte, []byte) { +func getVMAndCode(code []byte) (uint8, []byte) { if MULTIVM && len(code) > 0 { switch code[0] { case EVM, SQLVM: |