aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
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: