aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/block_processor.go141
-rw-r--r--core/block_processor_test.go8
-rw-r--r--core/chain_makers.go2
-rw-r--r--core/chain_manager.go16
-rw-r--r--core/state/dump.go6
-rw-r--r--core/state/state_object.go97
-rw-r--r--core/state/state_test.go23
-rw-r--r--core/state/statedb.go46
-rw-r--r--core/state_transition.go23
-rw-r--r--core/transaction_pool.go24
-rw-r--r--core/vm/vm.go17
11 files changed, 182 insertions, 221 deletions
diff --git a/core/block_processor.go b/core/block_processor.go
index c01b110be..e30ced312 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -58,7 +58,7 @@ func NewBlockProcessor(db, extra common.Database, pow pow.PoW, chainManager *Cha
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
- coinbase.SetGasPool(block.Header().GasLimit)
+ coinbase.SetGasLimit(block.Header().GasLimit)
// Process the transactions on to parent state
receipts, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
@@ -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[:]...))
diff --git a/core/block_processor_test.go b/core/block_processor_test.go
index 97b80038d..e38c815ef 100644
--- a/core/block_processor_test.go
+++ b/core/block_processor_test.go
@@ -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")
}
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 4e685f599..76acfd6ca 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -79,7 +79,7 @@ func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db common.Datab
block := newBlockFromParent(addr, parent)
state := state.New(block.Root(), db)
cbase := state.GetOrNewStateObject(addr)
- cbase.SetGasPool(CalcGasLimit(parent))
+ cbase.SetGasLimit(CalcGasLimit(parent))
cbase.AddBalance(BlockReward)
state.Update()
block.SetRoot(state.Root())
diff --git a/core/chain_manager.go b/core/chain_manager.go
index c3b7273c2..e3795f561 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -377,8 +377,14 @@ func (self *ChainManager) ExportN(w io.Writer, first uint64, last uint64) error
// assumes that the `mu` mutex is held!
func (bc *ChainManager) insert(block *types.Block) {
key := append(blockNumPre, block.Number().Bytes()...)
- bc.blockDb.Put(key, block.Hash().Bytes())
- bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes())
+ err := bc.blockDb.Put(key, block.Hash().Bytes())
+ if err != nil {
+ glog.Fatal("db write fail:", err)
+ }
+ err = bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes())
+ if err != nil {
+ glog.Fatal("db write fail:", err)
+ }
bc.currentBlock = block
bc.lastBlockHash = block.Hash()
@@ -387,7 +393,11 @@ func (bc *ChainManager) insert(block *types.Block) {
func (bc *ChainManager) write(block *types.Block) {
enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block))
key := append(blockHashPre, block.Hash().Bytes()...)
- bc.blockDb.Put(key, enc)
+ err := bc.blockDb.Put(key, enc)
+ if err != nil {
+ glog.Fatal("db write fail:", err)
+ }
+
// Push block to cache
bc.cache.Push(block)
}
diff --git a/core/state/dump.go b/core/state/dump.go
index 70ea21691..f6f2f9029 100644
--- a/core/state/dump.go
+++ b/core/state/dump.go
@@ -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)
}
diff --git a/core/state/state_object.go b/core/state/state_object.go
index 6d2455d79..a31c182d2 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -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
}
@@ -41,9 +40,8 @@ func (self Storage) Copy() Storage {
type StateObject struct {
// State database for storing state changes
- db common.Database
- // The state object
- State *StateDB
+ db common.Database
+ 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)
@@ -107,12 +104,11 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db common.Data
}
object := &StateObject{address: address, db: db}
- //object.RlpDecode(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 +125,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 (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)
+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)
+ }
+ 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 +157,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
}
@@ -221,20 +214,8 @@ func (c *StateObject) St() Storage {
// Return the gas back to the origin. Used by the Virtual machine or Closures
func (c *StateObject) ReturnGas(gas, price *big.Int) {}
-func (c *StateObject) ConvertGas(gas, price *big.Int) error {
- total := new(big.Int).Mul(gas, price)
- if total.Cmp(c.balance) > 0 {
- return fmt.Errorf("insufficient amount: %v, %v", c.balance, total)
- }
- c.SubBalance(total)
-
- c.dirty = true
-
- return nil
-}
-
-func (self *StateObject) SetGasPool(gasLimit *big.Int) {
+func (self *StateObject) SetGasLimit(gasLimit *big.Int) {
self.gasPool = new(big.Int).Set(gasLimit)
if glog.V(logger.Core) {
@@ -242,7 +223,7 @@ func (self *StateObject) SetGasPool(gasLimit *big.Int) {
}
}
-func (self *StateObject) BuyGas(gas, price *big.Int) error {
+func (self *StateObject) SubGas(gas, price *big.Int) error {
if self.gasPool.Cmp(gas) < 0 {
return GasLimitError(self.gasPool, gas)
}
@@ -257,7 +238,7 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error {
return nil
}
-func (self *StateObject) RefundGas(gas, price *big.Int) {
+func (self *StateObject) AddGas(gas, price *big.Int) {
self.gasPool.Add(self.gasPool, gas)
}
@@ -266,9 +247,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 +285,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 +321,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 +348,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()
diff --git a/core/state/state_test.go b/core/state/state_test.go
index 09a65de54..00e133dab 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -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)
}
diff --git a/core/state/statedb.go b/core/state/statedb.go
index b3050515b..f6f63f329 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -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)
}
diff --git a/core/state_transition.go b/core/state_transition.go
index fedea8021..915dd466b 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -151,7 +151,7 @@ func (self *StateTransition) BuyGas() error {
}
coinbase := self.Coinbase()
- err = coinbase.BuyGas(self.msg.Gas(), self.msg.GasPrice())
+ err = coinbase.SubGas(self.msg.Gas(), self.msg.GasPrice())
if err != nil {
return err
}
@@ -241,26 +241,13 @@ 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)
- self.gas.Add(self.gas, refund)
- self.state.AddBalance(common.StringToAddress(addr), refund.Mul(refund, self.msg.GasPrice()))
- }
+ refund := common.BigMin(uhalf, self.state.Refunds())
+ self.gas.Add(self.gas, refund)
+ self.state.AddBalance(sender.Address(), refund.Mul(refund, self.msg.GasPrice()))
- coinbase.RefundGas(self.gas, self.msg.GasPrice())
+ coinbase.AddGas(self.gas, self.msg.GasPrice())
}
func (self *StateTransition) gasUsed() *big.Int {
return new(big.Int).Sub(self.initialGas, self.gas)
}
-
-// Converts an message in to a state object
-func makeContract(msg Message, state *state.StateDB) *state.StateObject {
- faddr, _ := msg.From()
- addr := crypto.CreateAddress(faddr, msg.Nonce())
-
- contract := state.GetOrNewStateObject(addr)
- contract.SetInitCode(msg.Data())
-
- return contract
-}
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index e31f5c6b3..34a1733d7 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -105,7 +105,9 @@ 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.
- pool.pendingState.SetNonce(addr, tx.Nonce())
+ if pool.pendingState.GetNonce(addr) < tx.Nonce() {
+ pool.pendingState.SetNonce(addr, tx.Nonce())
+ }
}
}
@@ -147,12 +149,17 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
return ErrInvalidSender
}
- // Make sure the account exist. Non existant accounts
+ // Make sure the account exist. Non existent accounts
// haven't got funds and well therefor never pass.
if !pool.currentState().HasAccount(from) {
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)
}
diff --git a/core/vm/vm.go b/core/vm/vm.go
index c5ad761f6..9e092300d 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -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))