Merge branch 'develop' of github.com:ethereum/eth-go into develop

This commit is contained in:
Maran 2014-06-17 11:40:37 +02:00
commit a90ffe1af1
7 changed files with 67 additions and 279 deletions

View File

@ -1,236 +0,0 @@
package ethchain
import (
"bytes"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject {
contract := MakeContract(tx, state)
if contract != nil {
state.states[string(tx.CreationAddress())] = contract.state
return contract
}
return nil
}
func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) {
account := state.GetAccount(tx.Sender())
err = account.ConvertGas(tx.Gas, tx.GasPrice)
if err != nil {
ethutil.Config.Log.Debugln(err)
return
}
closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice)
vm := NewVm(state, sm, RuntimeVars{
Origin: account.Address(),
BlockNumber: block.BlockInfo().Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: tx.Value,
//Price: tx.GasPrice,
})
ret, gas, err = closure.Call(vm, tx.Data, nil)
// Update the account (refunds)
state.UpdateStateObject(account)
state.UpdateStateObject(object)
return
}
func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) {
fmt.Printf("state root before update %x\n", state.Root())
defer func() {
if r := recover(); r != nil {
ethutil.Config.Log.Infoln(r)
err = fmt.Errorf("%v", r)
}
}()
gas = new(big.Int)
addGas := func(g *big.Int) { gas.Add(gas, g) }
addGas(GasTx)
// Get the sender
sender := state.GetAccount(tx.Sender())
if sender.Nonce != tx.Nonce {
err = NonceError(tx.Nonce, sender.Nonce)
return
}
sender.Nonce += 1
defer func() {
//state.UpdateStateObject(sender)
// Notify all subscribers
self.Ethereum.Reactor().Post("newTx:post", tx)
}()
txTotalBytes := big.NewInt(int64(len(tx.Data)))
//fmt.Println("txTotalBytes", txTotalBytes)
//txTotalBytes.Div(txTotalBytes, ethutil.Big32)
addGas(new(big.Int).Mul(txTotalBytes, GasData))
rGas := new(big.Int).Set(gas)
rGas.Mul(gas, tx.GasPrice)
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
totAmount := new(big.Int).Add(tx.Value, rGas)
if sender.Amount.Cmp(totAmount) < 0 {
state.UpdateStateObject(sender)
err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
return
}
coinbase.BuyGas(gas, tx.GasPrice)
state.UpdateStateObject(coinbase)
fmt.Printf("1. root %x\n", state.Root())
// Get the receiver
receiver := state.GetAccount(tx.Recipient)
// Send Tx to self
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
// Subtract the fee
sender.SubAmount(rGas)
} else {
// Subtract the amount from the senders account
sender.SubAmount(totAmount)
state.UpdateStateObject(sender)
fmt.Printf("3. root %x\n", state.Root())
// Add the amount to receivers account which should conclude this transaction
receiver.AddAmount(tx.Value)
state.UpdateStateObject(receiver)
fmt.Printf("2. root %x\n", state.Root())
}
ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash())
return
}
func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) {
/*
Applies transactions to the given state and creates new
state objects where needed.
If said objects needs to be created
run the initialization script provided by the transaction and
assume there's a return value. The return value will be set to
the script section of the state object.
*/
var (
addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) }
gas = new(big.Int)
script []byte
)
totalGasUsed = big.NewInt(0)
snapshot := state.Snapshot()
ca := state.GetAccount(coinbase)
// Apply the transaction to the current state
gas, err = sm.ProcessTransaction(tx, ca, state, false)
addTotalGas(gas)
fmt.Println("gas used by tx", gas)
if tx.CreatesContract() {
if err == nil {
// Create a new state object and the transaction
// as it's data provider.
contract := sm.MakeStateObject(state, tx)
if contract != nil {
fmt.Println(Disassemble(contract.Init()))
// Evaluate the initialization script
// and use the return value as the
// script section for the state object.
script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block)
fmt.Println("gas used by eval", gas)
addTotalGas(gas)
fmt.Println("total =", totalGasUsed)
fmt.Println("script len =", len(script))
if err != nil {
err = fmt.Errorf("[STATE] Error during init script run %v", err)
return
}
contract.script = script
state.UpdateStateObject(contract)
} else {
err = fmt.Errorf("[STATE] Unable to create contract")
}
} else {
err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender())
}
} else {
// Find the state object at the "recipient" address. If
// there's an object attempt to run the script.
stateObject := state.GetStateObject(tx.Recipient)
if err == nil && stateObject != nil && len(stateObject.Script()) > 0 {
_, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block)
addTotalGas(gas)
}
}
parent := sm.bc.GetBlock(block.PrevHash)
total := new(big.Int).Add(block.GasUsed, totalGasUsed)
limit := block.CalcGasLimit(parent)
if total.Cmp(limit) > 0 {
state.Revert(snapshot)
err = GasLimitError(total, limit)
}
return
}
// Apply transactions uses the transaction passed to it and applies them onto
// the current processing state.
func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) {
// Process each transaction/contract
var receipts []*Receipt
var validTxs []*Transaction
var ignoredTxs []*Transaction // Transactions which go over the gasLimit
totalUsedGas := big.NewInt(0)
for _, tx := range txs {
usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx)
if err != nil {
if IsNonceErr(err) {
continue
}
if IsGasLimitErr(err) {
ignoredTxs = append(ignoredTxs, tx)
// We need to figure out if we want to do something with thse txes
ethutil.Config.Log.Debugln("Gastlimit:", err)
continue
}
ethutil.Config.Log.Infoln(err)
}
accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas))
receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative}
receipts = append(receipts, receipt)
validTxs = append(validTxs, tx)
}
fmt.Println("################# MADE\n", receipts, "\n############################")
// Update the total gas used for the block (to be mined)
block.GasUsed = totalUsedGas
return receipts, validTxs
}

View File

@ -13,8 +13,6 @@ import (
type State struct { type State struct {
// The trie for this structure // The trie for this structure
trie *ethutil.Trie trie *ethutil.Trie
// Nested states
states map[string]*State
stateObjects map[string]*StateObject stateObjects map[string]*StateObject
@ -23,7 +21,7 @@ type State struct {
// Create a new state from a given trie // Create a new state from a given trie
func NewState(trie *ethutil.Trie) *State { func NewState(trie *ethutil.Trie) *State {
return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
} }
// Resets the trie and all siblings // Resets the trie and all siblings
@ -38,12 +36,16 @@ func (s *State) Reset() {
stateObject.state.Reset() stateObject.state.Reset()
} }
s.Empty()
} }
// Syncs the trie and all siblings // Syncs the trie and all siblings
func (s *State) Sync() { func (s *State) Sync() {
// Sync all nested states // Sync all nested states
for _, stateObject := range s.stateObjects { for _, stateObject := range s.stateObjects {
s.UpdateStateObject(stateObject)
if stateObject.state == nil { if stateObject.state == nil {
continue continue
} }
@ -52,6 +54,18 @@ func (s *State) Sync() {
} }
s.trie.Sync() s.trie.Sync()
s.Empty()
}
func (self *State) Empty() {
self.stateObjects = make(map[string]*StateObject)
}
func (self *State) Update() {
for _, stateObject := range self.stateObjects {
self.UpdateStateObject(stateObject)
}
} }
// Purges the current trie. // Purges the current trie.
@ -68,6 +82,7 @@ func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address() addr := stateObject.Address()
if self.stateObjects[string(addr)] == nil { if self.stateObjects[string(addr)] == nil {
panic("?")
self.stateObjects[string(addr)] = stateObject self.stateObjects[string(addr)] = stateObject
} }
@ -98,13 +113,19 @@ func (self *State) GetStateObject(addr []byte) *StateObject {
func (self *State) GetOrNewStateObject(addr []byte) *StateObject { func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
stateObject := self.GetStateObject(addr) stateObject := self.GetStateObject(addr)
if stateObject == nil { if stateObject == nil {
stateObject = NewStateObject(addr) stateObject = self.NewStateObject(addr)
self.stateObjects[string(addr)] = stateObject
} }
return stateObject return stateObject
} }
func (self *State) NewStateObject(addr []byte) *StateObject {
stateObject := NewStateObject(addr)
self.stateObjects[string(addr)] = stateObject
return stateObject
}
func (self *State) GetAccount(addr []byte) *StateObject { func (self *State) GetAccount(addr []byte) *StateObject {
return self.GetOrNewStateObject(addr) return self.GetOrNewStateObject(addr)
} }
@ -132,7 +153,7 @@ func (s *State) Snapshot() *State {
func (s *State) Revert(snapshot *State) { func (s *State) Revert(snapshot *State) {
s.trie = snapshot.trie s.trie = snapshot.trie
s.states = snapshot.states s.stateObjects = snapshot.stateObjects
} }
func (s *State) Put(key, object []byte) { func (s *State) Put(key, object []byte) {

View File

@ -181,7 +181,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea
coinbase.SetGasPool(block.CalcGasLimit(parent)) coinbase.SetGasPool(block.CalcGasLimit(parent))
// Process the transactions on to current block // Process the transactions on to current block
//sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions())
sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions())
// Block validation // Block validation
@ -197,6 +196,9 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea
return err return err
} }
// Update the state with pending changes
state.Update()
if !block.State().Cmp(state) { if !block.State().Cmp(state) {
return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root)
} }

View File

@ -4,8 +4,15 @@ import (
"fmt" "fmt"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"math/big" "math/big"
"strings"
) )
type Code []byte
func (self Code) String() string {
return strings.Join(Disassemble(self), " ")
}
type StateObject struct { type StateObject struct {
// Address of the object // Address of the object
address []byte address []byte
@ -15,8 +22,8 @@ type StateObject struct {
Nonce uint64 Nonce uint64
// Contract related attributes // Contract related attributes
state *State state *State
script []byte script Code
initScript []byte initScript Code
// Total gas pool is the total amount of gas currently // Total gas pool is the total amount of gas currently
// left if this object is the coinbase. Gas is directly // left if this object is the coinbase. Gas is directly
@ -30,12 +37,9 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
if tx.IsContract() { if tx.IsContract() {
addr := tx.CreationAddress() addr := tx.CreationAddress()
value := tx.Value contract := state.NewStateObject(addr)
contract := NewContract(addr, value, ZeroHash256)
contract.initScript = tx.Data contract.initScript = tx.Data
contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, ""))
state.UpdateStateObject(contract)
return contract return contract
} }
@ -120,13 +124,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) {
func (c *StateObject) AddAmount(amount *big.Int) { func (c *StateObject) AddAmount(amount *big.Int) {
c.SetAmount(new(big.Int).Add(c.Amount, amount)) c.SetAmount(new(big.Int).Add(c.Amount, amount))
ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount)
} }
func (c *StateObject) SubAmount(amount *big.Int) { func (c *StateObject) SubAmount(amount *big.Int) {
c.SetAmount(new(big.Int).Sub(c.Amount, amount)) c.SetAmount(new(big.Int).Sub(c.Amount, amount))
ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount)
} }
func (c *StateObject) SetAmount(amount *big.Int) { func (c *StateObject) SetAmount(amount *big.Int) {
@ -197,12 +201,12 @@ func (c *StateObject) Address() []byte {
} }
// Returns the main script body // Returns the main script body
func (c *StateObject) Script() []byte { func (c *StateObject) Script() Code {
return c.script return c.script
} }
// Returns the initialization script // Returns the initialization script
func (c *StateObject) Init() []byte { func (c *StateObject) Init() Code {
return c.initScript return c.initScript
} }

View File

@ -67,15 +67,10 @@ func (self *StateTransition) Receiver() *StateObject {
func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject { func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject {
contract := MakeContract(tx, state) contract := MakeContract(tx, state)
if contract != nil {
state.states[string(tx.CreationAddress())] = contract.state
return contract return contract
} }
return nil
}
func (self *StateTransition) UseGas(amount *big.Int) error { func (self *StateTransition) UseGas(amount *big.Int) error {
if self.gas.Cmp(amount) < 0 { if self.gas.Cmp(amount) < 0 {
return OutOfGasError() return OutOfGasError()
@ -137,6 +132,8 @@ func (self *StateTransition) TransitionState() (err error) {
receiver *StateObject receiver *StateObject
) )
ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", tx.Hash())
// Make sure this transaction's nonce is correct // Make sure this transaction's nonce is correct
if sender.Nonce != tx.Nonce { if sender.Nonce != tx.Nonce {
return NonceError(tx.Nonce, sender.Nonce) return NonceError(tx.Nonce, sender.Nonce)
@ -152,6 +149,7 @@ func (self *StateTransition) TransitionState() (err error) {
defer func() { defer func() {
self.RefundGas() self.RefundGas()
/*
if sender != nil { if sender != nil {
self.state.UpdateStateObject(sender) self.state.UpdateStateObject(sender)
} }
@ -161,6 +159,7 @@ func (self *StateTransition) TransitionState() (err error) {
} }
self.state.UpdateStateObject(self.Coinbase()) self.state.UpdateStateObject(self.Coinbase())
*/
}() }()
// Increment the nonce for the next transaction // Increment the nonce for the next transaction
@ -209,6 +208,7 @@ func (self *StateTransition) TransitionState() (err error) {
receiver.script = code receiver.script = code
} else { } else {
if len(receiver.Script()) > 0 { if len(receiver.Script()) > 0 {
fmt.Println(receiver.Script())
_, err := self.Eval(receiver.Script(), receiver) _, err := self.Eval(receiver.Script(), receiver)
if err != nil { if err != nil {
return fmt.Errorf("Error during code execution %v", err) return fmt.Errorf("Error during code execution %v", err)

View File

@ -95,9 +95,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
step := 0 step := 0
prevStep := 0 prevStep := 0
if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("# op\n") ethutil.Config.Log.Debugf("# op\n")
}
for { for {
prevStep = step prevStep = step
@ -109,9 +107,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
val := closure.Get(pc) val := closure.Get(pc)
// Get the opcode (it must be an opcode!) // Get the opcode (it must be an opcode!)
op := OpCode(val.Uint()) op := OpCode(val.Uint())
if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String())
}
gas := new(big.Int) gas := new(big.Int)
addStepGasUsage := func(amount *big.Int) { addStepGasUsage := func(amount *big.Int) {
@ -525,8 +522,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
vm.state.Revert(snapshot) vm.state.Revert(snapshot)
} else { } else {
stack.Push(ethutil.BigD(addr)) stack.Push(ethutil.BigD(addr))
vm.state.UpdateStateObject(contract)
} }
case CALL: case CALL:
// TODO RE-WRITE // TODO RE-WRITE
@ -569,8 +564,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
} else { } else {
stack.Push(ethutil.BigTrue) stack.Push(ethutil.BigTrue)
vm.state.UpdateStateObject(contract)
mem.Set(retOffset.Int64(), retSize.Int64(), ret) mem.Set(retOffset.Int64(), retSize.Int64(), ret)
} }
} else { } else {
@ -589,9 +582,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver := vm.state.GetAccount(stack.Pop().Bytes())
receiver.AddAmount(closure.object.Amount) receiver.AddAmount(closure.object.Amount)
vm.state.UpdateStateObject(receiver)
closure.object.state.Purge() trie := closure.object.state.trie
trie.NewIterator().Each(func(key string, v *ethutil.Value) {
trie.Delete(key)
})
fallthrough fallthrough
case STOP: // Stop the closure case STOP: // Stop the closure

View File

@ -154,6 +154,8 @@ func (self *Miner) mineNewBlock() {
// Accumulate the rewards included for this block // Accumulate the rewards included for this block
stateManager.AccumelateRewards(self.block.State(), self.block) stateManager.AccumelateRewards(self.block.State(), self.block)
self.block.State().Update()
ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(self.txs), "transactions") ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(self.txs), "transactions")
// Find a valid nonce // Find a valid nonce