diff options
author | Janos Guljas <janos@resenje.org> | 2017-12-13 17:23:11 +0800 |
---|---|---|
committer | Janos Guljas <janos@resenje.org> | 2017-12-13 17:40:39 +0800 |
commit | 19982f946735948478b6b7e7706f1b615f171d0d (patch) | |
tree | cbacbdb6f9e6e731c2ebc17bad74e875f4d8ea8b /core | |
parent | 1dc19de5da64962a98a37bbc7b93a3895d2eb6e6 (diff) | |
parent | 32516c768ec09e2a71cab5983d2c8b8ae5d92fc7 (diff) | |
download | dexon-19982f946735948478b6b7e7706f1b615f171d0d.tar dexon-19982f946735948478b6b7e7706f1b615f171d0d.tar.gz dexon-19982f946735948478b6b7e7706f1b615f171d0d.tar.bz2 dexon-19982f946735948478b6b7e7706f1b615f171d0d.tar.lz dexon-19982f946735948478b6b7e7706f1b615f171d0d.tar.xz dexon-19982f946735948478b6b7e7706f1b615f171d0d.tar.zst dexon-19982f946735948478b6b7e7706f1b615f171d0d.zip |
swarm, cmd/swarm: Merge branch 'master' into multiple-ens-endpoints
Merge with changes that implement config file PR #15548.
Field *EnsApi string* in swarm/api.Config is replaced with
*EnsAPIs []string*.
A new field *EnsDisabled bool* is added to swarm/api.Config for
easy way to disable ENS resolving with config file.
Signature of function swarm.NewSwarm is changed and simplified.
Diffstat (limited to 'core')
-rw-r--r-- | core/chain_indexer.go | 2 | ||||
-rw-r--r-- | core/state/statedb.go | 2 | ||||
-rw-r--r-- | core/state/statedb_test.go | 51 | ||||
-rw-r--r-- | core/tx_pool_test.go | 2 | ||||
-rw-r--r-- | core/types/transaction.go | 2 | ||||
-rw-r--r-- | core/vm/evm.go | 4 | ||||
-rw-r--r-- | core/vm/gas_table.go | 46 | ||||
-rw-r--r-- | core/vm/instructions.go | 76 | ||||
-rw-r--r-- | core/vm/interpreter.go | 28 | ||||
-rw-r--r-- | core/vm/logger.go | 26 | ||||
-rw-r--r-- | core/vm/logger_test.go | 24 |
11 files changed, 114 insertions, 149 deletions
diff --git a/core/chain_indexer.go b/core/chain_indexer.go index 7e7500dc8..7fb184aaa 100644 --- a/core/chain_indexer.go +++ b/core/chain_indexer.go @@ -230,7 +230,7 @@ func (c *ChainIndexer) newHead(head uint64, reorg bool) { if changed < c.storedSections { c.setValidSections(changed) } - // Update the new head number to te finalized section end and notify children + // Update the new head number to the finalized section end and notify children head = changed * c.sectionSize if head < c.cascadedHead { diff --git a/core/state/statedb.go b/core/state/statedb.go index 002fa6249..de9fb367d 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -453,7 +453,7 @@ func (self *StateDB) Copy() *StateDB { // Copy all the basic fields, initialize the memory ones state := &StateDB{ db: self.db, - trie: self.trie, + trie: self.db.CopyTrie(self.trie), stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)), stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), refund: new(big.Int).Set(self.refund), diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index b2bd18e65..e9944cd74 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -117,6 +117,57 @@ func TestIntermediateLeaks(t *testing.T) { } } +// TestCopy tests that copying a statedb object indeed makes the original and +// the copy independent of each other. This test is a regression test against +// https://github.com/ethereum/go-ethereum/pull/15549. +func TestCopy(t *testing.T) { + // Create a random state test to copy and modify "independently" + mem, _ := ethdb.NewMemDatabase() + orig, _ := New(common.Hash{}, NewDatabase(mem)) + + for i := byte(0); i < 255; i++ { + obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) + obj.AddBalance(big.NewInt(int64(i))) + orig.updateStateObject(obj) + } + orig.Finalise(false) + + // Copy the state, modify both in-memory + copy := orig.Copy() + + for i := byte(0); i < 255; i++ { + origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) + copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) + + origObj.AddBalance(big.NewInt(2 * int64(i))) + copyObj.AddBalance(big.NewInt(3 * int64(i))) + + orig.updateStateObject(origObj) + copy.updateStateObject(copyObj) + } + // Finalise the changes on both concurrently + done := make(chan struct{}) + go func() { + orig.Finalise(true) + close(done) + }() + copy.Finalise(true) + <-done + + // Verify that the two states have been updated independently + for i := byte(0); i < 255; i++ { + origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) + copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) + + if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { + t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) + } + if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 { + t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) + } + } +} + func TestSnapshotRandom(t *testing.T) { config := &quick.Config{MaxCount: 1000} err := quick.Check((*snapshotTest).run, config) diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index e9ecbb933..21171a737 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -1266,7 +1266,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { // Tests that when the pool reaches its global transaction limit, underpriced // transactions are gradually shifted out for more expensive ones and any gapped -// pending transactions are moved into te queue. +// pending transactions are moved into the queue. // // Note, local transactions are never allowed to be dropped. func TestTransactionPoolUnderpricing(t *testing.T) { diff --git a/core/types/transaction.go b/core/types/transaction.go index a46521236..7e2933bb1 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -137,7 +137,7 @@ func isProtectedV(V *big.Int) bool { return true } -// DecodeRLP implements rlp.Encoder +// EncodeRLP implements rlp.Encoder func (tx *Transaction) EncodeRLP(w io.Writer) error { return rlp.Encode(w, &tx.data) } diff --git a/core/vm/evm.go b/core/vm/evm.go index 093c7d4c1..344435f73 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -104,6 +104,10 @@ type EVM struct { // abort is used to abort the EVM calling operations // NOTE: must be set atomically abort int32 + // callGasTemp holds the gas available for the current call. This is needed because the + // available gas is calculated in gasCall* according to the 63/64 rule and later + // applied in opCall*. + callGasTemp uint64 } // NewEVM retutrns a new EVM . The returned EVM is not thread safe and should diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 0d8e295a5..ff109af57 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -342,19 +342,11 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return 0, errGasUintOverflow } - cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } - // 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] = new(big.Int).SetUint64(cg) - - if gas, overflow = math.SafeAdd(gas, cg); overflow { + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil @@ -374,19 +366,11 @@ func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, return 0, errGasUintOverflow } - cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } - // 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] = new(big.Int).SetUint64(cg) - - if gas, overflow = math.SafeAdd(gas, cg); overflow { + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil @@ -436,18 +420,11 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St return 0, errGasUintOverflow } - cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } - // 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] = new(big.Int).SetUint64(cg) - - if gas, overflow = math.SafeAdd(gas, cg); overflow { + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil @@ -463,18 +440,11 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stac return 0, errGasUintOverflow } - cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } - // 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] = new(big.Int).SetUint64(cg) - - if gas, overflow = math.SafeAdd(gas, cg); overflow { + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil diff --git a/core/vm/instructions.go b/core/vm/instructions.go index b6d6e22c4..1d1585fca 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -603,24 +603,20 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S } func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - gas := stack.pop().Uint64() - // pop gas and value of the stack. - addr, value := stack.pop(), stack.pop() + // Pop gas. The actual gas in in evm.callGasTemp. + evm.interpreter.intPool.put(stack.pop()) + gas := evm.callGasTemp + // Pop other call parameters. + addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) value = math.U256(value) - // pop input size and offset - inOffset, inSize := stack.pop(), stack.pop() - // pop return size and offset - retOffset, retSize := stack.pop(), stack.pop() - - address := common.BigToAddress(addr) - - // Get the arguments from the memory + // Get the arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := evm.Call(contract, address, args, gas, value) + ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value) if err != nil { stack.push(new(big.Int)) } else { @@ -636,25 +632,20 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta } func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - gas := stack.pop().Uint64() - // pop gas and value of the stack. - addr, value := stack.pop(), stack.pop() + // Pop gas. The actual gas is in evm.callGasTemp. + evm.interpreter.intPool.put(stack.pop()) + gas := evm.callGasTemp + // Pop other call parameters. + addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) value = math.U256(value) - // pop input size and offset - inOffset, inSize := stack.pop(), stack.pop() - // pop return size and offset - retOffset, retSize := stack.pop(), stack.pop() - - address := common.BigToAddress(addr) - - // Get the arguments from the memory + // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) if value.Sign() != 0 { gas += params.CallStipend } - - ret, returnGas, err := evm.CallCode(contract, address, args, gas, value) + ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value) if err != nil { stack.push(new(big.Int)) } else { @@ -670,9 +661,13 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack } func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() - - toAddr := common.BigToAddress(to) + // Pop gas. The actual gas is in evm.callGasTemp. + evm.interpreter.intPool.put(stack.pop()) + gas := evm.callGasTemp + // Pop other call parameters. + addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) + // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas) @@ -682,30 +677,25 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st stack.push(big.NewInt(1)) } if err == nil || err == errExecutionReverted { - memory.Set(outOffset.Uint64(), outSize.Uint64(), ret) + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize) + evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // pop gas - gas := stack.pop().Uint64() - // pop address - addr := stack.pop() - // pop input size and offset - inOffset, inSize := stack.pop(), stack.pop() - // pop return size and offset - retOffset, retSize := stack.pop(), stack.pop() - - address := common.BigToAddress(addr) - - // Get the arguments from the memory + // Pop gas. The actual gas is in evm.callGasTemp. + evm.interpreter.intPool.put(stack.pop()) + gas := evm.callGasTemp + // Pop other call parameters. + addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + toAddr := common.BigToAddress(addr) + // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := evm.StaticCall(contract, address, args, gas) + ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas) if err != nil { stack.push(new(big.Int)) } else { diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index ea5468f90..ac6000f97 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -138,16 +138,15 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret pc = uint64(0) // program counter cost uint64 // copies used by tracer - stackCopy = newstack() // stackCopy needed for Tracer since stack is mutated by 63/64 gas rule - pcCopy uint64 // needed for the deferred Tracer - gasCopy uint64 // for Tracer to log gas remaining before execution - logged bool // deferred Tracer should ignore already logged steps + pcCopy uint64 // needed for the deferred Tracer + gasCopy uint64 // for Tracer to log gas remaining before execution + logged bool // deferred Tracer should ignore already logged steps ) contract.Input = input defer func() { if err != nil && !logged && in.cfg.Debug { - in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stackCopy, contract, in.evm.depth, err) + in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) } }() @@ -156,21 +155,14 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret // the execution of one of the operations or until the done flag is set by the // parent context. for atomic.LoadInt32(&in.evm.abort) == 0 { - // Get the memory location of pc - op = contract.GetOp(pc) - if in.cfg.Debug { - logged = false - pcCopy = pc - gasCopy = contract.Gas - stackCopy = newstack() - for _, val := range stack.data { - stackCopy.push(val) - } + // Capture pre-execution values for tracing. + logged, pcCopy, gasCopy = false, pc, contract.Gas } - // Get the operation from the jump table matching the opcode and validate the - // stack and make sure there enough stack items available to perform the operation + // Get the operation from the jump table and validate the stack to ensure there are + // enough stack items available to perform the operation. + op = contract.GetOp(pc) operation := in.cfg.JumpTable[op] if !operation.valid { return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) @@ -211,7 +203,7 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret } if in.cfg.Debug { - in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stackCopy, contract, in.evm.depth, err) + in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) logged = true } diff --git a/core/vm/logger.go b/core/vm/logger.go index 623c0d563..75309da92 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -45,7 +45,6 @@ type LogConfig struct { DisableMemory bool // disable memory capture DisableStack bool // disable stack capture DisableStorage bool // disable storage capture - FullStorage bool // show full storage (slow) Limit int // maximum length of output, but zero means unlimited } @@ -136,14 +135,13 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui ) l.changedValues[contract.Address()][address] = value } - // copy a snapstot of the current memory state to a new buffer + // Copy a snapstot of the current memory state to a new buffer var mem []byte if !l.cfg.DisableMemory { mem = make([]byte, len(memory.Data())) copy(mem, memory.Data()) } - - // copy a snapshot of the current stack state to a new buffer + // Copy a snapshot of the current stack state to a new buffer var stck []*big.Int if !l.cfg.DisableStack { stck = make([]*big.Int, len(stack.Data())) @@ -151,26 +149,10 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui stck[i] = new(big.Int).Set(item) } } - - // Copy the storage based on the settings specified in the log config. If full storage - // is disabled (default) we can use the simple Storage.Copy method, otherwise we use - // the state object to query for all values (slow process). + // Copy a snapshot of the current storage to a new container var storage Storage if !l.cfg.DisableStorage { - if l.cfg.FullStorage { - storage = make(Storage) - // Get the contract account and loop over each storage entry. This may involve looping over - // the trie and is a very expensive process. - - env.StateDB.ForEachStorage(contract.Address(), func(key, value common.Hash) bool { - storage[key] = value - // Return true, indicating we'd like to continue. - return true - }) - } else { - // copy a snapshot of the current storage to a new container. - storage = l.changedValues[contract.Address()].Copy() - } + storage = l.changedValues[contract.Address()].Copy() } // create a new snaptshot of the EVM. log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, err} diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index b6fa31132..915f7177e 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -63,32 +63,8 @@ func TestStoreCapture(t *testing.T) { if len(logger.changedValues[contract.Address()]) == 0 { t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()])) } - exp := common.BigToHash(big.NewInt(1)) if logger.changedValues[contract.Address()][index] != exp { t.Errorf("expected %x, got %x", exp, logger.changedValues[contract.Address()][index]) } } - -func TestStorageCapture(t *testing.T) { - t.Skip("implementing this function is difficult. it requires all sort of interfaces to be implemented which isn't trivial. The value (the actual test) isn't worth it") - var ( - ref = &dummyContractRef{} - contract = NewContract(ref, ref, new(big.Int), 0) - env = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) - logger = NewStructLogger(nil) - mem = NewMemory() - stack = newstack() - ) - - logger.CaptureState(env, 0, STOP, 0, 0, mem, stack, contract, 0, nil) - if ref.calledForEach { - t.Error("didn't expect for each to be called") - } - - logger = NewStructLogger(&LogConfig{FullStorage: true}) - logger.CaptureState(env, 0, STOP, 0, 0, mem, stack, contract, 0, nil) - if !ref.calledForEach { - t.Error("expected for each to be called") - } -} |