Merge pull request #3144 from ethereum/release/1.4

Release/1.4.18 to master
This commit is contained in:
Felix Lange
2016-10-15 13:00:43 +02:00
committed by GitHub
63 changed files with 77642 additions and 230 deletions

View File

@ -1 +1 @@
1.4.17 1.4.18

View File

@ -74,7 +74,7 @@ func runTestWithReader(test string, r io.Reader) error {
var err error var err error
switch strings.ToLower(test) { switch strings.ToLower(test) {
case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests": case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, r, skipTests) err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, params.MainNetHomesteadGasRepriceBlock, r, skipTests)
case "st", "state", "statetest", "statetests": case "st", "state", "statetest", "statetests":
rs := tests.RuleSet{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true} rs := tests.RuleSet{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true}
err = tests.RunStateTestWithReader(rs, r, skipTests) err = tests.RunStateTestWithReader(rs, r, skipTests)

View File

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )
@ -222,6 +223,9 @@ func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int, cfg
type ruleSet struct{} type ruleSet struct{}
func (ruleSet) IsHomestead(*big.Int) bool { return true } func (ruleSet) IsHomestead(*big.Int) bool { return true }
func (ruleSet) GasTable(*big.Int) params.GasTable {
return params.GasTableHomesteadGasRepriceFork
}
func (self *VMEnv) RuleSet() vm.RuleSet { return ruleSet{} } func (self *VMEnv) RuleSet() vm.RuleSet { return ruleSet{} }
func (self *VMEnv) Vm() vm.Vm { return self.evm } func (self *VMEnv) Vm() vm.Vm { return self.evm }

View File

@ -50,7 +50,7 @@ const (
clientIdentifier = "Geth" // Client identifier to advertise over the network clientIdentifier = "Geth" // Client identifier to advertise over the network
versionMajor = 1 // Major version component of the current release versionMajor = 1 // Major version component of the current release
versionMinor = 4 // Minor version component of the current release versionMinor = 4 // Minor version component of the current release
versionPatch = 17 // Patch version component of the current release versionPatch = 18 // Patch version component of the current release
versionMeta = "stable" // Version metadata to append to the version string versionMeta = "stable" // Version metadata to append to the version string
versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle

View File

@ -809,6 +809,13 @@ func MustMakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainC
} }
config.DAOForkSupport = true config.DAOForkSupport = true
} }
if config.HomesteadGasRepriceBlock == nil {
if ctx.GlobalBool(TestNetFlag.Name) {
config.HomesteadGasRepriceBlock = params.TestNetHomesteadGasRepriceBlock
} else {
config.HomesteadGasRepriceBlock = params.MainNetHomesteadGasRepriceBlock
}
}
// Force override any existing configs if explicitly requested // Force override any existing configs if explicitly requested
switch { switch {
case ctx.GlobalBool(SupportDAOFork.Name): case ctx.GlobalBool(SupportDAOFork.Name):

View File

@ -269,7 +269,7 @@ func (self *BlockChain) FastSyncCommitHead(hash common.Hash) error {
if block == nil { if block == nil {
return fmt.Errorf("non existent block [%x…]", hash[:4]) return fmt.Errorf("non existent block [%x…]", hash[:4])
} }
if _, err := trie.NewSecure(block.Root(), self.chainDb); err != nil { if _, err := trie.NewSecure(block.Root(), self.chainDb, 0); err != nil {
return err return err
} }
// If all checks out, manually set the head block // If all checks out, manually set the head block
@ -824,19 +824,16 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// faster than direct delivery and requires much less mutex // faster than direct delivery and requires much less mutex
// acquiring. // acquiring.
var ( var (
stats struct{ queued, processed, ignored int } stats = insertStats{startTime: time.Now()}
events = make([]interface{}, 0, len(chain)) events = make([]interface{}, 0, len(chain))
coalescedLogs vm.Logs coalescedLogs vm.Logs
tstart = time.Now() nonceChecked = make([]bool, len(chain))
nonceChecked = make([]bool, len(chain))
) )
// Start the parallel nonce verifier. // Start the parallel nonce verifier.
nonceAbort, nonceResults := verifyNoncesFromBlocks(self.pow, chain) nonceAbort, nonceResults := verifyNoncesFromBlocks(self.pow, chain)
defer close(nonceAbort) defer close(nonceAbort)
txcount := 0
for i, block := range chain { for i, block := range chain {
if atomic.LoadInt32(&self.procInterrupt) == 1 { if atomic.LoadInt32(&self.procInterrupt) == 1 {
glog.V(logger.Debug).Infoln("Premature abort during block chain processing") glog.V(logger.Debug).Infoln("Premature abort during block chain processing")
@ -931,7 +928,6 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
return i, err return i, err
} }
txcount += len(block.Transactions())
// write the block to the chain and get the status // write the block to the chain and get the status
status, err := self.WriteBlock(block) status, err := self.WriteBlock(block)
if err != nil { if err != nil {
@ -966,19 +962,54 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
case SplitStatTy: case SplitStatTy:
events = append(events, ChainSplitEvent{block, logs}) events = append(events, ChainSplitEvent{block, logs})
} }
stats.processed++ stats.processed++
if glog.V(logger.Info) {
stats.report(chain, i)
}
} }
if (stats.queued > 0 || stats.processed > 0 || stats.ignored > 0) && bool(glog.V(logger.Info)) {
tend := time.Since(tstart)
start, end := chain[0], chain[len(chain)-1]
glog.Infof("imported %d block(s) (%d queued %d ignored) including %d txs in %v. #%v [%x / %x]\n", stats.processed, stats.queued, stats.ignored, txcount, tend, end.Number(), start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
}
go self.postChainEvents(events, coalescedLogs) go self.postChainEvents(events, coalescedLogs)
return 0, nil return 0, nil
} }
// insertStats tracks and reports on block insertion.
type insertStats struct {
queued, processed, ignored int
lastIndex int
startTime time.Time
}
const (
statsReportLimit = 1024
statsReportTimeLimit = 8 * time.Second
)
// report prints statistics if some number of blocks have been processed
// or more than a few seconds have passed since the last message.
func (st *insertStats) report(chain []*types.Block, index int) {
limit := statsReportLimit
if index == len(chain)-1 {
limit = 0 // Always print a message for the last block.
}
now := time.Now()
duration := now.Sub(st.startTime)
if duration > statsReportTimeLimit || st.queued > limit || st.processed > limit || st.ignored > limit {
start, end := chain[st.lastIndex], chain[index]
txcount := countTransactions(chain[st.lastIndex : index+1])
glog.Infof("imported %d block(s) (%d queued %d ignored) including %d txs in %v. #%v [%x / %x]\n", st.processed, st.queued, st.ignored, txcount, duration, end.Number(), start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
*st = insertStats{startTime: now, lastIndex: index}
}
}
func countTransactions(chain []*types.Block) (c int) {
for _, b := range chain {
c += len(b.Transactions())
}
return c
}
// reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them // reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them
// to be part of the new canonical chain and accumulates potential missing transactions and post an // to be part of the new canonical chain and accumulates potential missing transactions and post an
// event about them // event about them

View File

@ -21,6 +21,7 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
) )
var ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error var ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
@ -35,6 +36,8 @@ type ChainConfig struct {
DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork) DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork)
DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
HomesteadGasRepriceBlock *big.Int `json:"homesteadGasRepriceBlock"` // Homestead gas reprice switch block (nil = no fork)
VmConfig vm.Config `json:"-"` VmConfig vm.Config `json:"-"`
} }
@ -45,3 +48,14 @@ func (c *ChainConfig) IsHomestead(num *big.Int) bool {
} }
return num.Cmp(c.HomesteadBlock) >= 0 return num.Cmp(c.HomesteadBlock) >= 0
} }
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
//
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
func (c *ChainConfig) GasTable(num *big.Int) params.GasTable {
if c.HomesteadGasRepriceBlock == nil || num == nil || num.Cmp(c.HomesteadGasRepriceBlock) < 0 {
return params.GasTableHomestead
}
return params.GasTableHomesteadGasRepriceFork
}

View File

