core/state, core/vm: reworked storage get / set to use common.Hash

This commit is contained in:
obscuren 2015-06-17 11:24:40 +02:00
parent 5721fcf668
commit 787a61bb27
5 changed files with 45 additions and 41 deletions

@ -62,6 +62,10 @@ func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
return reflect.ValueOf(h) return reflect.ValueOf(h)
} }
func EmptyHash(h Hash) bool {
return h == Hash{}
}
/////////// Address /////////// Address
func BytesToAddress(b []byte) Address { func BytesToAddress(b []byte) Address {
var a Address var a Address

@ -19,11 +19,11 @@ func (self Code) String() string {
return string(self) //strings.Join(Disassemble(self), " ") 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) { func (self Storage) String() (str string) {
for key, value := range self { for key, value := range self {
str += fmt.Sprintf("%X : %X\n", key, value.Bytes()) str += fmt.Sprintf("%X : %X\n", key, value)
} }
return return
@ -32,7 +32,6 @@ func (self Storage) String() (str string) {
func (self Storage) Copy() Storage { func (self Storage) Copy() Storage {
cpy := make(Storage) cpy := make(Storage)
for key, value := range self { for key, value := range self {
// XXX Do we need a 'value' copy or is this sufficient?
cpy[key] = value cpy[key] = value
} }
@ -112,7 +111,7 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db common.Data
object.balance = extobject.Balance object.balance = extobject.Balance
object.codeHash = extobject.CodeHash object.codeHash = extobject.CodeHash
object.State = New(extobject.Root, db) object.State = New(extobject.Root, db)
object.storage = make(map[string]*common.Value) object.storage = make(map[string]common.Hash)
object.gasPool = new(big.Int) object.gasPool = new(big.Int)
object.prepaid = new(big.Int) object.prepaid = new(big.Int)
object.code, _ = db.Get(extobject.CodeHash) object.code, _ = db.Get(extobject.CodeHash)
@ -129,35 +128,29 @@ func (self *StateObject) MarkForDeletion() {
} }
} }
func (c *StateObject) getAddr(addr common.Hash) *common.Value { func (c *StateObject) getAddr(addr common.Hash) (ret common.Hash) {
return common.NewValueFromBytes([]byte(c.State.trie.Get(addr[:]))) return common.BytesToHash(common.NewValueFromBytes([]byte(c.State.trie.Get(addr[:]))).Bytes())
} }
func (c *StateObject) setAddr(addr []byte, value interface{}) { func (c *StateObject) setAddr(addr []byte, value common.Hash) {
c.State.trie.Update(addr, common.Encode(value)) 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
func (self *StateObject) GetStorage(key *big.Int) *common.Value { panic(err)
fmt.Printf("%v: get %v %v", self.address.Hex(), key) }
return self.GetState(common.BytesToHash(key.Bytes())) c.State.trie.Update(addr, v)
}
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)
} }
func (self *StateObject) Storage() Storage { func (self *StateObject) Storage() Storage {
return self.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() strkey := key.Str()
value := self.storage[strkey] value, exists := self.storage[strkey]
if value == nil { if !exists {
value = self.getAddr(key) value = self.getAddr(key)
if (value != common.Hash{}) {
if !value.IsNil() {
self.storage[strkey] = value self.storage[strkey] = value
} }
} }
@ -165,14 +158,14 @@ func (self *StateObject) GetState(key common.Hash) *common.Value {
return value return value
} }
func (self *StateObject) SetState(k common.Hash, value *common.Value) { func (self *StateObject) SetState(k, value common.Hash) {
self.storage[k.Str()] = value.Copy() self.storage[k.Str()] = value
self.dirty = true self.dirty = true
} }
func (self *StateObject) Sync() { func (self *StateObject) Sync() {
for key, value := range self.storage { for key, value := range self.storage {
if value.Len() == 0 { if (value == common.Hash{}) {
self.State.trie.Delete([]byte(key)) self.State.trie.Delete([]byte(key))
continue continue
} }
@ -370,7 +363,7 @@ func (c *StateObject) RlpDecode(data []byte) {
c.nonce = decoder.Get(0).Uint() c.nonce = decoder.Get(0).Uint()
c.balance = decoder.Get(1).BigInt() 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.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.storage = make(map[string]common.Hash)
c.gasPool = new(big.Int) c.gasPool = new(big.Int)
c.codeHash = decoder.Get(3).Bytes() c.codeHash = decoder.Get(3).Bytes()

@ -103,13 +103,13 @@ func (self *StateDB) GetCode(addr common.Address) []byte {
return nil 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) stateObject := self.GetStateObject(a)
if stateObject != nil { 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 { func (self *StateDB) IsDeleted(addr common.Address) bool {
@ -145,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) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetState(key, common.NewValue(value)) stateObject.SetState(key, value)
} }
} }

@ -506,14 +506,14 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
case SLOAD: case SLOAD:
loc := common.BigToHash(stack.pop()) loc := common.BigToHash(stack.pop())
val := common.Bytes2Big(statedb.GetState(context.Address(), loc)) val := statedb.GetState(context.Address(), loc).Big()
stack.push(val) stack.push(val)
case SSTORE: case SSTORE:
loc := common.BigToHash(stack.pop()) loc := common.BigToHash(stack.pop())
val := stack.pop() val := stack.pop()
statedb.SetState(context.Address(), loc, val) statedb.SetState(context.Address(), loc, common.BigToHash(val))
case JUMP: case JUMP:
if err := jump(pc, stack.pop()); err != nil { if err := jump(pc, stack.pop()); err != nil {
@ -686,10 +686,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
var g *big.Int var g *big.Int
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
val := statedb.GetState(context.Address(), common.BigToHash(x)) val := statedb.GetState(context.Address(), common.BigToHash(x))
if len(val) == 0 && len(y.Bytes()) > 0 { if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
// 0 => non 0 // 0 => non 0
g = params.SstoreSetGas g = params.SstoreSetGas
} else if len(val) > 0 && len(y.Bytes()) == 0 { } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
statedb.Refund(params.SstoreRefundGas) statedb.Refund(params.SstoreRefundGas)
g = params.SstoreClearGas g = params.SstoreClearGas
@ -697,6 +697,13 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
// non 0 => non 0 (or 0 => 0) // non 0 => non 0 (or 0 => 0)
g = params.SstoreClearGas g = params.SstoreClearGas
} }
/*
if len(val) == 0 && len(y.Bytes()) > 0 {
} else if len(val) > 0 && len(y.Bytes()) == 0 {
} else {
}
*/
gas.Set(g) gas.Set(g)
case SUICIDE: case SUICIDE:
if !statedb.IsDeleted(context.Address()) { if !statedb.IsDeleted(context.Address()) {

@ -97,7 +97,7 @@ func RunVmTest(p string, t *testing.T) {
obj := StateObjectFromAccount(db, addr, account) obj := StateObjectFromAccount(db, addr, account)
statedb.SetStateObject(obj) statedb.SetStateObject(obj)
for a, v := range account.Storage { 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 { for addr, value := range account.Storage {
v := obj.GetState(common.HexToHash(addr)).Bytes() v := obj.GetState(common.HexToHash(addr))
vexp := helper.FromHex(value) vexp := common.HexToHash(value)
if bytes.Compare(v, vexp) != 0 { 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, common.BigD(vexp), common.BigD(v)) 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())
} }
} }
} }