func TestNull(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := New(common.Hash{}, db) address := common.HexToAddress("0x823140710bf13990e4500136726d8b55") state.CreateAccount(address) //value := common.FromHex("0x823140710bf13990e4500136726d8b55") var value common.Hash state.SetState(address, common.Hash{}, value) state.SyncIntermediate() state.Sync() value = state.GetState(address, common.Hash{}) if !common.EmptyHash(value) { t.Errorf("expected empty hash. got %x", value) } }
// jitCalculateGasAndSize 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. func jitCalculateGasAndSize(env Environment, context *Context, caller ContextRef, instr instruction, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) { var ( gas = new(big.Int) newMemSize *big.Int = new(big.Int) ) err := jitBaseCheck(instr, stack, gas) if err != nil { return nil, nil, err } // stack Check, memory resize & gas phase switch op := instr.op; op { case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) err := stack.require(n) if err != nil { return nil, nil, err } gas.Set(GasFastestStep) case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) err := stack.require(n) if err != nil { return nil, nil, err } gas.Set(GasFastestStep) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) err := stack.require(n + 2) if err != nil { return nil, nil, err } mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] add := new(big.Int) gas.Add(gas, params.LogGas) gas.Add(gas, add.Mul(big.NewInt(int64(n)), params.LogTopicGas)) gas.Add(gas, add.Mul(mSize, params.LogDataGas)) newMemSize = calcMemSize(mStart, mSize) case EXP: gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas)) case SSTORE: err := stack.require(2) if err != nil { return nil, nil, err } var g *big.Int y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] val := statedb.GetState(context.Address(), common.BigToHash(x)) // This checks for 3 scenario's and calculates gas accordingly // 1. From a zero-value address to a non-zero value (NEW VALUE) // 2. From a non-zero value address to a zero-value address (DELETE) // 3. From a nen-zero to a non-zero (CHANGE) if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { // 0 => non 0 g = params.SstoreSetGas } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { statedb.Refund(params.SstoreRefundGas) g = params.SstoreClearGas } else { // non 0 => non 0 (or 0 => 0) g = params.SstoreClearGas } gas.Set(g) case SUICIDE: if !statedb.IsDeleted(context.Address()) { statedb.Refund(params.SuicideRefundGas) } case MLOAD: newMemSize = calcMemSize(stack.peek(), u256(32)) case MSTORE8: newMemSize = calcMemSize(stack.peek(), u256(1)) case MSTORE: newMemSize = calcMemSize(stack.peek(), u256(32)) case RETURN: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) case SHA3: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) words := toWordSize(stack.data[stack.len()-2]) gas.Add(gas, words.Mul(words, params.Sha3WordGas)) case CALLDATACOPY: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3]) gas.Add(gas, words.Mul(words, params.CopyGas)) case CODECOPY: newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) words := toWordSize(stack.data[stack.len()-3]) gas.Add(gas, words.Mul(words, params.CopyGas)) case EXTCODECOPY: newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) words := toWordSize(stack.data[stack.len()-4]) gas.Add(gas, words.Mul(words, params.CopyGas)) case CREATE: newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) case CALL, CALLCODE: gas.Add(gas, stack.data[stack.len()-1]) if op == CALL { if env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil { gas.Add(gas, params.CallNewAccountGas) } } if len(stack.data[stack.len()-3].Bytes()) > 0 { gas.Add(gas, params.CallValueTransferGas) } x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5]) newMemSize = common.BigMax(x, y) } if newMemSize.Cmp(common.Big0) > 0 { newMemSizeWords := toWordSize(newMemSize) newMemSize.Mul(newMemSizeWords, u256(32)) if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { // be careful reusing variables here when changing. // The order has been optimised to reduce allocation oldSize := toWordSize(big.NewInt(int64(mem.Len()))) pow := new(big.Int).Exp(oldSize, common.Big2, Zero) linCoef := oldSize.Mul(oldSize, params.MemoryGas) quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv) oldTotalFee := new(big.Int).Add(linCoef, quadCoef) pow.Exp(newMemSizeWords, common.Big2, Zero) linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas) quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv) newTotalFee := linCoef.Add(linCoef, quadCoef) fee := newTotalFee.Sub(newTotalFee, oldTotalFee) gas.Add(gas, fee) } } return newMemSize, gas, nil }
// findAncestor tries to locate the common ancestor block of the local chain and // a remote peers blockchain. In the general case when our node was in sync and // on the correct chain, checking the top N blocks should already get us a match. // In the rare scenario when we ended up on a long soft fork (i.e. none of the // head blocks match), we do a binary search to find the common ancestor. func (d *Downloader) findAncestor(p *peer) (uint64, error) { glog.V(logger.Debug).Infof("%v: looking for common ancestor", p) // Request out head blocks to short circuit ancestor location head := d.headBlock().NumberU64() from := int64(head) - int64(MaxHashFetch) if from < 0 { from = 0 } go p.getAbsHashes(uint64(from), MaxHashFetch) // Wait for the remote response to the head fetch number, hash := uint64(0), common.Hash{} timeout := time.After(hashTTL) for finished := false; !finished; { select { case <-d.cancelCh: return 0, errCancelHashFetch case hashPack := <-d.hashCh: // Discard anything not from the origin peer if hashPack.peerId != p.id { glog.V(logger.Debug).Infof("Received hashes from incorrect peer(%s)", hashPack.peerId) break } // Make sure the peer actually gave something valid hashes := hashPack.hashes if len(hashes) == 0 { glog.V(logger.Debug).Infof("%v: empty head hash set", p) return 0, errEmptyHashSet } // Check if a common ancestor was found finished = true for i := len(hashes) - 1; i >= 0; i-- { if d.hasBlock(hashes[i]) { number, hash = uint64(from)+uint64(i), hashes[i] break } } case <-d.blockCh: // Out of bounds blocks received, ignore them case <-timeout: glog.V(logger.Debug).Infof("%v: head hash timeout", p) return 0, errTimeout } } // If the head fetch already found an ancestor, return if !common.EmptyHash(hash) { glog.V(logger.Debug).Infof("%v: common ancestor: #%d [%x]", p, number, hash[:4]) return number, nil } // Ancestor not found, we need to binary search over our chain start, end := uint64(0), head for start+1 < end { // Split our chain interval in two, and request the hash to cross check check := (start + end) / 2 timeout := time.After(hashTTL) go p.getAbsHashes(uint64(check), 1) // Wait until a reply arrives to this request for arrived := false; !arrived; { select { case <-d.cancelCh: return 0, errCancelHashFetch case hashPack := <-d.hashCh: // Discard anything not from the origin peer if hashPack.peerId != p.id { glog.V(logger.Debug).Infof("Received hashes from incorrect peer(%s)", hashPack.peerId) break } // Make sure the peer actually gave something valid hashes := hashPack.hashes if len(hashes) != 1 { glog.V(logger.Debug).Infof("%v: invalid search hash set (%d)", p, len(hashes)) return 0, errBadPeer } arrived = true // Modify the search interval based on the response block := d.getBlock(hashes[0]) if block == nil { end = check break } if block.NumberU64() != check { glog.V(logger.Debug).Infof("%v: non requested hash #%d [%x], instead of #%d", p, block.NumberU64(), block.Hash().Bytes()[:4], check) return 0, errBadPeer } start = check case <-d.blockCh: // Out of bounds blocks received, ignore them case <-timeout: glog.V(logger.Debug).Infof("%v: search hash timeout", p) return 0, errTimeout } } } return start, nil }