@ -137,9 +137,9 @@ func (self *StateObject) markSuicided() {
func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie { func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie {
if c.trie == nil { if c.trie == nil {
var err error var err error
c.trie, err = trie.NewSecure(c.data.Root, db) c.trie, err = trie.NewSecure(c.data.Root, db, 0)
if err != nil { if err != nil {
c.trie, _ = trie.NewSecure(common.Hash{}, db) c.trie, _ = trie.NewSecure(common.Hash{}, db, 0)
c.setError(fmt.Errorf("can't create storage trie: %v", err)) c.setError(fmt.Errorf("can't create storage trie: %v", err))
} }
} }

View File

@ -41,7 +41,10 @@ var StartingNonce uint64
const ( const (
// Number of past tries to keep. The arbitrarily chosen value here // Number of past tries to keep. The arbitrarily chosen value here
// is max uncle depth + 1. // is max uncle depth + 1.
maxTrieCacheLength = 8 maxPastTries = 8
// Trie cache generation limit.
maxTrieCacheGen = 100
// Number of codehash->size associations to keep. // Number of codehash->size associations to keep.
codeSizeCacheSize = 100000 codeSizeCacheSize = 100000
@ -86,7 +89,7 @@ type StateDB struct {
// Create a new state from a given trie // Create a new state from a given trie
func New(root common.Hash, db ethdb.Database) (*StateDB, error) { func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
tr, err := trie.NewSecure(root, db) tr, err := trie.NewSecure(root, db, maxTrieCacheGen)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -155,14 +158,14 @@ func (self *StateDB) openTrie(root common.Hash) (*trie.SecureTrie, error) {
return &tr, nil return &tr, nil
} }
} }
return trie.NewSecure(root, self.db) return trie.NewSecure(root, self.db, maxTrieCacheGen)
} }
func (self *StateDB) pushTrie(t *trie.SecureTrie) { func (self *StateDB) pushTrie(t *trie.SecureTrie) {
self.lock.Lock() self.lock.Lock()
defer self.lock.Unlock() defer self.lock.Unlock()
if len(self.pastTries) >= maxTrieCacheLength { if len(self.pastTries) >= maxPastTries {
copy(self.pastTries, self.pastTries[1:]) copy(self.pastTries, self.pastTries[1:])
self.pastTries[len(self.pastTries)-1] = t self.pastTries[len(self.pastTries)-1] = t
} else { } else {

View File

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
) )
var ( var (
@ -46,10 +47,12 @@ var (
) )
var ( var (
maxQueuedPerAccount = uint64(64) // Max limit of queued transactions per address minPendingPerAccount = uint64(16) // Min number of guaranteed transaction slots per address
maxQueuedInTotal = uint64(8192) // Max limit of queued transactions from all accounts maxPendingTotal = uint64(4096) // Max limit of pending transactions from all accounts (soft)
maxQueuedLifetime = 3 * time.Hour // Max amount of time transactions from idle accounts are queued maxQueuedPerAccount = uint64(64) // Max limit of queued transactions per address
evictionInterval = time.Minute // Time interval to check for evictable transactions maxQueuedInTotal = uint64(1024) // Max limit of queued transactions from all accounts
maxQueuedLifetime = 3 * time.Hour // Max amount of time transactions from idle accounts are queued
evictionInterval = time.Minute // Time interval to check for evictable transactions
) )
type stateFn func() (*state.StateDB, error) type stateFn func() (*state.StateDB, error)
@ -481,7 +484,6 @@ func (pool *TxPool) promoteExecutables() {
} }
// Iterate over all accounts and promote any executable transactions // Iterate over all accounts and promote any executable transactions
queued := uint64(0) queued := uint64(0)
for addr, list := range pool.queue { for addr, list := range pool.queue {
// Drop all transactions that are deemed too old (low nonce) // Drop all transactions that are deemed too old (low nonce)
for _, tx := range list.Forward(state.GetNonce(addr)) { for _, tx := range list.Forward(state.GetNonce(addr)) {
@ -519,6 +521,59 @@ func (pool *TxPool) promoteExecutables() {
delete(pool.queue, addr) delete(pool.queue, addr)
} }
} }
// If the pending limit is overflown, start equalizing allowances
pending := uint64(0)
for _, list := range pool.pending {
pending += uint64(list.Len())
}
if pending > maxPendingTotal {
// Assemble a spam order to penalize large transactors first
spammers := prque.New()
for addr, list := range pool.pending {
// Only evict transactions from high rollers
if uint64(list.Len()) > minPendingPerAccount {
// Skip local accounts as pools should maintain backlogs for themselves
for _, tx := range list.txs.items {
if !pool.localTx.contains(tx.Hash()) {
spammers.Push(addr, float32(list.Len()))
}
break // Checking on transaction for locality is enough
}
}
}
// Gradually drop transactions from offenders
offenders := []common.Address{}
for pending > maxPendingTotal && !spammers.Empty() {
// Retrieve the next offender if not local address
offender, _ := spammers.Pop()
offenders = append(offenders, offender.(common.Address))
// Equalize balances until all the same or below threshold
if len(offenders) > 1 {
// Calculate the equalization threshold for all current offenders
threshold := pool.pending[offender.(common.Address)].Len()
// Iteratively reduce all offenders until below limit or threshold reached
for pending > maxPendingTotal && pool.pending[offenders[len(offenders)-2]].Len() > threshold {
for i := 0; i < len(offenders)-1; i++ {
list := pool.pending[offenders[i]]
list.Cap(list.Len() - 1)
pending--
}
}
}
}
// If still above threshold, reduce to limit or min allowance
if pending > maxPendingTotal && len(offenders) > 0 {
for pending > maxPendingTotal && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > minPendingPerAccount {
for _, addr := range offenders {
list := pool.pending[addr]
list.Cap(list.Len() - 1)
pending--
}
}
}
}
// If we've queued more transactions than the hard limit, drop oldest ones // If we've queued more transactions than the hard limit, drop oldest ones
if queued > maxQueuedInTotal { if queued > maxQueuedInTotal {
// Sort all accounts with queued transactions by heartbeat // Sort all accounts with queued transactions by heartbeat

View File

@ -618,6 +618,96 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
} }
} }
// Tests that if the transaction count belonging to multiple accounts go above
// some hard threshold, the higher transactions are dropped to prevent DOS
// attacks.
func TestTransactionPendingGlobalLimiting(t *testing.T) {
// Reduce the queue limits to shorten test time
defer func(old uint64) { maxPendingTotal = old }(maxPendingTotal)
maxPendingTotal = minPendingPerAccount * 10
// Create the pool to test the limit enforcement with
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState()
// Create a number of test accounts and fund them
state, _ := pool.currentState()
keys := make([]*ecdsa.PrivateKey, 5)
for i := 0; i < len(keys); i++ {
keys[i], _ = crypto.GenerateKey()
state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
}
// Generate and queue a batch of transactions
nonces := make(map[common.Address]uint64)
txs := types.Transactions{}
for _, key := range keys {
addr := crypto.PubkeyToAddress(key.PublicKey)
for j := 0; j < int(maxPendingTotal)/len(keys)*2; j++ {
txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key))
nonces[addr]++
}
}
// Import the batch and verify that limits have been enforced
pool.AddBatch(txs)
pending := 0
for _, list := range pool.pending {
pending += list.Len()
}
if pending > int(maxPendingTotal) {
t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, maxPendingTotal)
}
}
// Tests that if the transaction count belonging to multiple accounts go above
// some hard threshold, if they are under the minimum guaranteed slot count then
// the transactions are still kept.
func TestTransactionPendingMinimumAllowance(t *testing.T) {
// Reduce the queue limits to shorten test time
defer func(old uint64) { maxPendingTotal = old }(maxPendingTotal)
maxPendingTotal = 0
// Create the pool to test the limit enforcement with
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db)
pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState()
// Create a number of test accounts and fund them
state, _ := pool.currentState()
keys := make([]*ecdsa.PrivateKey, 5)
for i := 0; i < len(keys); i++ {
keys[i], _ = crypto.GenerateKey()
state.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
}
// Generate and queue a batch of transactions
nonces := make(map[common.Address]uint64)
txs := types.Transactions{}
for _, key := range keys {
addr := crypto.PubkeyToAddress(key.PublicKey)
for j := 0; j < int(minPendingPerAccount)*2; j++ {
txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key))
nonces[addr]++
}
}
// Import the batch and verify that limits have been enforced
pool.AddBatch(txs)
for addr, list := range pool.pending {
if list.Len() != int(minPendingPerAccount) {
t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), minPendingPerAccount)
}
}
}
// Benchmarks the speed of validating the contents of the pending queue of the // Benchmarks the speed of validating the contents of the pending queue of the
// transaction pool. // transaction pool.
func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) }

View File

@ -20,12 +20,16 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
) )
// RuleSet is an interface that defines the current rule set during the // RuleSet is an interface that defines the current rule set during the
// execution of the EVM instructions (e.g. whether it's homestead) // execution of the EVM instructions (e.g. whether it's homestead)
type RuleSet interface { type RuleSet interface {
IsHomestead(*big.Int) bool IsHomestead(*big.Int) bool
// GasTable returns the gas prices for this phase, which is based on
// block number passed in.
GasTable(*big.Int) params.GasTable
} }
// Environment is an EVM requirement and helper which allows access to outside // Environment is an EVM requirement and helper which allows access to outside

View File

@ -35,8 +35,27 @@ var (
GasStop = big.NewInt(0) GasStop = big.NewInt(0)
GasContractByte = big.NewInt(200) GasContractByte = big.NewInt(200)
n64 = big.NewInt(64)
) )
// calcGas returns the actual gas cost of the call.
//
// The cost of gas was changed during the homestead price change HF. To allow for EIP150
// to be implemented. The returned gas is gas - base * 63 / 64.
func callGas(gasTable params.GasTable, availableGas, base, callCost *big.Int) *big.Int {
if gasTable.CreateBySuicide != nil {
availableGas = new(big.Int).Sub(availableGas, base)
g := new(big.Int).Div(availableGas, n64)
g.Sub(availableGas, g)
if g.Cmp(callCost) < 0 {
return g
}
}
return callCost
}
// baseCheck checks for any stack error underflows // baseCheck checks for any stack error underflows
func baseCheck(op OpCode, stack *stack, gas *big.Int) error { func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit // PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
@ -127,18 +146,19 @@ var _baseCheck = map[OpCode]req{
MSIZE: {0, GasQuickStep, 1}, MSIZE: {0, GasQuickStep, 1},
GAS: {0, GasQuickStep, 1}, GAS: {0, GasQuickStep, 1},
BLOCKHASH: {1, GasExtStep, 1}, BLOCKHASH: {1, GasExtStep, 1},
BALANCE: {1, GasExtStep, 1}, BALANCE: {1, Zero, 1},
EXTCODESIZE: {1, GasExtStep, 1}, EXTCODESIZE: {1, Zero, 1},
EXTCODECOPY: {4, GasExtStep, 0}, EXTCODECOPY: {4, Zero, 0},
SLOAD: {1, params.SloadGas, 1}, SLOAD: {1, params.SloadGas, 1},
SSTORE: {2, Zero, 0}, SSTORE: {2, Zero, 0},
SHA3: {2, params.Sha3Gas, 1}, SHA3: {2, params.Sha3Gas, 1},
CREATE: {3, params.CreateGas, 1}, CREATE: {3, params.CreateGas, 1},
CALL: {7, params.CallGas, 1}, // Zero is calculated in the gasSwitch
CALLCODE: {7, params.CallGas, 1}, CALL: {7, Zero, 1},
DELEGATECALL: {6, params.CallGas, 1}, CALLCODE: {7, Zero, 1},
JUMPDEST: {0, params.JumpdestGas, 0}, DELEGATECALL: {6, Zero, 1},
SUICIDE: {1, Zero, 0}, SUICIDE: {1, Zero, 0},
JUMPDEST: {0, params.JumpdestGas, 0},
RETURN: {2, Zero, 0}, RETURN: {2, Zero, 0},
PUSH1: {0, GasFastestStep, 1}, PUSH1: {0, GasFastestStep, 1},
DUP1: {0, Zero, 1}, DUP1: {0, Zero, 1},

View File

@ -514,7 +514,12 @@ func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract
input = memory.Get(offset.Int64(), size.Int64()) input = memory.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(contract.Gas) gas = new(big.Int).Set(contract.Gas)
) )
contract.UseGas(contract.Gas) if env.RuleSet().GasTable(env.BlockNumber()).CreateBySuicide != nil {
gas.Div(gas, n64)
gas = gas.Sub(contract.Gas, gas)
}
contract.UseGas(gas)
_, addr, suberr := env.Create(contract, input, gas, contract.Price, value) _, addr, suberr := env.Create(contract, input, gas, contract.Price, value)
// Push item on the stack based on the returned error. If the ruleset is // Push item on the stack based on the returned error. If the ruleset is
// homestead we must check for CodeStoreOutOfGasError (homestead only // homestead we must check for CodeStoreOutOfGasError (homestead only

View File

@ -25,12 +25,16 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
) )
// The default, always homestead, rule set for the vm env // The default, always homestead, rule set for the vm env
type ruleSet struct{} type ruleSet struct{}
func (ruleSet) IsHomestead(*big.Int) bool { return true } func (ruleSet) IsHomestead(*big.Int) bool { return true }
func (ruleSet) GasTable(*big.Int) params.GasTable {
return params.GasTableHomesteadGasRepriceFork
}
// Config is a basic type specifying certain configuration flags for running // Config is a basic type specifying certain configuration flags for running
// the EVM. // the EVM.

View File

@ -16,10 +16,17 @@
package vm package vm
import "math/big" import (
"math/big"
"github.com/ethereum/go-ethereum/params"
)
type ruleSet struct { type ruleSet struct {
hs *big.Int hs *big.Int
} }
func (r ruleSet) IsHomestead(n *big.Int) bool { return n.Cmp(r.hs) >= 0 } func (r ruleSet) IsHomestead(n *big.Int) bool { return n.Cmp(r.hs) >= 0 }
func (r ruleSet) GasTable(*big.Int) params.GasTable {
return params.GasTableHomestead
}

View File

