aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJhih-Ming Huang <jm.huang@cobinhood.com>2019-03-27 18:49:38 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-05-06 10:50:26 +0800
commite715414cae9b4654b4784dfb924880a0787d1d55 (patch)
treea0772b2a0ef3be4ac03fc608a21ee0b7ccbd167a /core
parent996310cbd484b5ff1ea76068578314d71973770f (diff)
downloaddexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.gz
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.bz2
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.lz
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.xz
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.zst
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.zip
core: vm: refactor vm config and context
To support multiple VMs, there must be a shared execution environment for each VM, so this pull request moved some shared component to vm.Context and implemented the vm.ExecPack to hold the list of VM, list of VM configures, context and some shared resources. The adjustment includes: * Move NoRecursion, Depth, ReadOnly, RandCallIndex, IntPool and CallGasTemp to Context. * Adjust VM enumeration from byte to uint8, and the VMList from map to array. * Register VM constructor in each VM package's init function. * Initialize all VM instance in NewExecPack. * Remove EVMImplement, and modify EVM, such that EVM can do the same functions with EVMImplement.
Diffstat (limited to 'core')
-rw-r--r--core/bench_test.go11
-rw-r--r--core/block_validator_test.go19
-rw-r--r--core/blockchain.go15
-rw-r--r--core/blockchain_test.go89
-rw-r--r--core/chain_makers.go5
-rw-r--r--core/chain_makers_test.go7
-rw-r--r--core/dao_test.go27
-rw-r--r--core/dexon_chain_makers.go5
-rw-r--r--core/evm.go7
-rw-r--r--core/genesis_test.go7
-rw-r--r--core/state_processor.go14
-rw-r--r--core/state_transition.go37
-rw-r--r--core/types.go4
-rw-r--r--core/vm/evm/evm.go114
-rw-r--r--core/vm/evm/evm_test.go13
-rw-r--r--core/vm/evm/gas_table.go16
-rw-r--r--core/vm/evm/instructions.go196
-rw-r--r--core/vm/evm/instructions_test.go102
-rw-r--r--core/vm/evm/interpreter.go51
-rw-r--r--core/vm/evm/logger_test.go7
-rw-r--r--core/vm/evm/oracle_contracts_test.go9
-rw-r--r--core/vm/evm/runtime/env.go10
-rw-r--r--core/vm/evm/runtime/runtime.go20
-rw-r--r--core/vm/evm/runtime/runtime_test.go50
-rw-r--r--core/vm/intpool.go19
-rw-r--r--core/vm/sqlvm/sqlvm.go41
-rw-r--r--core/vm/stateDB.go19
-rw-r--r--core/vm/vm.go112
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: