forked from cerc-io/plugeth
Merge pull request #1282 from obscuren/state-cleanup
core/state: cleanup & optimisations
This commit is contained in:
commit
2cea410656
@ -62,6 +62,10 @@ func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
return reflect.ValueOf(h)
|
||||
}
|
||||
|
||||
func EmptyHash(h Hash) bool {
|
||||
return h == Hash{}
|
||||
}
|
||||
|
||||
/////////// Address
|
||||
func BytesToAddress(b []byte) Address {
|
||||
var a Address
|
||||
|
@ -185,7 +185,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
||||
state := state.New(parent.Root(), sm.db)
|
||||
|
||||
// Block validation
|
||||
if err = sm.ValidateHeader(block.Header(), parent.Header(), false); err != nil {
|
||||
if err = ValidateHeader(sm.Pow, block.Header(), parent.Header(), false); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -246,12 +246,6 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
||||
return
|
||||
}
|
||||
|
||||
// store the receipts
|
||||
err = putReceipts(sm.extraDb, block.Hash(), receipts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sync the current block's state to the database
|
||||
state.Sync()
|
||||
|
||||
@ -260,76 +254,12 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
||||
putTx(sm.extraDb, tx, block, uint64(i))
|
||||
}
|
||||
|
||||
receiptsRlp := receipts.RlpEncode()
|
||||
/*if len(receipts) > 0 {
|
||||
glog.V(logger.Info).Infof("Saving %v receipts, rlp len is %v\n", len(receipts), len(receiptsRlp))
|
||||
}*/
|
||||
sm.extraDb.Put(append(receiptsPre, block.Hash().Bytes()...), receiptsRlp)
|
||||
// store the receipts
|
||||
putReceipts(sm.extraDb, block.Hash(), receipts)
|
||||
|
||||
return state.Logs(), nil
|
||||
}
|
||||
|
||||
// See YP section 4.3.4. "Block Header Validity"
|
||||
// Validates a block. Returns an error if the block is invalid.
|
||||
func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow bool) error {
|
||||
if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
|
||||
return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
|
||||
}
|
||||
|
||||
expd := CalcDifficulty(block, parent)
|
||||
if expd.Cmp(block.Difficulty) != 0 {
|
||||
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
|
||||
}
|
||||
|
||||
a := new(big.Int).Sub(block.GasLimit, parent.GasLimit)
|
||||
a.Abs(a)
|
||||
b := new(big.Int).Div(parent.GasLimit, params.GasLimitBoundDivisor)
|
||||
if !(a.Cmp(b) < 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) {
|
||||
return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b)
|
||||
}
|
||||
|
||||
if int64(block.Time) > time.Now().Unix() {
|
||||
return BlockFutureErr
|
||||
}
|
||||
|
||||
if new(big.Int).Sub(block.Number, parent.Number).Cmp(big.NewInt(1)) != 0 {
|
||||
return BlockNumberErr
|
||||
}
|
||||
|
||||
if block.Time <= parent.Time {
|
||||
return BlockEqualTSErr //ValidationError("Block timestamp equal or less than previous block (%v - %v)", block.Time, parent.Time)
|
||||
}
|
||||
|
||||
if checkPow {
|
||||
// Verify the nonce of the block. Return an error if it's not valid
|
||||
if !sm.Pow.Verify(types.NewBlockWithHeader(block)) {
|
||||
return ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func AccumulateRewards(statedb *state.StateDB, block *types.Block) {
|
||||
reward := new(big.Int).Set(BlockReward)
|
||||
|
||||
for _, uncle := range block.Uncles() {
|
||||
num := new(big.Int).Add(big.NewInt(8), uncle.Number)
|
||||
num.Sub(num, block.Number())
|
||||
|
||||
r := new(big.Int)
|
||||
r.Mul(BlockReward, num)
|
||||
r.Div(r, big.NewInt(8))
|
||||
|
||||
statedb.AddBalance(uncle.Coinbase, r)
|
||||
|
||||
reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
|
||||
}
|
||||
|
||||
// Get the account associated with the coinbase
|
||||
statedb.AddBalance(block.Header().Coinbase, reward)
|
||||
}
|
||||
|
||||
func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error {
|
||||
ancestors := set.New()
|
||||
uncles := set.New()
|
||||
@ -367,7 +297,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
|
||||
return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4])
|
||||
}
|
||||
|
||||
if err := sm.ValidateHeader(uncle, ancestorHeaders[uncle.ParentHash], true); err != nil {
|
||||
if err := ValidateHeader(sm.Pow, uncle, ancestorHeaders[uncle.ParentHash], true); err != nil {
|
||||
return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
|
||||
}
|
||||
}
|
||||
@ -404,6 +334,67 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
|
||||
return state.Logs(), nil
|
||||
}
|
||||
|
||||
// See YP section 4.3.4. "Block Header Validity"
|
||||
// Validates a block. Returns an error if the block is invalid.
|
||||
func ValidateHeader(pow pow.PoW, block, parent *types.Header, checkPow bool) error {
|
||||
if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
|
||||
return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
|
||||
}
|
||||
|
||||
expd := CalcDifficulty(block, parent)
|
||||
if expd.Cmp(block.Difficulty) != 0 {
|
||||
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
|
||||
}
|
||||
|
||||
a := new(big.Int).Sub(block.GasLimit, parent.GasLimit)
|
||||
a.Abs(a)
|
||||
b := new(big.Int).Div(parent.GasLimit, params.GasLimitBoundDivisor)
|
||||
if !(a.Cmp(b) < 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) {
|
||||
return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b)
|
||||
}
|
||||
|
||||
if int64(block.Time) > time.Now().Unix() {
|
||||
return BlockFutureErr
|
||||
}
|
||||
|
||||
if new(big.Int).Sub(block.Number, parent.Number).Cmp(big.NewInt(1)) != 0 {
|
||||
return BlockNumberErr
|
||||
}
|
||||
|
||||
if block.Time <= parent.Time {
|
||||
return BlockEqualTSErr //ValidationError("Block timestamp equal or less than previous block (%v - %v)", block.Time, parent.Time)
|
||||
}
|
||||
|
||||
if checkPow {
|
||||
// Verify the nonce of the block. Return an error if it's not valid
|
||||
if !pow.Verify(types.NewBlockWithHeader(block)) {
|
||||
return ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func AccumulateRewards(statedb *state.StateDB, block *types.Block) {
|
||||
reward := new(big.Int).Set(BlockReward)
|
||||
|
||||
for _, uncle := range block.Uncles() {
|
||||
num := new(big.Int).Add(big.NewInt(8), uncle.Number)
|
||||
num.Sub(num, block.Number())
|
||||
|
||||
r := new(big.Int)
|
||||
r.Mul(BlockReward, num)
|
||||
r.Div(r, big.NewInt(8))
|
||||
|
||||
statedb.AddBalance(uncle.Coinbase, r)
|
||||
|
||||
reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
|
||||
}
|
||||
|
||||
// Get the account associated with the coinbase
|
||||
statedb.AddBalance(block.Header().Coinbase, reward)
|
||||
}
|
||||
|
||||
func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Receipts, err error) {
|
||||
var rdata []byte
|
||||
rdata, err = db.Get(append(receiptsPre, bhash[:]...))
|
||||
|
@ -26,18 +26,20 @@ func proc() (*BlockProcessor, *ChainManager) {
|
||||
}
|
||||
|
||||
func TestNumber(t *testing.T) {
|
||||
bp, chain := proc()
|
||||
_, chain := proc()
|
||||
block1 := chain.NewBlock(common.Address{})
|
||||
block1.Header().Number = big.NewInt(3)
|
||||
block1.Header().Time--
|
||||
|
||||
err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header(), false)
|
||||
pow := ezp.New()
|
||||
|
||||
err := ValidateHeader(pow, block1.Header(), chain.Genesis().Header(), false)
|
||||
if err != BlockNumberErr {
|
||||
t.Errorf("expected block number error %v", err)
|
||||
}
|
||||
|
||||
block1 = chain.NewBlock(common.Address{})
|
||||
err = bp.ValidateHeader(block1.Header(), chain.Genesis().Header(), false)
|
||||
err = ValidateHeader(pow, block1.Header(), chain.Genesis().Header(), false)
|
||||
if err == BlockNumberErr {
|
||||
t.Errorf("didn't expect block number error")
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ func (self *StateDB) RawDump() World {
|
||||
account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: common.Bytes2Hex(stateObject.Root()), CodeHash: common.Bytes2Hex(stateObject.codeHash)}
|
||||
account.Storage = make(map[string]string)
|
||||
|
||||
storageIt := stateObject.State.trie.Iterator()
|
||||
storageIt := stateObject.trie.Iterator()
|
||||
for storageIt.Next() {
|
||||
account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
||||
}
|
||||
@ -54,8 +54,8 @@ func (self *StateDB) Dump() []byte {
|
||||
|
||||
// Debug stuff
|
||||
func (self *StateObject) CreateOutputForDiff() {
|
||||
fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.balance.Bytes(), self.nonce)
|
||||
it := self.State.trie.Iterator()
|
||||
fmt.Printf("%x %x %x %x\n", self.Address(), self.Root(), self.balance.Bytes(), self.nonce)
|
||||
it := self.trie.Iterator()
|
||||
for it.Next() {
|
||||
fmt.Printf("%x %x\n", it.Key, it.Value)
|
||||
}
|
||||
|
@ -19,11 +19,11 @@ func (self Code) String() string {
|
||||
return string(self) //strings.Join(Disassemble(self), " ")
|
||||
}
|
||||
|
||||
type Storage map[string]*common.Value
|
||||
type Storage map[string]common.Hash
|
||||
|
||||
func (self Storage) String() (str string) {
|
||||
for key, value := range self {
|
||||
str += fmt.Sprintf("%X : %X\n", key, value.Bytes())
|
||||
str += fmt.Sprintf("%X : %X\n", key, value)
|
||||
}
|
||||
|
||||
return
|
||||
@ -32,7 +32,6 @@ func (self Storage) String() (str string) {
|
||||
func (self Storage) Copy() Storage {
|
||||
cpy := make(Storage)
|
||||
for key, value := range self {
|
||||
// XXX Do we need a 'value' copy or is this sufficient?
|
||||
cpy[key] = value
|
||||
}
|
||||
|
||||
@ -42,8 +41,7 @@ func (self Storage) Copy() Storage {
|
||||
type StateObject struct {
|
||||
// State database for storing state changes
|
||||
db common.Database
|
||||
// The state object
|
||||
State *StateDB
|
||||
trie *trie.SecureTrie
|
||||
|
||||
// Address belonging to this account
|
||||
address common.Address
|
||||
@ -76,7 +74,6 @@ type StateObject struct {
|
||||
|
||||
func (self *StateObject) Reset() {
|
||||
self.storage = make(Storage)
|
||||
self.State.Reset()
|
||||
}
|
||||
|
||||
func NewStateObject(address common.Address, db common.Database) *StateObject {
|
||||
@ -84,7 +81,7 @@ func NewStateObject(address common.Address, db common.Database) *StateObject {
|
||||
//address := common.ToAddress(addr)
|
||||
|
||||
object := &StateObject{db: db, address: address, balance: new(big.Int), gasPool: new(big.Int), dirty: true}
|
||||
object.State = New(common.Hash{}, db) //New(trie.New(common.Config.Db, ""))
|
||||
object.trie = trie.NewSecure((common.Hash{}).Bytes(), db)
|
||||
object.storage = make(Storage)
|
||||
object.gasPool = new(big.Int)
|
||||
object.prepaid = new(big.Int)
|
||||
@ -111,8 +108,8 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db common.Data
|
||||
object.nonce = extobject.Nonce
|
||||
object.balance = extobject.Balance
|
||||
object.codeHash = extobject.CodeHash
|
||||
object.State = New(extobject.Root, db)
|
||||
object.storage = make(map[string]*common.Value)
|
||||
object.trie = trie.NewSecure(extobject.Root[:], db)
|
||||
object.storage = make(map[string]common.Hash)
|
||||
object.gasPool = new(big.Int)
|
||||
object.prepaid = new(big.Int)
|
||||
object.code, _ = db.Get(extobject.CodeHash)
|
||||
@ -129,35 +126,31 @@ func (self *StateObject) MarkForDeletion() {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *StateObject) getAddr(addr common.Hash) *common.Value {
|
||||
return common.NewValueFromBytes([]byte(c.State.trie.Get(addr[:])))
|
||||
func (c *StateObject) getAddr(addr common.Hash) common.Hash {
|
||||
var ret []byte
|
||||
rlp.DecodeBytes(c.trie.Get(addr[:]), &ret)
|
||||
return common.BytesToHash(ret)
|
||||
}
|
||||
|
||||
func (c *StateObject) setAddr(addr []byte, value interface{}) {
|
||||
c.State.trie.Update(addr, common.Encode(value))
|
||||
func (c *StateObject) setAddr(addr []byte, value common.Hash) {
|
||||
v, err := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
|
||||
if err != nil {
|
||||
// if RLPing failed we better panic and not fail silently. This would be considered a consensus issue
|
||||
panic(err)
|
||||
}
|
||||
|
||||
func (self *StateObject) GetStorage(key *big.Int) *common.Value {
|
||||
fmt.Printf("%v: get %v %v", self.address.Hex(), key)
|
||||
return self.GetState(common.BytesToHash(key.Bytes()))
|
||||
}
|
||||
|
||||
func (self *StateObject) SetStorage(key *big.Int, value *common.Value) {
|
||||
fmt.Printf("%v: set %v -> %v", self.address.Hex(), key, value)
|
||||
self.SetState(common.BytesToHash(key.Bytes()), value)
|
||||
c.trie.Update(addr, v)
|
||||
}
|
||||
|
||||
func (self *StateObject) Storage() Storage {
|
||||
return self.storage
|
||||
}
|
||||
|
||||
func (self *StateObject) GetState(key common.Hash) *common.Value {
|
||||
func (self *StateObject) GetState(key common.Hash) common.Hash {
|
||||
strkey := key.Str()
|
||||
value := self.storage[strkey]
|
||||
if value == nil {
|
||||
value, exists := self.storage[strkey]
|
||||
if !exists {
|
||||
value = self.getAddr(key)
|
||||
|
||||
if !value.IsNil() {
|
||||
if (value != common.Hash{}) {
|
||||
self.storage[strkey] = value
|
||||
}
|
||||
}
|
||||
@ -165,15 +158,16 @@ func (self *StateObject) GetState(key common.Hash) *common.Value {
|
||||
return value
|
||||
}
|
||||
|
||||
func (self *StateObject) SetState(k common.Hash, value *common.Value) {
|
||||
self.storage[k.Str()] = value.Copy()
|
||||
func (self *StateObject) SetState(k, value common.Hash) {
|
||||
self.storage[k.Str()] = value
|
||||
self.dirty = true
|
||||
}
|
||||
|
||||
func (self *StateObject) Sync() {
|
||||
// Update updates the current cached storage to the trie
|
||||
func (self *StateObject) Update() {
|
||||
for key, value := range self.storage {
|
||||
if value.Len() == 0 {
|
||||
self.State.trie.Delete([]byte(key))
|
||||
if (value == common.Hash{}) {
|
||||
self.trie.Delete([]byte(key))
|
||||
continue
|
||||
}
|
||||
|
||||
@ -266,9 +260,7 @@ func (self *StateObject) Copy() *StateObject {
|
||||
stateObject.balance.Set(self.balance)
|
||||
stateObject.codeHash = common.CopyBytes(self.codeHash)
|
||||
stateObject.nonce = self.nonce
|
||||
if self.State != nil {
|
||||
stateObject.State = self.State.Copy()
|
||||
}
|
||||
stateObject.trie = self.trie
|
||||
stateObject.code = common.CopyBytes(self.code)
|
||||
stateObject.initCode = common.CopyBytes(self.initCode)
|
||||
stateObject.storage = self.storage.Copy()
|
||||
@ -306,11 +298,11 @@ func (c *StateObject) Init() Code {
|
||||
}
|
||||
|
||||
func (self *StateObject) Trie() *trie.SecureTrie {
|
||||
return self.State.trie
|
||||
return self.trie
|
||||
}
|
||||
|
||||
func (self *StateObject) Root() []byte {
|
||||
return self.Trie().Root()
|
||||
return self.trie.Root()
|
||||
}
|
||||
|
||||
func (self *StateObject) Code() []byte {
|
||||
@ -342,10 +334,10 @@ func (self *StateObject) EachStorage(cb func(key, value []byte)) {
|
||||
cb([]byte(h), v.Bytes())
|
||||
}
|
||||
|
||||
it := self.State.trie.Iterator()
|
||||
it := self.trie.Iterator()
|
||||
for it.Next() {
|
||||
// ignore cached values
|
||||
key := self.State.trie.GetKey(it.Key)
|
||||
key := self.trie.GetKey(it.Key)
|
||||
if _, ok := self.storage[string(key)]; !ok {
|
||||
cb(key, it.Value)
|
||||
}
|
||||
@ -369,8 +361,8 @@ func (c *StateObject) RlpDecode(data []byte) {
|
||||
decoder := common.NewValueFromBytes(data)
|
||||
c.nonce = decoder.Get(0).Uint()
|
||||
c.balance = decoder.Get(1).BigInt()
|
||||
c.State = New(common.BytesToHash(decoder.Get(2).Bytes()), c.db) //New(trie.New(common.Config.Db, decoder.Get(2).Interface()))
|
||||
c.storage = make(map[string]*common.Value)
|
||||
c.trie = trie.NewSecure(decoder.Get(2).Bytes(), c.db)
|
||||
c.storage = make(map[string]common.Hash)
|
||||
c.gasPool = new(big.Int)
|
||||
|
||||
c.codeHash = decoder.Get(3).Bytes()
|
||||
|
@ -70,37 +70,34 @@ func TestNull(t *testing.T) {
|
||||
address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")
|
||||
state.CreateAccount(address)
|
||||
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
|
||||
value := make([]byte, 16)
|
||||
var value common.Hash
|
||||
state.SetState(address, common.Hash{}, value)
|
||||
state.Update()
|
||||
state.Sync()
|
||||
value = state.GetState(address, common.Hash{})
|
||||
if !common.EmptyHash(value) {
|
||||
t.Errorf("expected empty hash. got %x", value)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateSuite) TestSnapshot(c *checker.C) {
|
||||
stateobjaddr := toAddr([]byte("aa"))
|
||||
storageaddr := common.Big("0")
|
||||
data1 := common.NewValue(42)
|
||||
data2 := common.NewValue(43)
|
||||
var storageaddr common.Hash
|
||||
data1 := common.BytesToHash([]byte{42})
|
||||
data2 := common.BytesToHash([]byte{43})
|
||||
|
||||
// get state object
|
||||
stateObject := s.state.GetOrNewStateObject(stateobjaddr)
|
||||
// set inital state object value
|
||||
stateObject.SetStorage(storageaddr, data1)
|
||||
s.state.SetState(stateobjaddr, storageaddr, data1)
|
||||
// get snapshot of current state
|
||||
snapshot := s.state.Copy()
|
||||
|
||||
// get state object. is this strictly necessary?
|
||||
stateObject = s.state.GetStateObject(stateobjaddr)
|
||||
// set new state object value
|
||||
stateObject.SetStorage(storageaddr, data2)
|
||||
s.state.SetState(stateobjaddr, storageaddr, data2)
|
||||
// restore snapshot
|
||||
s.state.Set(snapshot)
|
||||
|
||||
// get state object
|
||||
stateObject = s.state.GetStateObject(stateobjaddr)
|
||||
// get state storage value
|
||||
res := stateObject.GetStorage(storageaddr)
|
||||
res := s.state.GetState(stateobjaddr, storageaddr)
|
||||
|
||||
c.Assert(data1, checker.DeepEquals, res)
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ type StateDB struct {
|
||||
|
||||
stateObjects map[string]*StateObject
|
||||
|
||||
refund map[string]*big.Int
|
||||
refund *big.Int
|
||||
|
||||
thash, bhash common.Hash
|
||||
txIndex int
|
||||
@ -31,7 +31,7 @@ type StateDB struct {
|
||||
// Create a new state from a given trie
|
||||
func New(root common.Hash, db common.Database) *StateDB {
|
||||
trie := trie.NewSecure(root[:], db)
|
||||
return &StateDB{db: db, trie: trie, stateObjects: make(map[string]*StateObject), refund: make(map[string]*big.Int), logs: make(map[common.Hash]Logs)}
|
||||
return &StateDB{db: db, trie: trie, stateObjects: make(map[string]*StateObject), refund: new(big.Int), logs: make(map[common.Hash]Logs)}
|
||||
}
|
||||
|
||||
func (self *StateDB) PrintRoot() {
|
||||
@ -63,12 +63,8 @@ func (self *StateDB) Logs() Logs {
|
||||
return logs
|
||||
}
|
||||
|
||||
func (self *StateDB) Refund(address common.Address, gas *big.Int) {
|
||||
addr := address.Str()
|
||||
if self.refund[addr] == nil {
|
||||
self.refund[addr] = new(big.Int)
|
||||
}
|
||||
self.refund[addr].Add(self.refund[addr], gas)
|
||||
func (self *StateDB) Refund(gas *big.Int) {
|
||||
self.refund.Add(self.refund, gas)
|
||||
}
|
||||
|
||||
/*
|
||||
@ -107,13 +103,13 @@ func (self *StateDB) GetCode(addr common.Address) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *StateDB) GetState(a common.Address, b common.Hash) []byte {
|
||||
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
|
||||
stateObject := self.GetStateObject(a)
|
||||
if stateObject != nil {
|
||||
return stateObject.GetState(b).Bytes()
|
||||
return stateObject.GetState(b)
|
||||
}
|
||||
|
||||
return nil
|
||||
return common.Hash{}
|
||||
}
|
||||
|
||||
func (self *StateDB) IsDeleted(addr common.Address) bool {
|
||||
@ -149,10 +145,10 @@ func (self *StateDB) SetCode(addr common.Address, code []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *StateDB) SetState(addr common.Address, key common.Hash, value interface{}) {
|
||||
func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) {
|
||||
stateObject := self.GetOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SetState(key, common.NewValue(value))
|
||||
stateObject.SetState(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,14 +259,12 @@ func (s *StateDB) Cmp(other *StateDB) bool {
|
||||
|
||||
func (self *StateDB) Copy() *StateDB {
|
||||
state := New(common.Hash{}, self.db)
|
||||
state.trie = self.trie.Copy()
|
||||
state.trie = self.trie
|
||||
for k, stateObject := range self.stateObjects {
|
||||
state.stateObjects[k] = stateObject.Copy()
|
||||
}
|
||||
|
||||
for addr, refund := range self.refund {
|
||||
state.refund[addr] = new(big.Int).Set(refund)
|
||||
}
|
||||
state.refund.Set(self.refund)
|
||||
|
||||
for hash, logs := range self.logs {
|
||||
state.logs[hash] = make(Logs, len(logs))
|
||||
@ -302,10 +296,6 @@ func (s *StateDB) Reset() {
|
||||
|
||||
// Reset all nested states
|
||||
for _, stateObject := range s.stateObjects {
|
||||
if stateObject.State == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
stateObject.Reset()
|
||||
}
|
||||
|
||||
@ -316,11 +306,7 @@ func (s *StateDB) Reset() {
|
||||
func (s *StateDB) Sync() {
|
||||
// Sync all nested states
|
||||
for _, stateObject := range s.stateObjects {
|
||||
if stateObject.State == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
stateObject.State.Sync()
|
||||
stateObject.trie.Commit()
|
||||
}
|
||||
|
||||
s.trie.Commit()
|
||||
@ -330,22 +316,22 @@ func (s *StateDB) Sync() {
|
||||
|
||||
func (self *StateDB) Empty() {
|
||||
self.stateObjects = make(map[string]*StateObject)
|
||||
self.refund = make(map[string]*big.Int)
|
||||
self.refund = new(big.Int)
|
||||
}
|
||||
|
||||
func (self *StateDB) Refunds() map[string]*big.Int {
|
||||
func (self *StateDB) Refunds() *big.Int {
|
||||
return self.refund
|
||||
}
|
||||
|
||||
func (self *StateDB) Update() {
|
||||
self.refund = make(map[string]*big.Int)
|
||||
self.refund = new(big.Int)
|
||||
|
||||
for _, stateObject := range self.stateObjects {
|
||||
if stateObject.dirty {
|
||||
if stateObject.remove {
|
||||
self.DeleteStateObject(stateObject)
|
||||
} else {
|
||||
stateObject.Sync()
|
||||
stateObject.Update()
|
||||
|
||||
self.UpdateStateObject(stateObject)
|
||||
}
|
||||
|
@ -241,11 +241,9 @@ func (self *StateTransition) refundGas() {
|
||||
sender.AddBalance(remaining)
|
||||
|
||||
uhalf := new(big.Int).Div(self.gasUsed(), common.Big2)
|
||||
for addr, ref := range self.state.Refunds() {
|
||||
refund := common.BigMin(uhalf, ref)
|
||||
refund := common.BigMin(uhalf, self.state.Refunds())
|
||||
self.gas.Add(self.gas, refund)
|
||||
self.state.AddBalance(common.StringToAddress(addr), refund.Mul(refund, self.msg.GasPrice()))
|
||||
}
|
||||
self.state.AddBalance(sender.Address(), refund.Mul(refund, self.msg.GasPrice()))
|
||||
|
||||
coinbase.RefundGas(self.gas, self.msg.GasPrice())
|
||||
}
|
||||
|
@ -105,9 +105,11 @@ func (pool *TxPool) resetState() {
|
||||
if addr, err := tx.From(); err == nil {
|
||||
// Set the nonce. Transaction nonce can never be lower
|
||||
// than the state nonce; validatePool took care of that.
|
||||
if pool.pendingState.GetNonce(addr) < tx.Nonce() {
|
||||
pool.pendingState.SetNonce(addr, tx.Nonce())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the queue and move transactions over to the pending if possible
|
||||
// or remove those that have become invalid
|
||||
@ -153,6 +155,11 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||
return ErrNonExistentAccount
|
||||
}
|
||||
|
||||
// Last but not least check for nonce errors
|
||||
if pool.currentState().GetNonce(from) > tx.Nonce() {
|
||||
return ErrNonce
|
||||
}
|
||||
|
||||
// Check the transaction doesn't exceed the current
|
||||
// block limit gas.
|
||||
if pool.gasLimit().Cmp(tx.GasLimit) < 0 {
|
||||
@ -179,12 +186,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||
return ErrIntrinsicGas
|
||||
}
|
||||
|
||||
// Last but not least check for nonce errors (intensive
|
||||
// operation, saved for last)
|
||||
if pool.currentState().GetNonce(from) > tx.Nonce() {
|
||||
return ErrNonce
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -394,10 +395,13 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
||||
|
||||
// validatePool removes invalid and processed transactions from the main pool.
|
||||
func (pool *TxPool) validatePool() {
|
||||
state := pool.currentState()
|
||||
for hash, tx := range pool.pending {
|
||||
if err := pool.validateTx(tx); err != nil {
|
||||
from, _ := tx.From() // err already checked
|
||||
// perform light nonce validation
|
||||
if state.GetNonce(from) > tx.Nonce() {
|
||||
if glog.V(logger.Core) {
|
||||
glog.Infof("removed tx (%x) from pool: %v\n", hash[:4], err)
|
||||
glog.Infof("removed tx (%x) from pool: low tx nonce\n", hash[:4])
|
||||
}
|
||||
delete(pool.pending, hash)
|
||||
}
|
||||
|
@ -506,14 +506,14 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
|
||||
|
||||
case SLOAD:
|
||||
loc := common.BigToHash(stack.pop())
|
||||
val := common.Bytes2Big(statedb.GetState(context.Address(), loc))
|
||||
val := statedb.GetState(context.Address(), loc).Big()
|
||||
stack.push(val)
|
||||
|
||||
case SSTORE:
|
||||
loc := common.BigToHash(stack.pop())
|
||||
val := stack.pop()
|
||||
|
||||
statedb.SetState(context.Address(), loc, val)
|
||||
statedb.SetState(context.Address(), loc, common.BigToHash(val))
|
||||
|
||||
case JUMP:
|
||||
if err := jump(pc, stack.pop()); err != nil {
|
||||
@ -686,11 +686,16 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
|
||||
var g *big.Int
|
||||
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
||||
val := statedb.GetState(context.Address(), common.BigToHash(x))
|
||||
if len(val) == 0 && len(y.Bytes()) > 0 {
|
||||
|
||||
// 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 len(val) > 0 && len(y.Bytes()) == 0 {
|
||||
statedb.Refund(self.env.Origin(), params.SstoreRefundGas)
|
||||
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
|
||||
statedb.Refund(params.SstoreRefundGas)
|
||||
|
||||
g = params.SstoreClearGas
|
||||
} else {
|
||||
@ -700,7 +705,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
|
||||
gas.Set(g)
|
||||
case SUICIDE:
|
||||
if !statedb.IsDeleted(context.Address()) {
|
||||
statedb.Refund(self.env.Origin(), params.SuicideRefundGas)
|
||||
statedb.Refund(params.SuicideRefundGas)
|
||||
}
|
||||
case MLOAD:
|
||||
newMemSize = calcMemSize(stack.peek(), u256(32))
|
||||
|
@ -124,7 +124,7 @@ func (t *BlockTest) InsertPreState(ethereum *eth.Ethereum) (*state.StateDB, erro
|
||||
obj.SetBalance(balance)
|
||||
obj.SetNonce(nonce)
|
||||
for k, v := range acct.Storage {
|
||||
statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.FromHex(v))
|
||||
statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.HexToHash(v))
|
||||
}
|
||||
}
|
||||
// sync objects to trie
|
||||
|
@ -97,7 +97,7 @@ func RunVmTest(p string, t *testing.T) {
|
||||
obj := StateObjectFromAccount(db, addr, account)
|
||||
statedb.SetStateObject(obj)
|
||||
for a, v := range account.Storage {
|
||||
obj.SetState(common.HexToHash(a), common.NewValue(helper.FromHex(v)))
|
||||
obj.SetState(common.HexToHash(a), common.HexToHash(v))
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,11 +168,11 @@ func RunVmTest(p string, t *testing.T) {
|
||||
}
|
||||
|
||||
for addr, value := range account.Storage {
|
||||
v := obj.GetState(common.HexToHash(addr)).Bytes()
|
||||
vexp := helper.FromHex(value)
|
||||
v := obj.GetState(common.HexToHash(addr))
|
||||
vexp := common.HexToHash(value)
|
||||
|
||||
if bytes.Compare(v, vexp) != 0 {
|
||||
t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v))
|
||||
if v != vexp {
|
||||
t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, vexp.Big(), v.Big())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ func NewObject(state *state.StateObject) *Object {
|
||||
return &Object{state}
|
||||
}
|
||||
|
||||
func (self *Object) StorageString(str string) *common.Value {
|
||||
func (self *Object) StorageString(str string) []byte {
|
||||
if common.IsHex(str) {
|
||||
return self.storage(common.Hex2Bytes(str[2:]))
|
||||
} else {
|
||||
@ -30,12 +30,12 @@ func (self *Object) StorageString(str string) *common.Value {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Object) StorageValue(addr *common.Value) *common.Value {
|
||||
func (self *Object) StorageValue(addr *common.Value) []byte {
|
||||
return self.storage(addr.Bytes())
|
||||
}
|
||||
|
||||
func (self *Object) storage(addr []byte) *common.Value {
|
||||
return self.StateObject.GetStorage(common.BigD(addr))
|
||||
func (self *Object) storage(addr []byte) []byte {
|
||||
return self.StateObject.GetState(common.BytesToHash(addr)).Bytes()
|
||||
}
|
||||
|
||||
func (self *Object) Storage() (storage map[string]string) {
|
||||
|
@ -488,7 +488,7 @@ func (self *XEth) NumberToHuman(balance string) string {
|
||||
}
|
||||
|
||||
func (self *XEth) StorageAt(addr, storageAddr string) string {
|
||||
return common.ToHex(self.State().state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)))
|
||||
return self.State().state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex()
|
||||
}
|
||||
|
||||
func (self *XEth) BalanceAt(addr string) string {
|
||||
|
Loading…
Reference in New Issue
Block a user