@ -44,8 +44,8 @@ type EVM struct {
env Environment env Environment
jumpTable vmJumpTable jumpTable vmJumpTable
cfg Config cfg Config
logger *Logger
logger *Logger gasTable params.GasTable
} }
// New returns a new instance of the EVM. // New returns a new instance of the EVM.
@ -60,6 +60,7 @@ func New(env Environment, cfg Config) *EVM {
jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()), jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()),
cfg: cfg, cfg: cfg,
logger: logger, logger: logger,
gasTable: env.RuleSet().GasTable(env.BlockNumber()),
} }
} }
@ -177,7 +178,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
// Get the memory location of pc // Get the memory location of pc
op = contract.GetOp(pc) op = contract.GetOp(pc)
// calculate the new memory size and gas price for the current executing opcode // calculate the new memory size and gas price for the current executing opcode
newMemSize, cost, err = calculateGasAndSize(evm.env, contract, caller, op, statedb, mem, stack) newMemSize, cost, err = calculateGasAndSize(evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -242,7 +243,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for // calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
// the operation. This does not reduce gas or resizes the memory. // the operation. This does not reduce gas or resizes the memory.
func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *stack) (*big.Int, *big.Int, error) { func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
var ( var (
gas = new(big.Int) gas = new(big.Int)
newMemSize *big.Int = new(big.Int) newMemSize *big.Int = new(big.Int)
@ -254,6 +255,24 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
// stack Check, memory resize & gas phase // stack Check, memory resize & gas phase
switch op { switch op {
case SUICIDE:
// if suicide is not nil: homestead gas fork
if gasTable.CreateBySuicide != nil {
gas.Set(gasTable.Suicide)
if !env.Db().Exist(common.BigToAddress(stack.data[len(stack.data)-1])) {
gas.Add(gas, gasTable.CreateBySuicide)
}
}
if !statedb.HasSuicided(contract.Address()) {
statedb.AddRefund(params.SuicideRefundGas)
}
case EXTCODESIZE:
gas.Set(gasTable.ExtcodeSize)
case BALANCE:
gas.Set(gasTable.Balance)
case SLOAD:
gas.Set(gasTable.SLoad)
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2) n := int(op - SWAP1 + 2)
err := stack.require(n) err := stack.require(n)
@ -282,6 +301,8 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas)) gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
newMemSize = calcMemSize(mStart, mSize) newMemSize = calcMemSize(mStart, mSize)
quadMemGas(mem, newMemSize, gas)
case EXP: case EXP:
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas)) gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
case SSTORE: case SSTORE:
@ -310,67 +331,100 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
g = params.SstoreClearGas g = params.SstoreClearGas
} }
gas.Set(g) gas.Set(g)
case SUICIDE:
if !statedb.HasSuicided(contract.Address()) {
statedb.AddRefund(params.SuicideRefundGas)
}
case MLOAD: case MLOAD:
newMemSize = calcMemSize(stack.peek(), u256(32)) newMemSize = calcMemSize(stack.peek(), u256(32))
quadMemGas(mem, newMemSize, gas)
case MSTORE8: case MSTORE8:
newMemSize = calcMemSize(stack.peek(), u256(1)) newMemSize = calcMemSize(stack.peek(), u256(1))
quadMemGas(mem, newMemSize, gas)
case MSTORE: case MSTORE:
newMemSize = calcMemSize(stack.peek(), u256(32)) newMemSize = calcMemSize(stack.peek(), u256(32))
quadMemGas(mem, newMemSize, gas)
case RETURN: case RETURN:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
quadMemGas(mem, newMemSize, gas)
case SHA3: case SHA3:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
words := toWordSize(stack.data[stack.len()-2]) words := toWordSize(stack.data[stack.len()-2])
gas.Add(gas, words.Mul(words, params.Sha3WordGas)) gas.Add(gas, words.Mul(words, params.Sha3WordGas))
quadMemGas(mem, newMemSize, gas)
case CALLDATACOPY: case CALLDATACOPY:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
words := toWordSize(stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, params.CopyGas)) gas.Add(gas, words.Mul(words, params.CopyGas))
quadMemGas(mem, newMemSize, gas)
case CODECOPY: case CODECOPY:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
words := toWordSize(stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, params.CopyGas)) gas.Add(gas, words.Mul(words, params.CopyGas))
quadMemGas(mem, newMemSize, gas)
case EXTCODECOPY: case EXTCODECOPY:
gas.Set(gasTable.ExtcodeCopy)
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
words := toWordSize(stack.data[stack.len()-4]) words := toWordSize(stack.data[stack.len()-4])
gas.Add(gas, words.Mul(words, params.CopyGas)) gas.Add(gas, words.Mul(words, params.CopyGas))
quadMemGas(mem, newMemSize, gas)
case CREATE: case CREATE:
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
quadMemGas(mem, newMemSize, gas)
case CALL, CALLCODE: case CALL, CALLCODE:
gas.Add(gas, stack.data[stack.len()-1]) gas.Set(gasTable.Calls)
if op == CALL { if op == CALL {
if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) { if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) {
gas.Add(gas, params.CallNewAccountGas) gas.Add(gas, params.CallNewAccountGas)
} }
} }
if len(stack.data[stack.len()-3].Bytes()) > 0 { if len(stack.data[stack.len()-3].Bytes()) > 0 {
gas.Add(gas, params.CallValueTransferGas) gas.Add(gas, params.CallValueTransferGas)
} }
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5]) y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
newMemSize = common.BigMax(x, y) newMemSize = common.BigMax(x, y)
quadMemGas(mem, newMemSize, gas)
cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1])
// Replace the stack item with the new gas calculation. This means that
// either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is
// called. This information is otherwise lost due to the dependency on *current*
// available gas.
stack.data[stack.len()-1] = cg
gas.Add(gas, cg)
case DELEGATECALL: case DELEGATECALL:
gas.Add(gas, stack.data[stack.len()-1]) gas.Set(gasTable.Calls)
x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6]) x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6])
y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4]) y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4])
newMemSize = common.BigMax(x, y) newMemSize = common.BigMax(x, y)
quadMemGas(mem, newMemSize, gas)
cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1])
// Replace the stack item with the new gas calculation. This means that
// either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is
// called.
stack.data[stack.len()-1] = cg
gas.Add(gas, cg)
} }
quadMemGas(mem, newMemSize, gas)
return newMemSize, gas, nil return newMemSize, gas, nil
} }

View File

@ -286,7 +286,7 @@ func (dl *downloadTester) headFastBlock() *types.Block {
func (dl *downloadTester) commitHeadBlock(hash common.Hash) error { func (dl *downloadTester) commitHeadBlock(hash common.Hash) error {
// For now only check that the state trie is correct // For now only check that the state trie is correct
if block := dl.getBlock(hash); block != nil { if block := dl.getBlock(hash); block != nil {
_, err := trie.NewSecure(block.Root(), dl.stateDb) _, err := trie.NewSecure(block.Root(), dl.stateDb, 0)
return err return err
} }
return fmt.Errorf("non existent block: %x", hash[:4]) return fmt.Errorf("non existent block: %x", hash[:4])

View File

@ -288,7 +288,7 @@ func (pm *ProtocolManager) handle(p *peer) error {
} }
// Start a timer to disconnect if the peer doesn't reply in time // Start a timer to disconnect if the peer doesn't reply in time
p.forkDrop = time.AfterFunc(daoChallengeTimeout, func() { p.forkDrop = time.AfterFunc(daoChallengeTimeout, func() {
glog.V(logger.Warn).Infof("%v: timed out DAO fork-check, dropping", p) glog.V(logger.Debug).Infof("%v: timed out DAO fork-check, dropping", p)
pm.removePeer(p.id) pm.removePeer(p.id)
}) })
// Make sure it's cleaned up if the peer dies off // Make sure it's cleaned up if the peer dies off

View File

@ -102,6 +102,11 @@ func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
}, nil }, nil
} }
// Path returns the path to the database directory.
func (db *LDBDatabase) Path() string {
return db.fn
}
// Put puts the given key / value to the queue // Put puts the given key / value to the queue
func (self *LDBDatabase) Put(key []byte, value []byte) error { func (self *LDBDatabase) Put(key []byte, value []byte) error {
// Measure the database put latency, if requested // Measure the database put latency, if requested

View File

@ -52,6 +52,11 @@ var (
Usage: "pprof HTTP server listening port", Usage: "pprof HTTP server listening port",
Value: 6060, Value: 6060,
} }
pprofAddrFlag = cli.StringFlag{
Name: "pprofaddr",
Usage: "pprof HTTP server listening interface",
Value: "127.0.0.1",
}
memprofilerateFlag = cli.IntFlag{ memprofilerateFlag = cli.IntFlag{
Name: "memprofilerate", Name: "memprofilerate",
Usage: "Turn on memory profiling with the given rate", Usage: "Turn on memory profiling with the given rate",
@ -74,7 +79,7 @@ var (
// Flags holds all command-line flags required for debugging. // Flags holds all command-line flags required for debugging.
var Flags = []cli.Flag{ var Flags = []cli.Flag{
verbosityFlag, vmoduleFlag, backtraceAtFlag, verbosityFlag, vmoduleFlag, backtraceAtFlag,
pprofFlag, pprofPortFlag, pprofFlag, pprofAddrFlag, pprofPortFlag,
memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag, memprofilerateFlag, blockprofilerateFlag, cpuprofileFlag, traceFlag,
} }
@ -101,7 +106,7 @@ func Setup(ctx *cli.Context) error {
// pprof server // pprof server
if ctx.GlobalBool(pprofFlag.Name) { if ctx.GlobalBool(pprofFlag.Name) {
address := fmt.Sprintf("127.0.0.1:%d", ctx.GlobalInt(pprofPortFlag.Name)) address := fmt.Sprintf("%s:%d", ctx.GlobalString(pprofAddrFlag.Name), ctx.GlobalInt(pprofPortFlag.Name))
go func() { go func() {
glog.V(logger.Info).Infof("starting pprof server at http://%s/debug/pprof", address) glog.V(logger.Info).Infof("starting pprof server at http://%s/debug/pprof", address)
glog.Errorln(http.ListenAndServe(address, nil)) glog.Errorln(http.ListenAndServe(address, nil))

View File

@ -79,7 +79,7 @@ func (t *LightTrie) do(ctx context.Context, fallbackKey []byte, fn func() error)
func (t *LightTrie) Get(ctx context.Context, key []byte) (res []byte, err error) { func (t *LightTrie) Get(ctx context.Context, key []byte) (res []byte, err error) {
err = t.do(ctx, key, func() (err error) { err = t.do(ctx, key, func() (err error) {
if t.trie == nil { if t.trie == nil {
t.trie, err = trie.NewSecure(t.originalRoot, t.db) t.trie, err = trie.NewSecure(t.originalRoot, t.db, 0)
} }
if err == nil { if err == nil {
res, err = t.trie.TryGet(key) res, err = t.trie.TryGet(key)
@ -98,7 +98,7 @@ func (t *LightTrie) Get(ctx context.Context, key []byte) (res []byte, err error)
func (t *LightTrie) Update(ctx context.Context, key, value []byte) (err error) { func (t *LightTrie) Update(ctx context.Context, key, value []byte) (err error) {
err = t.do(ctx, key, func() (err error) { err = t.do(ctx, key, func() (err error) {
if t.trie == nil { if t.trie == nil {
t.trie, err = trie.NewSecure(t.originalRoot, t.db) t.trie, err = trie.NewSecure(t.originalRoot, t.db, 0)
} }
if err == nil { if err == nil {
err = t.trie.TryUpdate(key, value) err = t.trie.TryUpdate(key, value)
@ -112,7 +112,7 @@ func (t *LightTrie) Update(ctx context.Context, key, value []byte) (err error) {
func (t *LightTrie) Delete(ctx context.Context, key []byte) (err error) { func (t *LightTrie) Delete(ctx context.Context, key []byte) (err error) {
err = t.do(ctx, key, func() (err error) { err = t.do(ctx, key, func() (err error) {
if t.trie == nil { if t.trie == nil {
t.trie, err = trie.NewSecure(t.originalRoot, t.db) t.trie, err = trie.NewSecure(t.originalRoot, t.db, 0)
} }
if err == nil { if err == nil {
err = t.trie.TryDelete(key) err = t.trie.TryDelete(key)

View File

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/rcrowley/go-metrics" "github.com/rcrowley/go-metrics"
"github.com/rcrowley/go-metrics/exp"
) )
// MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. // MetricsEnabledFlag is the CLI flag name to use to enable metrics collections.
@ -44,6 +45,7 @@ func init() {
Enabled = true Enabled = true
} }
} }
exp.Exp(metrics.DefaultRegistry)
} }
// NewMeter create a new metrics Meter, either a real one of a NOP stub depending // NewMeter create a new metrics Meter, either a real one of a NOP stub depending

65
params/gas_table.go Normal file
View File

@ -0,0 +1,65 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// 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,
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package params
import "math/big"
type GasTable struct {
ExtcodeSize *big.Int
ExtcodeCopy *big.Int
Balance *big.Int
SLoad *big.Int
Calls *big.Int
Suicide *big.Int
// CreateBySuicide occurs when the
// refunded account is one that does
// not exist. This logic is similar
// to call. May be left nil. Nil means
// not charged.
CreateBySuicide *big.Int
}
var (
// GasTableHomestead contain the gas prices for
// the homestead phase.
GasTableHomestead = GasTable{
ExtcodeSize: big.NewInt(20),
ExtcodeCopy: big.NewInt(20),
Balance: big.NewInt(20),
SLoad: big.NewInt(50),
Calls: big.NewInt(40),
Suicide: big.NewInt(0),
// explicitly set to nil to indicate
// this rule does not apply to homestead.
CreateBySuicide: nil,
}
// GasTableHomestead contain the gas re-prices for
// the homestead phase.
GasTableHomesteadGasRepriceFork = GasTable{
ExtcodeSize: big.NewInt(700),
ExtcodeCopy: big.NewInt(700),
Balance: big.NewInt(400),
SLoad: big.NewInt(200),
Calls: big.NewInt(700),
Suicide: big.NewInt(5000),
CreateBySuicide: big.NewInt(25000),
}
)

View File

@ -71,4 +71,5 @@ var (
SuicideRefundGas = big.NewInt(24000) // Refunded following a suicide operation. SuicideRefundGas = big.NewInt(24000) // Refunded following a suicide operation.
MemoryGas = big.NewInt(3) // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. MemoryGas = big.NewInt(3) // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. TxDataNonZeroGas = big.NewInt(68) // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
) )

View File

@ -19,6 +19,8 @@ package params
import "math/big" import "math/big"
var ( var (
TestNetHomesteadBlock = big.NewInt(494000) // Testnet homestead block TestNetHomesteadBlock = big.NewInt(494000) // Testnet homestead block
MainNetHomesteadBlock = big.NewInt(1150000) // Mainnet homestead block MainNetHomesteadBlock = big.NewInt(1150000) // Mainnet homestead block
TestNetHomesteadGasRepriceBlock = big.NewInt(1783000) // Test net gas reprice block
MainNetHomesteadGasRepriceBlock = big.NewInt(2463000) // Main net gas reprice block
) )

View File

@ -23,63 +23,63 @@ import (
) )
func TestBcValidBlockTests(t *testing.T) { func TestBcValidBlockTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcValidBlockTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcValidBlockTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcUncleHeaderValidityTests(t *testing.T) { func TestBcUncleHeaderValidityTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcUncleHeaderValiditiy.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcUncleHeaderValiditiy.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcUncleTests(t *testing.T) { func TestBcUncleTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcUncleTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcUncleTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcForkUncleTests(t *testing.T) { func TestBcForkUncleTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcForkUncle.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcForkUncle.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcInvalidHeaderTests(t *testing.T) { func TestBcInvalidHeaderTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcInvalidHeaderTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcInvalidHeaderTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcInvalidRLPTests(t *testing.T) { func TestBcInvalidRLPTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcInvalidRLPTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcInvalidRLPTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcRPCAPITests(t *testing.T) { func TestBcRPCAPITests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcRPC_API_Test.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcRPC_API_Test.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcForkBlockTests(t *testing.T) { func TestBcForkBlockTests(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcForkBlockTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcForkBlockTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcForkStress(t *testing.T) { func TestBcForkStress(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcForkStressTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcForkStressTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -89,21 +89,21 @@ func TestBcTotalDifficulty(t *testing.T) {
// skip because these will fail due to selfish mining fix // skip because these will fail due to selfish mining fix
t.Skip() t.Skip()
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcTotalDifficultyTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcTotalDifficultyTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcWallet(t *testing.T) { func TestBcWallet(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcWalletTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcWalletTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcGasPricer(t *testing.T) { func TestBcGasPricer(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcGasPricerTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, nil, filepath.Join(blockTestDir, "bcGasPricerTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -111,7 +111,7 @@ func TestBcGasPricer(t *testing.T) {
// TODO: iterate over files once we got more than a few // TODO: iterate over files once we got more than a few
func TestBcRandom(t *testing.T) { func TestBcRandom(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "RandomTests/bl201507071825GO.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, big.NewInt(10), filepath.Join(blockTestDir, "RandomTests/bl201507071825GO.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -121,14 +121,14 @@ func TestBcMultiChain(t *testing.T) {
// skip due to selfish mining // skip due to selfish mining
t.Skip() t.Skip()
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcMultiChainTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, big.NewInt(10), filepath.Join(blockTestDir, "bcMultiChainTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestBcState(t *testing.T) { func TestBcState(t *testing.T) {
err := RunBlockTest(big.NewInt(1000000), nil, filepath.Join(blockTestDir, "bcStateTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(1000000), nil, big.NewInt(10), filepath.Join(blockTestDir, "bcStateTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -136,77 +136,77 @@ func TestBcState(t *testing.T) {
// Homestead tests // Homestead tests
func TestHomesteadBcValidBlockTests(t *testing.T) { func TestHomesteadBcValidBlockTests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcValidBlockTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcValidBlockTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcUncleHeaderValidityTests(t *testing.T) { func TestHomesteadBcUncleHeaderValidityTests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcUncleHeaderValiditiy.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcUncleHeaderValiditiy.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcUncleTests(t *testing.T) { func TestHomesteadBcUncleTests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcUncleTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcUncleTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcInvalidHeaderTests(t *testing.T) { func TestHomesteadBcInvalidHeaderTests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcInvalidHeaderTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcInvalidHeaderTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcRPCAPITests(t *testing.T) { func TestHomesteadBcRPCAPITests(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcRPC_API_Test.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcRPC_API_Test.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcForkStress(t *testing.T) { func TestHomesteadBcForkStress(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcForkStressTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcForkStressTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcTotalDifficulty(t *testing.T) { func TestHomesteadBcTotalDifficulty(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcTotalDifficultyTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcTotalDifficultyTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcWallet(t *testing.T) { func TestHomesteadBcWallet(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcWalletTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcWalletTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcGasPricer(t *testing.T) { func TestHomesteadBcGasPricer(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcGasPricerTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcGasPricerTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcMultiChain(t *testing.T) { func TestHomesteadBcMultiChain(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcMultiChainTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcMultiChainTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcState(t *testing.T) { func TestHomesteadBcState(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcStateTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcStateTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -214,26 +214,33 @@ func TestHomesteadBcState(t *testing.T) {
// DAO hard-fork tests // DAO hard-fork tests
func TestDAOBcTheDao(t *testing.T) { func TestDAOBcTheDao(t *testing.T) {
err := RunBlockTest(big.NewInt(5), big.NewInt(8), filepath.Join(blockTestDir, "TestNetwork", "bcTheDaoTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(5), big.NewInt(8), nil, filepath.Join(blockTestDir, "TestNetwork", "bcTheDaoTest.json"), BlockSkipTests)
if err != nil {
t.Fatal(err)
}
}
func TestEIP150Bc(t *testing.T) {
err := RunBlockTest(big.NewInt(0), big.NewInt(8), big.NewInt(10), filepath.Join(blockTestDir, "TestNetwork", "bcEIP150Test.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcExploit(t *testing.T) { func TestHomesteadBcExploit(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcExploitTest.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcExploitTest.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcShanghaiLove(t *testing.T) { func TestHomesteadBcShanghaiLove(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcShanghaiLove.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcShanghaiLove.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestHomesteadBcSuicideIssue(t *testing.T) { func TestHomesteadBcSuicideIssue(t *testing.T) {
err := RunBlockTest(big.NewInt(0), nil, filepath.Join(blockTestDir, "Homestead", "bcSuicideIssue.json"), BlockSkipTests) err := RunBlockTest(big.NewInt(0), nil, nil, filepath.Join(blockTestDir, "Homestead", "bcSuicideIssue.json"), BlockSkipTests)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -104,7 +104,7 @@ type btTransaction struct {
Value string Value string
} }
func RunBlockTestWithReader(homesteadBlock, daoForkBlock *big.Int, r io.Reader, skipTests []string) error { func RunBlockTestWithReader(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, r io.Reader, skipTests []string) error {
btjs := make(map[string]*btJSON) btjs := make(map[string]*btJSON)
if err := readJson(r, &btjs); err != nil { if err := readJson(r, &btjs); err != nil {
return err return err
@ -115,13 +115,13 @@ func RunBlockTestWithReader(homesteadBlock, daoForkBlock *big.Int, r io.Reader,
return err return err
} }
if err := runBlockTests(homesteadBlock, daoForkBlock, bt, skipTests); err != nil { if err := runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork, bt, skipTests); err != nil {
return err return err
} }
return nil return nil
} }
func RunBlockTest(homesteadBlock, daoForkBlock *big.Int, file string, skipTests []string) error { func RunBlockTest(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, file string, skipTests []string) error {
btjs := make(map[string]*btJSON) btjs := make(map[string]*btJSON)
if err := readJsonFile(file, &btjs); err != nil { if err := readJsonFile(file, &btjs); err != nil {
return err return err
@ -131,13 +131,13 @@ func RunBlockTest(homesteadBlock, daoForkBlock *big.Int, file string, skipTests
if err != nil { if err != nil {
return err return err
} }
if err := runBlockTests(homesteadBlock, daoForkBlock, bt, skipTests); err != nil { if err := runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork, bt, skipTests); err != nil {
return err return err
} }
return nil return nil
} }
func runBlockTests(homesteadBlock, daoForkBlock *big.Int, bt map[string]*BlockTest, skipTests []string) error { func runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, bt map[string]*BlockTest, skipTests []string) error {
skipTest := make(map[string]bool, len(skipTests)) skipTest := make(map[string]bool, len(skipTests))
for _, name := range skipTests { for _, name := range skipTests {
skipTest[name] = true skipTest[name] = true
@ -149,7 +149,7 @@ func runBlockTests(homesteadBlock, daoForkBlock *big.Int, bt map[string]*BlockTe
continue continue
} }
// test the block // test the block
if err := runBlockTest(homesteadBlock, daoForkBlock, test); err != nil { if err := runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork, test); err != nil {
return fmt.Errorf("%s: %v", name, err) return fmt.Errorf("%s: %v", name, err)
} }
glog.Infoln("Block test passed: ", name) glog.Infoln("Block test passed: ", name)
@ -158,7 +158,7 @@ func runBlockTests(homesteadBlock, daoForkBlock *big.Int, bt map[string]*BlockTe
return nil return nil
} }
func runBlockTest(homesteadBlock, daoForkBlock *big.Int, test *BlockTest) error { func runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, test *BlockTest) error {
// import pre accounts & construct test genesis block & state root // import pre accounts & construct test genesis block & state root
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
if _, err := test.InsertPreState(db); err != nil { if _, err := test.InsertPreState(db); err != nil {
@ -170,7 +170,7 @@ func runBlockTest(homesteadBlock, daoForkBlock *big.Int, test *BlockTest) error
core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64()) core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64())
core.WriteHeadBlockHash(db, test.Genesis.Hash()) core.WriteHeadBlockHash(db, test.Genesis.Hash())
evmux := new(event.TypeMux) evmux := new(event.TypeMux)
config := &core.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true} config := &core.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, HomesteadGasRepriceBlock: gasPriceFork}
chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux) chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux)
if err != nil { if err != nil {
return err return err

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,320 @@
{
"contractCreationOOGdontLeaveEmptyContract" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x0f4240",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x00",
"code" : "0x60106001557f6001600155601080600c6000396000f3006000355415600957005b6020356000600052602060006000f0",
"nonce" : "0x01",
"storage" : {
"0x01" : "0x10"
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x016a48",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x1c58",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
}
},
"postStateRoot" : "35df33d2a146ff660bb837914781857715d1b8752371b2f3e0768f29dd484775",
"pre" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x00",
"code" : "0x60106001557f6001600155601080600c6000396000f3006000355415600957005b6020356000600052602060006000f0",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x016b80",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "1000000000000000000000000000000000000001",
"value" : "0x00"
}
},
"contractCreationOOGdontLeaveEmptyContractViaTransaction" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x0f4240",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x0186a0",
"code" : "0x6001600155",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x10c8e0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0",
"code" : "0x6040600060406000600073100000000000000000000000000000000000000161c350f1",
"nonce" : "0x00",
"storage" : {
}
}
},
"postStateRoot" : "e83fc77d3037af4447bc5e67db8c646240473cd77125129d085d4ffeddbb5e4f",
"pre" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x0186a0",
"code" : "0x6001600155",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x10c8e0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0",
"code" : "0x6040600060406000600073100000000000000000000000000000000000000161c350f1",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "0x6040600060406000600073100000000000000000000000000000000000000161c350f1",
"gasLimit" : "0xcf08",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "",
"value" : "0x00"
}
},
"createContractViaContract" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x0f4240",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x00",
"code" : "0x600060006000f0",
"nonce" : "0x01",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0xcf11",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"5dddfce53ee040d9eb21afbc0ae1bb4dbb0ba643" : {
"balance" : "0x00",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xb78f",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
}
},
"postStateRoot" : "373942284112628b5c8cfd0f36d8058934fe6861cd7224feb3ac2d03739da305",
"pre" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x00",
"code" : "0x600060006000f0",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0186a0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "1000000000000000000000000000000000000001",
"value" : "0x00"
}
},
"createContractViaContractOOGInitCode" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x0f4240",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x00",
"code" : "0x6b602060406000f0600c600055600052600c60146000f0",
"nonce" : "0x01",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x019728",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0f31b8",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
}
},
"postStateRoot" : "f079b93388a39a4c343c66a917a044fb0d91de079786366d0c6c3b01bee07e7b",
"pre" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x00",
"code" : "0x6b602060406000f0600c600055600052600c60146000f0",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x10c8e0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x019a54",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "1000000000000000000000000000000000000001",
"value" : "0x00"
}
},
"createContractViaTransactionCost53000" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x0f4240",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0xcf08",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"6295ee1b4f6dd65047762f924ecd367c17eabf8f" : {
"balance" : "0x00",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xb798",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
}
},
"postStateRoot" : "53f5b84edd82703a225e53e9ae3639729eb8e337098531456998af602b0ded0a",
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0186a0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "",
"value" : "0x00"
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,842 @@
{
"CallAndCallcodeConsumeMoreGasThenTransactionHas" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000103" : {
"balance" : "0x00",
"code" : "0x6012600055",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12"
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x01de61",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a3319f",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000103620927c0f160095560006000600060006000731000000000000000000000000000000000000103620927c0f2600a55",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12",
"0x08" : "0x08d5b6",
"0x09" : "0x01",
"0x0a" : "0x01"
}
}
},
"postStateRoot" : "e07824c59862157c8bf611662ba4c741fb14bbb207765ca6c089a3161c90e786",
"pre" : {
"1000000000000000000000000000000000000103" : {
"balance" : "0x00",
"code" : "0x6012600055",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000103620927c0f160095560006000600060006000731000000000000000000000000000000000000103620927c0f2600a55",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"CallAskMoreGasOnDepth2ThenTransactionHas" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000107" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000108620927c0f1600955",
"nonce" : "0x00",
"storage" : {
"0x08" : "0x030d3e",
"0x09" : "0x01"
}
},
"1000000000000000000000000000000000000108" : {
"balance" : "0x00",
"code" : "0x5a600855",
"nonce" : "0x00",
"storage" : {
"0x08" : "0x02b157"
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x01de5f",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a331a1",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a6008556000600060006000600073100000000000000000000000000000000000010762030d40f1600955",
"nonce" : "0x00",
"storage" : {
"0x08" : "0x08d5b6",
"0x09" : "0x01"
}
}
},
"postStateRoot" : "ee81a2e65faf354a854a80b05a1cbe6ba6c4889c8904cef51fe58fe6b597ebd4",
"pre" : {
"1000000000000000000000000000000000000107" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000108620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000108" : {
"balance" : "0x00",
"code" : "0x5a600855",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a6008556000600060006000600073100000000000000000000000000000000000010762030d40f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"CallGoesOOGOnSecondLevel" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000110" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000111620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000111" : {
"balance" : "0x00",
"code" : "0x5a600855600060006000f050600060006000f0505a6009555a600a55",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x035b60",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a1b4a0",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000110620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"postStateRoot" : "efa25a148e3c0182c26ed417bf44ed027fc73297a668655d82e61053866e5043",
"pre" : {
"1000000000000000000000000000000000000110" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000111620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000111" : {
"balance" : "0x00",
"code" : "0x5a600855600060006000f050600060006000f0505a6009555a600a55",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000110620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x035b60",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"CallGoesOOGOnSecondLevel2" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000113" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000114620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000114" : {
"balance" : "0x00",
"code" : "0x5a6008555a6009555a600a55",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x027100",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a29f00",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000113620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"postStateRoot" : "ce9eb695d33e2a0421b7c83dc50126010f662cfcab1c6cf971fc22d33e58ed49",
"pre" : {
"1000000000000000000000000000000000000113" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000114620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000114" : {
"balance" : "0x00",
"code" : "0x5a6008555a6009555a600a55",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560006000600060006000731000000000000000000000000000000000000113620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x027100",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"CreateAndGasInsideCreate" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x0207af",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a30851",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a600a55635a60fd556000526004601c6000f0600b555a600955",
"nonce" : "0x01",
"storage" : {
"0x09" : "0x076e34",
"0x0a" : "0x08d5b6",
"0x0b" : "0xf1ecf98489fa9ed60a664fc4998db699cfa39d40"
}
},
"f1ecf98489fa9ed60a664fc4998db699cfa39d40" : {
"balance" : "0x00",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
"0xfd" : "0x07ea53"
}
}
},
"postStateRoot" : "3ca082f6185a3019aea75573a032dd81b0e99f7b7f464b1a84e55eae4513baf5",
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a600a55635a60fd556000526004601c6000f0600b555a600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"DelegateCallOnEIP" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000105" : {
"balance" : "0x00",
"code" : "0x6012600055",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x013f44",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a3d0bc",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a6008556000600060006000731000000000000000000000000000000000000105620927c0f4600955",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12",
"0x08" : "0x08d5b6",
"0x09" : "0x01"
}
}
},
"postStateRoot" : "ccd9fad58a72db64ef2ed866ed2cef19f77371516bfed7fb06958262be55b9ff",
"pre" : {
"1000000000000000000000000000000000000105" : {
"balance" : "0x00",
"code" : "0x6012600055",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a6008556000600060006000731000000000000000000000000000000000000105620927c0f4600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"ExecuteCallThatAskForeGasThenTrabsactionHas" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x0186a0",
"code" : "0x600c600155",
"nonce" : "0x00",
"storage" : {
"0x01" : "0x0c"
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0xf122",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x957e",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x60006000600060006000731000000000000000000000000000000000000001620927c0f1600155",
"nonce" : "0x00",
"storage" : {
"0x01" : "0x01"
}
}
},
"postStateRoot" : "a306e41ea48a4777ce1ed4032d38cc4c56fd68acb409e69cec7e1315f08bf388",
"pre" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x0186a0",
"code" : "0x600c600155",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x60006000600060006000731000000000000000000000000000000000000001620927c0f1600155",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0186a0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"NewGasPriceForCodes" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000010" : {
"balance" : "0x6f",
"code" : "0x1122334455667788991011121314151617181920212223242526272829303132",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000011" : {
"balance" : "0x00",
"code" : "0x6011606455",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000013" : {
"balance" : "0x00",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x03936d",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a17c93",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x7310000000000000000000000000000000000000103b6001556014600060007310000000000000000000000000000000000000103c60005160025560005460045560006000600060006001731000000000000000000000000000000000000011617530f160055560006000600060006001731000000000000000000000000000000000000011617530f26006556000600060006000731000000000000000000000000000000000000011617530f460075560006000600060006000731000000000000000000000000000000000000013617530f160085573a94f5374fce5edbc8e2a8697c15331677e6ebf0b316003555a600a55",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12",
"0x01" : "0x20",
"0x02" : "0x1122334455667788991011121314151617181920000000000000000000000000",
"0x03" : "0xe8d49be840",
"0x04" : "0x12",
"0x07" : "0x01",
"0x08" : "0x01",
"0x0a" : "0x05e276",
"0x64" : "0x11"
}
}
},
"postStateRoot" : "58530241bc470bb693bf79333ecdb9561a65cad9a5e2717df5e9d2e252ed111e",
"pre" : {
"1000000000000000000000000000000000000010" : {
"balance" : "0x6f",
"code" : "0x1122334455667788991011121314151617181920212223242526272829303132",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000011" : {
"balance" : "0x00",
"code" : "0x6011606455",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x7310000000000000000000000000000000000000103b6001556014600060007310000000000000000000000000000000000000103c60005160025560005460045560006000600060006001731000000000000000000000000000000000000011617530f160055560006000600060006001731000000000000000000000000000000000000011617530f26006556000600060006000731000000000000000000000000000000000000011617530f460075560006000600060006000731000000000000000000000000000000000000013617530f160085573a94f5374fce5edbc8e2a8697c15331677e6ebf0b316003555a600a55",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12"
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"SuicideToExistingContract" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x5b46",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a4b4ba",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x6000600060006000600073100000000000000000000000000000000000011861ea60f1505a600155",
"nonce" : "0x00",
"storage" : {
"0x01" : "0x08bf58"
}
}
},
"postStateRoot" : "7f124d7f842eeeebc6889a06e0ad72ff0eb1ef804ee0254a6b3810b82eac0ddc",
"pre" : {
"1000000000000000000000000000000000000118" : {
"balance" : "0x00",
"code" : "0x73b94f5374fce5edbc8e2a8697c15331677e6ebf0bff",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x6000600060006000600073100000000000000000000000000000000000011861ea60f1505a600155",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"SuicideToNotExistingContract" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"2000000000000000000000000000000000000115" : {
"balance" : "0x00",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0xba73",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a4558d",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x6000600060006000600073100000000000000000000000000000000000011661ea60f1505a600155",
"nonce" : "0x00",
"storage" : {
"0x01" : "0x085db0"
}
}
},
"postStateRoot" : "b58c2baf17ec8ec989abfb6056bae2e5afe08d1bce5fc64039faba8e86f4fdd6",
"pre" : {
"1000000000000000000000000000000000000116" : {
"balance" : "0x00",
"code" : "0x732000000000000000000000000000000000000115ff",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x6000600060006000600073100000000000000000000000000000000000011661ea60f1505a600155",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
}
}

View File

@ -0,0 +1,695 @@
{
"CallAndCallcodeConsumeMoreGasThenTransactionHasWithMemExpandingCalls" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000103" : {
"balance" : "0x00",
"code" : "0x6012600055",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12"
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x01de91",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a3316f",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000103620927c0f160095560ff60ff60ff60ff6000731000000000000000000000000000000000000103620927c0f2600a55",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12",
"0x08" : "0x08d5b6",
"0x09" : "0x01",
"0x0a" : "0x01"
}
}
},
"postStateRoot" : "3a47c0e593bb7e5efddd07e15e10b7dc504b52b53ed93a924c5a32ff4ef5c373",
"pre" : {
"1000000000000000000000000000000000000103" : {
"balance" : "0x00",
"code" : "0x6012600055",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000103620927c0f160095560ff60ff60ff60ff6000731000000000000000000000000000000000000103620927c0f2600a55",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"CallAskMoreGasOnDepth2ThenTransactionHasWithMemExpandingCalls" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000107" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000108620927c0f1600955",
"nonce" : "0x00",
"storage" : {
"0x08" : "0x030d3e",
"0x09" : "0x01"
}
},
"1000000000000000000000000000000000000108" : {
"balance" : "0x00",
"code" : "0x5a600855",
"nonce" : "0x00",
"storage" : {
"0x08" : "0x02b128"
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x01debf",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a33141",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff600073100000000000000000000000000000000000010762030d40f1600955",
"nonce" : "0x00",
"storage" : {
"0x08" : "0x08d5b6",
"0x09" : "0x01"
}
}
},
"postStateRoot" : "c8d3489ab7b0e7016720dc3b3bb467d3413baf8c4309a37a90a0fd355ad931db",
"pre" : {
"1000000000000000000000000000000000000107" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000108620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000108" : {
"balance" : "0x00",
"code" : "0x5a600855",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff600073100000000000000000000000000000000000010762030d40f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"CallGoesOOGOnSecondLevel2WithMemExpandingCalls" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000113" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000114620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000114" : {
"balance" : "0x00",
"code" : "0x5a6008555a6009555a600a55",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x027100",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a29f00",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000113620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"postStateRoot" : "c53380bbe4ce6faf67f118f60693db4bc55ad222bca864a691d72de50432e1b2",
"pre" : {
"1000000000000000000000000000000000000113" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000114620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000114" : {
"balance" : "0x00",
"code" : "0x5a6008555a6009555a600a55",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000113620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x027100",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"CallGoesOOGOnSecondLevelWithMemExpandingCalls" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000110" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000111620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000111" : {
"balance" : "0x00",
"code" : "0x5a600855600060006000f050600060006000f0505a6009555a600a55",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x035b60",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a1b4a0",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000110620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"postStateRoot" : "f29c645d8735ceb8bc618a4069db255bdf77c23ece151cf0822c1613e8227c00",
"pre" : {
"1000000000000000000000000000000000000110" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000111620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000111" : {
"balance" : "0x00",
"code" : "0x5a600855600060006000f050600060006000f0505a6009555a600a55",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff6000731000000000000000000000000000000000000110620927c0f1600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x035b60",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"CreateAndGasInsideCreateWithMemExpandingCalls" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x0207af",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a30851",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a600a55635a60fd556000526004601c6000f0600b555a600955",
"nonce" : "0x01",
"storage" : {
"0x09" : "0x076e34",
"0x0a" : "0x08d5b6",
"0x0b" : "0xf1ecf98489fa9ed60a664fc4998db699cfa39d40"
}
},
"f1ecf98489fa9ed60a664fc4998db699cfa39d40" : {
"balance" : "0x00",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
"0xfd" : "0x07ea53"
}
}
},
"postStateRoot" : "3ca082f6185a3019aea75573a032dd81b0e99f7b7f464b1a84e55eae4513baf5",
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a600a55635a60fd556000526004601c6000f0600b555a600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"DelegateCallOnEIPWithMemExpandingCalls" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000105" : {
"balance" : "0x00",
"code" : "0x6012600055",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x013f74",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a3d08c",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff731000000000000000000000000000000000000105620927c0f4600955",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12",
"0x08" : "0x08d5b6",
"0x09" : "0x01"
}
}
},
"postStateRoot" : "a5c328fefa9c88698bc8874c177e30b327354c21d0fc4e8798f311f98ad9ac6c",
"pre" : {
"1000000000000000000000000000000000000105" : {
"balance" : "0x00",
"code" : "0x6012600055",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x5a60085560ff60ff60ff60ff731000000000000000000000000000000000000105620927c0f4600955",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"ExecuteCallThatAskForeGasThenTrabsactionHasWithMemExpandingCalls" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x0186a0",
"code" : "0x600c600155",
"nonce" : "0x00",
"storage" : {
"0x01" : "0x0c"
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0xf152",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x954e",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x60ff60ff60ff60ff6000731000000000000000000000000000000000000001620927c0f1600155",
"nonce" : "0x00",
"storage" : {
"0x01" : "0x01"
}
}
},
"postStateRoot" : "94b4df76c833bb02bfeb6b63427db966e368c23d3a41baf0c06ca6d6c29368d5",
"pre" : {
"1000000000000000000000000000000000000001" : {
"balance" : "0x0186a0",
"code" : "0x600c600155",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0186a0",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x60ff60ff60ff60ff6000731000000000000000000000000000000000000001620927c0f1600155",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0186a0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
},
"NewGasPriceForCodesWithMemExpandingCalls" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x02b8feb0",
"currentGasLimit" : "0x989680",
"currentNumber" : "0x257da8",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"logs" : [
],
"out" : "0x",
"post" : {
"1000000000000000000000000000000000000010" : {
"balance" : "0x6f",
"code" : "0x1122334455667788991011121314151617181920212223242526272829303132",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000011" : {
"balance" : "0x00",
"code" : "0x6011606455",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000013" : {
"balance" : "0x00",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0x03939a",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a17c66",
"code" : "0x",
"nonce" : "0x01",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x7310000000000000000000000000000000000000103b6001556014600060007310000000000000000000000000000000000000103c60005160025560005460045560ff60ff60ff60ff6001731000000000000000000000000000000000000011617530f160055560ff60ff60ff60ff6001731000000000000000000000000000000000000011617530f260065560ff60ff60ff60ff731000000000000000000000000000000000000011617530f460075560ff60ff60ff60ff6000731000000000000000000000000000000000000013617530f160085573a94f5374fce5edbc8e2a8697c15331677e6ebf0b316003555a600a55",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12",
"0x01" : "0x20",
"0x02" : "0x1122334455667788991011121314151617181920000000000000000000000000",
"0x03" : "0xe8d49be840",
"0x04" : "0x12",
"0x07" : "0x01",
"0x08" : "0x01",
"0x0a" : "0x05e249",
"0x64" : "0x11"
}
}
},
"postStateRoot" : "479fef1d31182ab6f401423f71268b338d5ab64cf0134b1d00429fbbb2681bc8",
"pre" : {
"1000000000000000000000000000000000000010" : {
"balance" : "0x6f",
"code" : "0x1122334455667788991011121314151617181920212223242526272829303132",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000011" : {
"balance" : "0x00",
"code" : "0x6011606455",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0xe8d4a51000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x00",
"code" : "0x7310000000000000000000000000000000000000103b6001556014600060007310000000000000000000000000000000000000103c60005160025560005460045560ff60ff60ff60ff6001731000000000000000000000000000000000000011617530f160055560ff60ff60ff60ff6001731000000000000000000000000000000000000011617530f260065560ff60ff60ff60ff731000000000000000000000000000000000000011617530f460075560ff60ff60ff60ff6000731000000000000000000000000000000000000013617530f160085573a94f5374fce5edbc8e2a8697c15331677e6ebf0b316003555a600a55",
"nonce" : "0x00",
"storage" : {
"0x00" : "0x12"
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "0x0927c0",
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "0x00"
}
}
}

View File

@ -440,3 +440,238 @@ func TestHomesteadBounds(t *testing.T) {
t.Error(err) t.Error(err)
} }
} }
// EIP150 tests
func TestEIP150Specific(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "stEIPSpecificTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150SingleCodeGasPrice(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "stEIPSingleCodeGasPrices.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150MemExpandingCalls(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "stMemExpandingEIPCalls.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadStateSystemOperations(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stSystemOperationsTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadStatePreCompiledContracts(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stPreCompiledContracts.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadStateRecursiveCreate(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stSpecialTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadStateRefund(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stRefundTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadStateInitCode(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stInitCodeTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadStateLog(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stLogTests.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadStateTransaction(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stTransactionTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadCallCreateCallCode(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallCreateCallCodeTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadCallCodes(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallCodes.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadMemory(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stMemoryTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadMemoryStress(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
if os.Getenv("TEST_VM_COMPLEX") == "" {
t.Skip()
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stMemoryStressTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadQuadraticComplexity(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
if os.Getenv("TEST_VM_COMPLEX") == "" {
t.Skip()
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stQuadraticComplexityTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadWallet(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stWalletTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadDelegateCodes(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallDelegateCodes.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadDelegateCodesCallCode(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallDelegateCodesCallCode.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}
func TestEIP150HomesteadBounds(t *testing.T) {
ruleSet := RuleSet{
HomesteadBlock: new(big.Int),
HomesteadGasRepriceBlock: big.NewInt(2457000),
}
fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stBoundsTest.json")
if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
t.Error(err)
}
}

View File

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
) )
var ( var (
@ -148,15 +149,24 @@ type VmTest struct {
} }
type RuleSet struct { type RuleSet struct {
HomesteadBlock *big.Int HomesteadBlock *big.Int
DAOForkBlock *big.Int DAOForkBlock *big.Int
DAOForkSupport bool DAOForkSupport bool
HomesteadGasRepriceBlock *big.Int
} }
func (r RuleSet) IsHomestead(n *big.Int) bool { func (r RuleSet) IsHomestead(n *big.Int) bool {
return n.Cmp(r.HomesteadBlock) >= 0 return n.Cmp(r.HomesteadBlock) >= 0
} }
func (r RuleSet) GasTable(num *big.Int) params.GasTable {
if r.HomesteadGasRepriceBlock == nil || num == nil || num.Cmp(r.HomesteadGasRepriceBlock) < 0 {
return params.GasTableHomestead
}
return params.GasTableHomesteadGasRepriceFork
}
type Env struct { type Env struct {
ruleSet RuleSet ruleSet RuleSet
depth int depth int

View File

@ -225,7 +225,7 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs,
caller := state.GetOrNewStateObject(from) caller := state.GetOrNewStateObject(from)
vmenv := NewEnvFromMap(RuleSet{params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, true}, state, env, exec) vmenv := NewEnvFromMap(RuleSet{params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, true, nil}, state, env, exec)
vmenv.vmTest = true vmenv.vmTest = true
vmenv.skipTransfer = true vmenv.skipTransfer = true
vmenv.initial = true vmenv.initial = true

View File

@ -27,8 +27,9 @@ import (
) )
type hasher struct { type hasher struct {
tmp *bytes.Buffer tmp *bytes.Buffer
sha hash.Hash sha hash.Hash
cachegen, cachelimit uint16
} }
// hashers live in a global pool. // hashers live in a global pool.
@ -38,8 +39,10 @@ var hasherPool = sync.Pool{
}, },
} }
func newHasher() *hasher { func newHasher(cachegen, cachelimit uint16) *hasher {
return hasherPool.Get().(*hasher) h := hasherPool.Get().(*hasher)
h.cachegen, h.cachelimit = cachegen, cachelimit
return h
} }
func returnHasherToPool(h *hasher) { func returnHasherToPool(h *hasher) {
@ -50,8 +53,18 @@ func returnHasherToPool(h *hasher) {
// original node initialzied with the computed hash to replace the original one. // original node initialzied with the computed hash to replace the original one.
func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) { func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) {
// If we're not storing the node, just hashing, use avaialble cached data // If we're not storing the node, just hashing, use avaialble cached data
if hash, dirty := n.cache(); hash != nil && (db == nil || !dirty) { if hash, dirty := n.cache(); hash != nil {
return hash, n, nil if db == nil {
return hash, n, nil
}
if n.canUnload(h.cachegen, h.cachelimit) {
// Evict the node from cache. All of its subnodes will have a lower or equal
// cache generation number.
return hash, hash, nil
}
if !dirty {
return hash, n, nil
}
} }
// Trie not processed yet or needs storage, walk the children // Trie not processed yet or needs storage, walk the children
collapsed, cached, err := h.hashChildren(n, db) collapsed, cached, err := h.hashChildren(n, db)
@ -62,19 +75,21 @@ func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error)
if err != nil { if err != nil {
return hashNode{}, n, err return hashNode{}, n, err
} }
// Cache the hash and RLP blob of the ndoe for later reuse // Cache the hash of the ndoe for later reuse.
if hash, ok := hashed.(hashNode); ok && !force { if hash, ok := hashed.(hashNode); ok && !force {
switch cached := cached.(type) { switch cached := cached.(type) {
case shortNode: case *shortNode:
cached.hash = hash cached = cached.copy()
cached.flags.hash = hash
if db != nil { if db != nil {
cached.dirty = false cached.flags.dirty = false
} }
return hashed, cached, nil return hashed, cached, nil
case fullNode: case *fullNode:
cached.hash = hash cached = cached.copy()
cached.flags.hash = hash
if db != nil { if db != nil {
cached.dirty = false cached.flags.dirty = false
} }
return hashed, cached, nil return hashed, cached, nil
} }
@ -89,40 +104,42 @@ func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, err
var err error var err error
switch n := original.(type) { switch n := original.(type) {
case shortNode: case *shortNode:
// Hash the short node's child, caching the newly hashed subtree // Hash the short node's child, caching the newly hashed subtree
cached := n collapsed, cached := n.copy(), n.copy()
cached.Key = common.CopyBytes(cached.Key) collapsed.Key = compactEncode(n.Key)
cached.Key = common.CopyBytes(n.Key)
n.Key = compactEncode(n.Key)
if _, ok := n.Val.(valueNode); !ok { if _, ok := n.Val.(valueNode); !ok {
if n.Val, cached.Val, err = h.hash(n.Val, db, false); err != nil { collapsed.Val, cached.Val, err = h.hash(n.Val, db, false)
return n, original, err if err != nil {
return original, original, err
} }
} }
if n.Val == nil { if collapsed.Val == nil {
n.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings. collapsed.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings.
} }
return n, cached, nil return collapsed, cached, nil
case fullNode: case *fullNode:
// Hash the full node's children, caching the newly hashed subtrees // Hash the full node's children, caching the newly hashed subtrees
cached := fullNode{dirty: n.dirty} collapsed, cached := n.copy(), n.copy()
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
if n.Children[i] != nil { if n.Children[i] != nil {
if n.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false); err != nil { collapsed.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false)
return n, original, err if err != nil {
return original, original, err
} }
} else { } else {
n.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings. collapsed.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings.
} }
} }
cached.Children[16] = n.Children[16] cached.Children[16] = n.Children[16]
if n.Children[16] == nil { if collapsed.Children[16] == nil {
n.Children[16] = valueNode(nil) collapsed.Children[16] = valueNode(nil)
} }
return n, cached, nil return collapsed, cached, nil
default: default:
// Value and hash nodes don't have children so they're left as were // Value and hash nodes don't have children so they're left as were
@ -140,6 +157,7 @@ func (h *hasher) store(n node, db DatabaseWriter, force bool) (node, error) {
if err := rlp.Encode(h.tmp, n); err != nil { if err := rlp.Encode(h.tmp, n); err != nil {
panic("encode error: " + err.Error()) panic("encode error: " + err.Error())
} }
if h.tmp.Len() < 32 && !force { if h.tmp.Len() < 32 && !force {
return n, nil // Nodes smaller than 32 bytes are stored inside their parent return n, nil // Nodes smaller than 32 bytes are stored inside their parent
} }

View File

@ -56,11 +56,11 @@ func (it *Iterator) makeKey() []byte {
key := it.keyBuf[:0] key := it.keyBuf[:0]
for _, se := range it.nodeIt.stack { for _, se := range it.nodeIt.stack {
switch node := se.node.(type) { switch node := se.node.(type) {
case fullNode: case *fullNode:
if se.child <= 16 { if se.child <= 16 {
key = append(key, byte(se.child)) key = append(key, byte(se.child))
} }
case shortNode: case *shortNode:
if hasTerm(node.Key) { if hasTerm(node.Key) {
key = append(key, node.Key[:len(node.Key)-1]...) key = append(key, node.Key[:len(node.Key)-1]...)
} else { } else {
@ -148,7 +148,7 @@ func (it *NodeIterator) step() error {
if (ancestor == common.Hash{}) { if (ancestor == common.Hash{}) {
ancestor = parent.parent ancestor = parent.parent
} }
if node, ok := parent.node.(fullNode); ok { if node, ok := parent.node.(*fullNode); ok {
// Full node, traverse all children, then the node itself // Full node, traverse all children, then the node itself
if parent.child >= len(node.Children) { if parent.child >= len(node.Children) {
break break
@ -156,7 +156,7 @@ func (it *NodeIterator) step() error {
for parent.child++; parent.child < len(node.Children); parent.child++ { for parent.child++; parent.child < len(node.Children); parent.child++ {
if current := node.Children[parent.child]; current != nil { if current := node.Children[parent.child]; current != nil {
it.stack = append(it.stack, &nodeIteratorState{ it.stack = append(it.stack, &nodeIteratorState{
hash: common.BytesToHash(node.hash), hash: common.BytesToHash(node.flags.hash),
node: current, node: current,
parent: ancestor, parent: ancestor,
child: -1, child: -1,
@ -164,14 +164,14 @@ func (it *NodeIterator) step() error {
break break
} }
} }
} else if node, ok := parent.node.(shortNode); ok { } else if node, ok := parent.node.(*shortNode); ok {
// Short node, traverse the pointer singleton child, then the node itself // Short node, traverse the pointer singleton child, then the node itself
if parent.child >= 0 { if parent.child >= 0 {
break break
} }
parent.child++ parent.child++
it.stack = append(it.stack, &nodeIteratorState{ it.stack = append(it.stack, &nodeIteratorState{
hash: common.BytesToHash(node.hash), hash: common.BytesToHash(node.flags.hash),
node: node.Val, node: node.Val,
parent: ancestor, parent: ancestor,
child: -1, child: -1,

View File

@ -30,42 +30,60 @@ var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b
type node interface { type node interface {
fstring(string) string fstring(string) string
cache() (hashNode, bool) cache() (hashNode, bool)
canUnload(cachegen, cachelimit uint16) bool
} }
type ( type (
fullNode struct { fullNode struct {
Children [17]node // Actual trie node data to encode/decode (needs custom encoder) Children [17]node // Actual trie node data to encode/decode (needs custom encoder)
hash hashNode // Cached hash of the node to prevent rehashing (may be nil) flags nodeFlag
dirty bool // Cached flag whether the node's new or already stored
} }
shortNode struct { shortNode struct {
Key []byte Key []byte
Val node Val node
hash hashNode // Cached hash of the node to prevent rehashing (may be nil) flags nodeFlag
dirty bool // Cached flag whether the node's new or already stored
} }
hashNode []byte hashNode []byte
valueNode []byte valueNode []byte
) )
// EncodeRLP encodes a full node into the consensus RLP format. // EncodeRLP encodes a full node into the consensus RLP format.
func (n fullNode) EncodeRLP(w io.Writer) error { func (n *fullNode) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, n.Children) return rlp.Encode(w, n.Children)
} }
// Cache accessors to retrieve precalculated values (avoid lengthy type switches). func (n *fullNode) copy() *fullNode { copy := *n; return &copy }
func (n fullNode) cache() (hashNode, bool) { return n.hash, n.dirty } func (n *shortNode) copy() *shortNode { copy := *n; return &copy }
func (n shortNode) cache() (hashNode, bool) { return n.hash, n.dirty }
func (n hashNode) cache() (hashNode, bool) { return nil, true } // nodeFlag contains caching-related metadata about a node.
func (n valueNode) cache() (hashNode, bool) { return nil, true } type nodeFlag struct {
hash hashNode // cached hash of the node (may be nil)
gen uint16 // cache generation counter
dirty bool // whether the node has changes that must be written to the database
}
// canUnload tells whether a node can be unloaded.
func (n *nodeFlag) canUnload(cachegen, cachelimit uint16) bool {
return !n.dirty && cachegen-n.gen >= cachelimit
}
func (n *fullNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) }
func (n *shortNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) }
func (n hashNode) canUnload(uint16, uint16) bool { return false }
func (n valueNode) canUnload(uint16, uint16) bool { return false }
func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty }
func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty }
func (n hashNode) cache() (hashNode, bool) { return nil, true }
func (n valueNode) cache() (hashNode, bool) { return nil, true }
// Pretty printing. // Pretty printing.
func (n fullNode) String() string { return n.fstring("") } func (n *fullNode) String() string { return n.fstring("") }
func (n shortNode) String() string { return n.fstring("") } func (n *shortNode) String() string { return n.fstring("") }
func (n hashNode) String() string { return n.fstring("") } func (n hashNode) String() string { return n.fstring("") }
func (n valueNode) String() string { return n.fstring("") } func (n valueNode) String() string { return n.fstring("") }
func (n fullNode) fstring(ind string) string { func (n *fullNode) fstring(ind string) string {
resp := fmt.Sprintf("[\n%s ", ind) resp := fmt.Sprintf("[\n%s ", ind)
for i, node := range n.Children { for i, node := range n.Children {
if node == nil { if node == nil {
@ -76,7 +94,7 @@ func (n fullNode) fstring(ind string) string {
} }
return resp + fmt.Sprintf("\n%s] ", ind) return resp + fmt.Sprintf("\n%s] ", ind)
} }
func (n shortNode) fstring(ind string) string { func (n *shortNode) fstring(ind string) string {
return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+" ")) return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+" "))
} }
func (n hashNode) fstring(ind string) string { func (n hashNode) fstring(ind string) string {
@ -120,6 +138,7 @@ func decodeShort(hash, buf, elems []byte) (node, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
flag := nodeFlag{hash: hash}
key := compactDecode(kbuf) key := compactDecode(kbuf)
if key[len(key)-1] == 16 { if key[len(key)-1] == 16 {
// value node // value node
@ -127,17 +146,17 @@ func decodeShort(hash, buf, elems []byte) (node, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid value node: %v", err) return nil, fmt.Errorf("invalid value node: %v", err)
} }
return shortNode{key, valueNode(val), hash, false}, nil return &shortNode{key, append(valueNode{}, val...), flag}, nil
} }
r, _, err := decodeRef(rest) r, _, err := decodeRef(rest)
if err != nil { if err != nil {
return nil, wrapError(err, "val") return nil, wrapError(err, "val")
} }
return shortNode{key, r, hash, false}, nil return &shortNode{key, r, flag}, nil
} }
func decodeFull(hash, buf, elems []byte) (fullNode, error) { func decodeFull(hash, buf, elems []byte) (*fullNode, error) {
n := fullNode{hash: hash} n := &fullNode{flags: nodeFlag{hash: hash}}
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
cld, rest, err := decodeRef(elems) cld, rest, err := decodeRef(elems)
if err != nil { if err != nil {
@ -150,7 +169,7 @@ func decodeFull(hash, buf, elems []byte) (fullNode, error) {
return n, err return n, err
} }
if len(val) > 0 { if len(val) > 0 {
n.Children[16] = valueNode(val) n.Children[16] = append(valueNode{}, val...)
} }
return n, nil return n, nil
} }
@ -176,7 +195,7 @@ func decodeRef(buf []byte) (node, []byte, error) {
// empty node // empty node
return nil, rest, nil return nil, rest, nil
case kind == rlp.String && len(val) == 32: case kind == rlp.String && len(val) == 32:
return hashNode(val), rest, nil return append(hashNode{}, val...), rest, nil
default: default:
return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val)) return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val))
} }

58
trie/node_test.go Normal file
View File

@ -0,0 +1,58 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// 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,
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package trie
import "testing"
func TestCanUnload(t *testing.T) {
tests := []struct {
flag nodeFlag
cachegen, cachelimit uint16
want bool
}{
{
flag: nodeFlag{dirty: true, gen: 0},
want: false,
},
{
flag: nodeFlag{dirty: false, gen: 0},
cachegen: 0, cachelimit: 0,
want: true,
},
{
flag: nodeFlag{dirty: false, gen: 65534},
cachegen: 65535, cachelimit: 1,
want: true,
},
{
flag: nodeFlag{dirty: false, gen: 65534},
cachegen: 0, cachelimit: 1,
want: true,
},
{
flag: nodeFlag{dirty: false, gen: 1},
cachegen: 65535, cachelimit: 1,
want: true,
},
}
for _, test := range tests {
if got := test.flag.canUnload(test.cachegen, test.cachelimit); got != test.want {
t.Errorf("%+v\n got %t, want %t", test, got, test.want)
}
}
}

View File

@ -44,7 +44,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue {
tn := t.root tn := t.root
for len(key) > 0 && tn != nil { for len(key) > 0 && tn != nil {
switch n := tn.(type) { switch n := tn.(type) {
case shortNode: case *shortNode:
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
// The trie doesn't contain the key. // The trie doesn't contain the key.
tn = nil tn = nil
@ -53,7 +53,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue {
key = key[len(n.Key):] key = key[len(n.Key):]
} }
nodes = append(nodes, n) nodes = append(nodes, n)
case fullNode: case *fullNode:
tn = n.Children[key[0]] tn = n.Children[key[0]]
key = key[1:] key = key[1:]
nodes = append(nodes, n) nodes = append(nodes, n)
@ -70,7 +70,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue {
panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) panic(fmt.Sprintf("%T: invalid node: %v", tn, tn))
} }
} }
hasher := newHasher() hasher := newHasher(0, 0)
proof := make([]rlp.RawValue, 0, len(nodes)) proof := make([]rlp.RawValue, 0, len(nodes))
for i, n := range nodes { for i, n := range nodes {
// Don't bother checking for errors here since hasher panics // Don't bother checking for errors here since hasher panics
@ -130,13 +130,13 @@ func VerifyProof(rootHash common.Hash, key []byte, proof []rlp.RawValue) (value
func get(tn node, key []byte) ([]byte, node) { func get(tn node, key []byte) ([]byte, node) {
for len(key) > 0 { for len(key) > 0 {
switch n := tn.(type) { switch n := tn.(type) {
case shortNode: case *shortNode:
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
return nil, nil return nil, nil
} }
tn = n.Val tn = n.Val
key = key[len(n.Key):] key = key[len(n.Key):]
case fullNode: case *fullNode:
tn = n.Children[key[0]] tn = n.Children[key[0]]
key = key[1:] key = key[1:]
case hashNode: case hashNode:

View File

@ -49,8 +49,12 @@ type SecureTrie struct {
// If root is the zero hash or the sha3 hash of an empty string, the // If root is the zero hash or the sha3 hash of an empty string, the
// trie is initially empty. Otherwise, New will panic if db is nil // trie is initially empty. Otherwise, New will panic if db is nil
// and returns MissingNodeError if the root node cannot be found. // and returns MissingNodeError if the root node cannot be found.
//
// Accessing the trie loads nodes from db on demand. // Accessing the trie loads nodes from db on demand.
func NewSecure(root common.Hash, db Database) (*SecureTrie, error) { // Loaded nodes are kept around until their 'cache generation' expires.
// A new cache generation is created by each call to Commit.
// cachelimit sets the number of past cache generations to keep.
func NewSecure(root common.Hash, db Database, cachelimit uint16) (*SecureTrie, error) {
if db == nil { if db == nil {
panic("NewSecure called with nil database") panic("NewSecure called with nil database")
} }
@ -58,9 +62,8 @@ func NewSecure(root common.Hash, db Database) (*SecureTrie, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &SecureTrie{ trie.SetCacheLimit(cachelimit)
trie: *trie, return &SecureTrie{trie: *trie}, nil
}, nil
} }
// Get returns the value for key stored in the trie. // Get returns the value for key stored in the trie.
@ -191,7 +194,7 @@ func (t *SecureTrie) secKey(key []byte) []byte {
// The caller must not hold onto the return value because it will become // The caller must not hold onto the return value because it will become
// invalid on the next call to hashKey or secKey. // invalid on the next call to hashKey or secKey.
func (t *SecureTrie) hashKey(key []byte) []byte { func (t *SecureTrie) hashKey(key []byte) []byte {
h := newHasher() h := newHasher(0, 0)
h.sha.Reset() h.sha.Reset()
h.sha.Write(key) h.sha.Write(key)
buf := h.sha.Sum(t.hashKeyBuf[:0]) buf := h.sha.Sum(t.hashKeyBuf[:0])

View File

@ -29,7 +29,7 @@ import (
func newEmptySecure() *SecureTrie { func newEmptySecure() *SecureTrie {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
trie, _ := NewSecure(common.Hash{}, db) trie, _ := NewSecure(common.Hash{}, db, 0)
return trie return trie
} }
@ -37,7 +37,7 @@ func newEmptySecure() *SecureTrie {
func makeTestSecureTrie() (ethdb.Database, *SecureTrie, map[string][]byte) { func makeTestSecureTrie() (ethdb.Database, *SecureTrie, map[string][]byte) {
// Create an empty trie // Create an empty trie
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
trie, _ := NewSecure(common.Hash{}, db) trie, _ := NewSecure(common.Hash{}, db, 0)
// Fill it with some arbitrary data // Fill it with some arbitrary data
content := make(map[string][]byte) content := make(map[string][]byte)

View File

@ -212,12 +212,14 @@ func (s *TrieSync) children(req *request) ([]*request, error) {
children := []child{} children := []child{}
switch node := (*req.object).(type) { switch node := (*req.object).(type) {
case shortNode: case *shortNode:
node = node.copy() // Prevents linking all downloaded nodes together.
children = []child{{ children = []child{{
node: &node.Val, node: &node.Val,
depth: req.depth + len(node.Key), depth: req.depth + len(node.Key),
}} }}
case fullNode: case *fullNode:
node = node.copy()
for i := 0; i < 17; i++ { for i := 0; i < 17; i++ {
if node.Children[i] != nil { if node.Children[i] != nil {
children = append(children, child{ children = append(children, child{

View File

@ -59,6 +59,23 @@ type Trie struct {
root node root node
db Database db Database
originalRoot common.Hash originalRoot common.Hash
// Cache generation values.
// cachegen increase by one with each commit operation.
// new nodes are tagged with the current generation and unloaded
// when their generation is older than than cachegen-cachelimit.
cachegen, cachelimit uint16
}
// SetCacheLimit sets the number of 'cache generations' to keep.
// A cache generations is created by a call to Commit.
func (t *Trie) SetCacheLimit(l uint16) {
t.cachelimit = l
}
// newFlag returns the cache flag value for a newly created node.
func (t *Trie) newFlag() nodeFlag {
return nodeFlag{dirty: true, gen: t.cachegen}
} }
// New creates a trie with an existing root node from db. // New creates a trie with an existing root node from db.
@ -117,27 +134,25 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode
return nil, nil, false, nil return nil, nil, false, nil
case valueNode: case valueNode:
return n, n, false, nil return n, n, false, nil
case shortNode: case *shortNode:
if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) { if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) {
// key not found in trie // key not found in trie
return nil, n, false, nil return nil, n, false, nil
} }
value, newnode, didResolve, err = t.tryGet(n.Val, key, pos+len(n.Key)) value, newnode, didResolve, err = t.tryGet(n.Val, key, pos+len(n.Key))
if err == nil && didResolve { if err == nil && didResolve {
n = n.copy()
n.Val = newnode n.Val = newnode
return value, n, didResolve, err
} else {
return value, origNode, didResolve, err
} }
case fullNode: return value, n, didResolve, err
child := n.Children[key[pos]] case *fullNode:
value, newnode, didResolve, err = t.tryGet(child, key, pos+1) value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1)
if err == nil && didResolve { if err == nil && didResolve {
n = n.copy()
n.Children[key[pos]] = newnode n.Children[key[pos]] = newnode
return value, n, didResolve, err
} else {
return value, origNode, didResolve, err
} }
return value, n, didResolve, err
case hashNode: case hashNode:
child, err := t.resolveHash(n, key[:pos], key[pos:]) child, err := t.resolveHash(n, key[:pos], key[pos:])
if err != nil { if err != nil {
@ -196,22 +211,19 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
return true, value, nil return true, value, nil
} }
switch n := n.(type) { switch n := n.(type) {
case shortNode: case *shortNode:
matchlen := prefixLen(key, n.Key) matchlen := prefixLen(key, n.Key)
// If the whole key matches, keep this short node as is // If the whole key matches, keep this short node as is
// and only update the value. // and only update the value.
if matchlen == len(n.Key) { if matchlen == len(n.Key) {
dirty, nn, err := t.insert(n.Val, append(prefix, key[:matchlen]...), key[matchlen:], value) dirty, nn, err := t.insert(n.Val, append(prefix, key[:matchlen]...), key[matchlen:], value)
if err != nil { if !dirty || err != nil {
return false, nil, err return false, n, err
} }
if !dirty { return true, &shortNode{n.Key, nn, t.newFlag()}, nil
return false, n, nil
}
return true, shortNode{n.Key, nn, nil, true}, nil
} }
// Otherwise branch out at the index where they differ. // Otherwise branch out at the index where they differ.
branch := fullNode{dirty: true} branch := &fullNode{flags: t.newFlag()}
var err error var err error
_, branch.Children[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val) _, branch.Children[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val)
if err != nil { if err != nil {
@ -226,21 +238,19 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
return true, branch, nil return true, branch, nil
} }
// Otherwise, replace it with a short node leading up to the branch. // Otherwise, replace it with a short node leading up to the branch.
return true, shortNode{key[:matchlen], branch, nil, true}, nil return true, &shortNode{key[:matchlen], branch, t.newFlag()}, nil
case fullNode: case *fullNode:
dirty, nn, err := t.insert(n.Children[key[0]], append(prefix, key[0]), key[1:], value) dirty, nn, err := t.insert(n.Children[key[0]], append(prefix, key[0]), key[1:], value)
if err != nil { if !dirty || err != nil {
return false, nil, err return false, n, err
} }
if !dirty { n = n.copy()
return false, n, nil n.Children[key[0]], n.flags.hash, n.flags.dirty = nn, nil, true
}
n.Children[key[0]], n.hash, n.dirty = nn, nil, true
return true, n, nil return true, n, nil
case nil: case nil:
return true, shortNode{key, value, nil, true}, nil return true, &shortNode{key, value, t.newFlag()}, nil
case hashNode: case hashNode:
// We've hit a part of the trie that isn't loaded yet. Load // We've hit a part of the trie that isn't loaded yet. Load
@ -251,11 +261,8 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
return false, nil, err return false, nil, err
} }
dirty, nn, err := t.insert(rn, prefix, key, value) dirty, nn, err := t.insert(rn, prefix, key, value)
if err != nil { if !dirty || err != nil {
return false, nil, err return false, rn, err
}
if !dirty {
return false, rn, nil
} }
return true, nn, nil return true, nn, nil
@ -288,7 +295,7 @@ func (t *Trie) TryDelete(key []byte) error {
// nodes on the way up after deleting recursively. // nodes on the way up after deleting recursively.
func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
switch n := n.(type) { switch n := n.(type) {
case shortNode: case *shortNode:
matchlen := prefixLen(key, n.Key) matchlen := prefixLen(key, n.Key)
if matchlen < len(n.Key) { if matchlen < len(n.Key) {
return false, n, nil // don't replace n on mismatch return false, n, nil // don't replace n on mismatch
@ -301,34 +308,29 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
// subtrie must contain at least two other values with keys // subtrie must contain at least two other values with keys
// longer than n.Key. // longer than n.Key.
dirty, child, err := t.delete(n.Val, append(prefix, key[:len(n.Key)]...), key[len(n.Key):]) dirty, child, err := t.delete(n.Val, append(prefix, key[:len(n.Key)]...), key[len(n.Key):])
if err != nil { if !dirty || err != nil {
return false, nil, err return false, n, err
}
if !dirty {
return false, n, nil
} }
switch child := child.(type) { switch child := child.(type) {
case shortNode: case *shortNode:
// Deleting from the subtrie reduced it to another // Deleting from the subtrie reduced it to another
// short node. Merge the nodes to avoid creating a // short node. Merge the nodes to avoid creating a
// shortNode{..., shortNode{...}}. Use concat (which // shortNode{..., shortNode{...}}. Use concat (which
// always creates a new slice) instead of append to // always creates a new slice) instead of append to
// avoid modifying n.Key since it might be shared with // avoid modifying n.Key since it might be shared with
// other nodes. // other nodes.
return true, shortNode{concat(n.Key, child.Key...), child.Val, nil, true}, nil return true, &shortNode{concat(n.Key, child.Key...), child.Val, t.newFlag()}, nil
default: default:
return true, shortNode{n.Key, child, nil, true}, nil return true, &shortNode{n.Key, child, t.newFlag()}, nil
} }
case fullNode: case *fullNode:
dirty, nn, err := t.delete(n.Children[key[0]], append(prefix, key[0]), key[1:]) dirty, nn, err := t.delete(n.Children[key[0]], append(prefix, key[0]), key[1:])
if err != nil { if !dirty || err != nil {
return false, nil, err return false, n, err
} }
if !dirty { n = n.copy()
return false, n, nil n.Children[key[0]], n.flags.hash, n.flags.dirty = nn, nil, true
}
n.Children[key[0]], n.hash, n.dirty = nn, nil, true
// Check how many non-nil entries are left after deleting and // Check how many non-nil entries are left after deleting and
// reduce the full node to a short node if only one entry is // reduce the full node to a short node if only one entry is
@ -362,14 +364,14 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
if cnode, ok := cnode.(shortNode); ok { if cnode, ok := cnode.(*shortNode); ok {
k := append([]byte{byte(pos)}, cnode.Key...) k := append([]byte{byte(pos)}, cnode.Key...)
return true, shortNode{k, cnode.Val, nil, true}, nil return true, &shortNode{k, cnode.Val, t.newFlag()}, nil
} }
} }
// Otherwise, n is replaced by a one-nibble short node // Otherwise, n is replaced by a one-nibble short node
// containing the child. // containing the child.
return true, shortNode{[]byte{byte(pos)}, n.Children[pos], nil, true}, nil return true, &shortNode{[]byte{byte(pos)}, n.Children[pos], t.newFlag()}, nil
} }
// n still contains at least two values and cannot be reduced. // n still contains at least two values and cannot be reduced.
return true, n, nil return true, n, nil
@ -389,11 +391,8 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
return false, nil, err return false, nil, err
} }
dirty, nn, err := t.delete(rn, prefix, key) dirty, nn, err := t.delete(rn, prefix, key)
if err != nil { if !dirty || err != nil {
return false, nil, err return false, rn, err
}
if !dirty {
return false, rn, nil
} }
return true, nn, nil return true, nn, nil
@ -468,6 +467,7 @@ func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) {
return (common.Hash{}), err return (common.Hash{}), err
} }
t.root = cached t.root = cached
t.cachegen++
return common.BytesToHash(hash.(hashNode)), nil return common.BytesToHash(hash.(hashNode)), nil
} }
@ -475,7 +475,7 @@ func (t *Trie) hashRoot(db DatabaseWriter) (node, node, error) {
if t.root == nil { if t.root == nil {
return hashNode(emptyRoot.Bytes()), nil, nil return hashNode(emptyRoot.Bytes()), nil, nil
} }
h := newHasher() h := newHasher(t.cachegen, t.cachelimit)
defer returnHasherToPool(h) defer returnHasherToPool(h)
return h.hash(t.root, db, true) return h.hash(t.root, db, true)
} }

View File

@ -460,8 +460,7 @@ const benchElemCount = 20000
func benchGet(b *testing.B, commit bool) { func benchGet(b *testing.B, commit bool) {
trie := new(Trie) trie := new(Trie)
if commit { if commit {
dir, tmpdb := tempDB() _, tmpdb := tempDB()
defer os.RemoveAll(dir)
trie, _ = New(common.Hash{}, tmpdb) trie, _ = New(common.Hash{}, tmpdb)
} }
k := make([]byte, 32) k := make([]byte, 32)
@ -478,6 +477,13 @@ func benchGet(b *testing.B, commit bool) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
trie.Get(k) trie.Get(k)
} }
b.StopTimer()
if commit {
ldb := trie.db.(*ethdb.LDBDatabase)
ldb.Close()
os.RemoveAll(ldb.Path())
}
} }
func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie {