merge upstream

This commit is contained in:
zelig 2014-07-14 18:50:06 +01:00
commit 3d5db7288f
24 changed files with 499 additions and 296 deletions

View File

@ -24,6 +24,10 @@ func Disassemble(script []byte) (asm []string) {
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
pc.Add(pc, ethutil.Big1)
a := int64(op) - int64(PUSH1) + 1
if int(pc.Int64()+a) > len(script) {
return nil
}
data := script[pc.Int64() : pc.Int64()+a]
if len(data) == 0 {
data = []byte{0}

View File

@ -294,7 +294,6 @@ func (bc *BlockChain) setLastBlock() {
bc.LastBlockHash = block.Hash()
bc.LastBlockNumber = block.Number.Uint64()
chainlogger.Infof("Last known block height #%d\n", bc.LastBlockNumber)
} else {
AddTestNetFunds(bc.genesisBlock)
@ -309,7 +308,7 @@ func (bc *BlockChain) setLastBlock() {
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
chainlogger.Infof("Last block: %x\n", bc.CurrentBlock.Hash())
chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash())
}
func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {

View File

@ -84,13 +84,7 @@ func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) {
func (c *Closure) Return(ret []byte) []byte {
// Return the remaining gas to the caller
// If no caller is present return it to
// the origin (i.e. contract or tx)
if c.caller != nil {
c.caller.ReturnGas(c.Gas, c.Price, c.State)
} else {
c.object.ReturnGas(c.Gas, c.Price, c.State)
}
c.caller.ReturnGas(c.Gas, c.Price, c.State)
return ret
}

View File

@ -3,7 +3,6 @@ package ethchain
import (
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/sha3"
"hash"
@ -15,7 +14,7 @@ import (
var powlogger = ethlog.NewLogger("POW")
type PoW interface {
Search(block *Block, reactChan chan ethreact.Event) []byte
Search(block *Block, reactChan chan ethutil.React) []byte
Verify(hash []byte, diff *big.Int, nonce []byte) bool
}
@ -23,7 +22,7 @@ type EasyPow struct {
hash *big.Int
}
func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte {
func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
hash := block.HashNoNonce()
diff := block.Difficulty

View File

@ -1,6 +1,7 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
@ -26,6 +27,131 @@ func NewState(trie *ethtrie.Trie) *State {
return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
}
// Iterate over each storage address and yield callback
func (s *State) EachStorage(cb ethtrie.EachCallback) {
it := s.trie.NewIterator()
it.Each(cb)
}
// Retrieve the balance from the given address or 0 if object not found
func (self *State) GetBalance(addr []byte) *big.Int {
stateObject := self.GetStateObject(addr)
if stateObject != nil {
return stateObject.Amount
}
return ethutil.Big0
}
func (self *State) GetNonce(addr []byte) uint64 {
stateObject := self.GetStateObject(addr)
if stateObject != nil {
return stateObject.Nonce
}
return 0
}
//
// Setting, updating & deleting state object methods
//
// Update the given state object and apply it to state trie
func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address()
ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script())
self.trie.Update(string(addr), string(stateObject.RlpEncode()))
self.manifest.AddObjectChange(stateObject)
}
// Delete the given state object and delete it from the state trie
func (self *State) DeleteStateObject(stateObject *StateObject) {
self.trie.Delete(string(stateObject.Address()))
delete(self.stateObjects, string(stateObject.Address()))
}
// Retrieve a state object given my the address. Nil if not found
func (self *State) GetStateObject(addr []byte) *StateObject {
stateObject := self.stateObjects[string(addr)]
if stateObject != nil {
return stateObject
}
data := self.trie.Get(string(addr))
if len(data) == 0 {
return nil
}
stateObject = NewStateObjectFromBytes(addr, []byte(data))
self.stateObjects[string(addr)] = stateObject
return stateObject
}
// Retrieve a state object or create a new state object if nil
func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
stateObject := self.GetStateObject(addr)
if stateObject == nil {
stateObject = self.NewStateObject(addr)
}
return stateObject
}
// Create a state object whether it exist in the trie or not
func (self *State) NewStateObject(addr []byte) *StateObject {
statelogger.Infof("(+) %x\n", addr)
stateObject := NewStateObject(addr)
self.stateObjects[string(addr)] = stateObject
return stateObject
}
// Deprecated
func (self *State) GetAccount(addr []byte) *StateObject {
return self.GetOrNewStateObject(addr)
}
//
// Setting, copying of the state methods
//
func (s *State) Cmp(other *State) bool {
return s.trie.Cmp(other.trie)
}
func (self *State) Copy() *State {
if self.trie != nil {
state := NewState(self.trie.Copy())
for k, stateObject := range self.stateObjects {
state.stateObjects[k] = stateObject.Copy()
}
return state
}
return nil
}
func (self *State) Set(state *State) {
if state == nil {
panic("Tried setting 'state' to nil through 'Set'")
}
self.trie = state.trie
self.stateObjects = state.stateObjects
//*self = *state
}
func (s *State) Root() interface{} {
return s.trie.Root
}
// Resets the trie and all siblings
func (s *State) Reset() {
s.trie.Undo()
@ -36,7 +162,8 @@ func (s *State) Reset() {
continue
}
stateObject.state.Reset()
//stateObject.state.Reset()
stateObject.Reset()
}
s.Empty()
@ -67,109 +194,29 @@ func (self *State) Empty() {
func (self *State) Update() {
for _, stateObject := range self.stateObjects {
if stateObject.remove {
self.trie.Delete(string(stateObject.Address()))
self.DeleteStateObject(stateObject)
} else {
stateObject.Sync()
self.UpdateStateObject(stateObject)
}
}
}
// Purges the current trie.
func (s *State) Purge() int {
return s.trie.NewIterator().Purge()
}
func (s *State) EachStorage(cb ethtrie.EachCallback) {
it := s.trie.NewIterator()
it.Each(cb)
}
func (self *State) ResetStateObject(stateObject *StateObject) {
delete(self.stateObjects, string(stateObject.Address()))
stateObject.state.Reset()
}
func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address()
ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script())
self.trie.Update(string(addr), string(stateObject.RlpEncode()))
self.manifest.AddObjectChange(stateObject)
}
func (self *State) GetStateObject(addr []byte) *StateObject {
stateObject := self.stateObjects[string(addr)]
if stateObject != nil {
return stateObject
// FIXME trie delete is broken
valid, t2 := ethtrie.ParanoiaCheck(self.trie)
if !valid {
self.trie = t2
}
}
data := self.trie.Get(string(addr))
if len(data) == 0 {
return nil
// Debug stuff
func (self *State) CreateOutputForDiff() {
for addr, stateObject := range self.stateObjects {
fmt.Printf("0x%x 0x%x 0x%x 0x%x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce)
stateObject.state.EachStorage(func(addr string, value *ethutil.Value) {
fmt.Printf("0x%x 0x%x\n", addr, value.Bytes())
})
}
stateObject = NewStateObjectFromBytes(addr, []byte(data))
self.stateObjects[string(addr)] = stateObject
return stateObject
}
func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
stateObject := self.GetStateObject(addr)
if stateObject == nil {
stateObject = self.NewStateObject(addr)
}
return stateObject
}
func (self *State) NewStateObject(addr []byte) *StateObject {
statelogger.Infof("(+) %x\n", addr)
stateObject := NewStateObject(addr)
self.stateObjects[string(addr)] = stateObject
return stateObject
}
func (self *State) GetAccount(addr []byte) *StateObject {
return self.GetOrNewStateObject(addr)
}
func (s *State) Cmp(other *State) bool {
return s.trie.Cmp(other.trie)
}
func (self *State) Copy() *State {
if self.trie != nil {
state := NewState(self.trie.Copy())
for k, stateObject := range self.stateObjects {
state.stateObjects[k] = stateObject.Copy()
}
return state
}
return nil
}
func (self *State) Set(state *State) {
if state == nil {
panic("Tried setting 'state' to nil through 'Set'")
}
*self = *state
}
func (s *State) Put(key, object []byte) {
s.trie.Update(string(key), string(object))
}
func (s *State) Root() interface{} {
return s.trie.Root
}
// Object manifest

View File

@ -6,7 +6,6 @@ import (
"fmt"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
@ -37,7 +36,7 @@ type EthManager interface {
BlockChain() *BlockChain
TxPool() *TxPool
Broadcast(msgType ethwire.MsgType, data []interface{})
Reactor() *ethreact.ReactorEngine
Reactor() *ethutil.ReactorEngine
PeerCount() int
IsMining() bool
IsListening() bool
@ -67,6 +66,11 @@ type StateManager struct {
// Mining state. The mining state is used purely and solely by the mining
// operation.
miningState *State
// The last attempted block is mainly used for debugging purposes
// This does not have to be a valid block and will be set during
// 'Process' & canonical validation.
lastAttemptedBlock *Block
}
func NewStateManager(ethereum EthManager) *StateManager {
@ -146,6 +150,10 @@ done:
receipts = append(receipts, receipt)
handled = append(handled, tx)
if ethutil.Config.Diff {
state.CreateOutputForDiff()
}
}
parent.GasUsed = totalUsedGas
@ -166,6 +174,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
return ParentError(block.PrevHash)
}
sm.lastAttemptedBlock = block
var (
parent = sm.bc.GetBlock(block.PrevHash)
state = parent.State()
@ -177,6 +187,10 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
// before that.
defer state.Reset()
if ethutil.Config.Diff {
fmt.Printf("## 0x%x 0x%x ##\n", block.Hash(), block.Number)
}
receipts, err := sm.ApplyDiff(state, parent, block)
defer func() {
if err != nil {

View File

@ -27,6 +27,8 @@ type StateObject struct {
script Code
initScript Code
storage map[string]*ethutil.Value
// Total gas pool is the total amount of gas currently
// left if this object is the coinbase. Gas is directly
// purchased of the coinbase.
@ -38,6 +40,10 @@ type StateObject struct {
remove bool
}
func (self *StateObject) Reset() {
self.storage = make(map[string]*ethutil.Value)
}
// Converts an transaction in to a state object
func MakeContract(tx *Transaction, state *State) *StateObject {
// Create contract if there's no recipient
@ -55,14 +61,19 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
}
func NewStateObject(addr []byte) *StateObject {
object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)}
// This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter.
address := ethutil.LeftPadBytes(addr, 20)
object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)}
object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
object.storage = make(map[string]*ethutil.Value)
return object
}
func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject {
contract := &StateObject{address: address, Amount: Amount, Nonce: 0}
contract := NewStateObject(address)
contract.Amount = Amount
contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root)))
return contract
@ -84,6 +95,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject {
func (self *StateObject) MarkForDeletion() {
self.remove = true
statelogger.Infof("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount)
}
func (c *StateObject) GetAddr(addr []byte) *ethutil.Value {
@ -94,24 +106,43 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) {
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
}
func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) {
addr := ethutil.BigToBytes(num, 256)
func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value {
return self.getStorage(key.Bytes())
}
func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) {
self.setStorage(key.Bytes(), value)
}
if val.BigInt().Cmp(ethutil.Big0) == 0 {
c.state.trie.Delete(string(addr))
func (self *StateObject) getStorage(key []byte) *ethutil.Value {
k := ethutil.LeftPadBytes(key, 32)
return
value := self.storage[string(k)]
if value == nil {
value = self.GetAddr(k)
self.storage[string(k)] = value
}
c.SetAddr(addr, val)
return value
}
func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value {
nb := ethutil.BigToBytes(num, 256)
func (self *StateObject) setStorage(key []byte, value *ethutil.Value) {
k := ethutil.LeftPadBytes(key, 32)
return c.GetAddr(nb)
self.storage[string(k)] = value
}
func (self *StateObject) Sync() {
for key, value := range self.storage {
if value.BigInt().Cmp(ethutil.Big0) == 0 {
self.state.trie.Delete(string(key))
continue
}
self.SetAddr([]byte(key), value)
}
}
func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
if int64(len(c.script)-1) < pc.Int64() {
return ethutil.NewValue(0)
@ -248,6 +279,7 @@ func (c *StateObject) RlpDecode(data []byte) {
c.Nonce = decoder.Get(0).Uint()
c.Amount = decoder.Get(1).BigInt()
c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
c.storage = make(map[string]*ethutil.Value)
c.ScriptHash = decoder.Get(3).Bytes()

View File

@ -164,8 +164,6 @@ func (self *StateTransition) TransitionState() (err error) {
// Increment the nonce for the next transaction
sender.Nonce += 1
receiver = self.Receiver()
// Transaction gas
if err = self.UseGas(GasTx); err != nil {
return
@ -178,13 +176,23 @@ func (self *StateTransition) TransitionState() (err error) {
return
}
/* FIXME
* If tx goes TO "0", goes OOG during init, reverse changes, but initial endowment should happen. The ether is lost forever
*/
var snapshot *State
// If the receiver is nil it's a contract (\0*32).
if receiver == nil {
if tx.CreatesContract() {
snapshot = self.state.Copy()
// Create a new state object for the contract
receiver = self.MakeStateObject(self.state, tx)
self.rec = receiver
if receiver == nil {
return fmt.Errorf("Unable to create contract")
}
} else {
receiver = self.Receiver()
}
// Transfer value from sender to receiver
@ -192,7 +200,9 @@ func (self *StateTransition) TransitionState() (err error) {
return
}
//snapshot := self.state.Copy()
if snapshot == nil {
snapshot = self.state.Copy()
}
// Process the init code and create 'valid' contract
if IsContractAddr(self.receiver) {
@ -203,8 +213,7 @@ func (self *StateTransition) TransitionState() (err error) {
code, err := self.Eval(receiver.Init(), receiver, "init")
if err != nil {
//self.state.Set(snapshot)
self.state.ResetStateObject(receiver)
self.state.Set(snapshot)
return fmt.Errorf("Error during init execution %v", err)
}
@ -214,8 +223,7 @@ func (self *StateTransition) TransitionState() (err error) {
if len(receiver.Script()) > 0 {
_, err = self.Eval(receiver.Script(), receiver, "code")
if err != nil {
//self.state.Set(snapshot)
self.state.ResetStateObject(receiver)
self.state.Set(snapshot)
return fmt.Errorf("Error during code execution %v", err)
}

View File

@ -22,12 +22,16 @@ var (
GasMemory = big.NewInt(1)
GasData = big.NewInt(5)
GasTx = big.NewInt(500)
LogTyPretty byte = 0x1
LogTyDiff byte = 0x2
)
type Debugger interface {
BreakHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
StepHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
BreakPoints() []int64
SetCode(byteCode []byte)
}
type Vm struct {
@ -44,6 +48,7 @@ type Vm struct {
Verbose bool
logTy byte
logStr string
err error
@ -69,7 +74,7 @@ type RuntimeVars struct {
}
func (self *Vm) Printf(format string, v ...interface{}) *Vm {
if self.Verbose {
if self.Verbose && self.logTy == LogTyPretty {
self.logStr += fmt.Sprintf(format, v...)
}
@ -77,7 +82,7 @@ func (self *Vm) Printf(format string, v ...interface{}) *Vm {
}
func (self *Vm) Endl() *Vm {
if self.Verbose {
if self.Verbose && self.logTy == LogTyPretty {
vmlogger.Debugln(self.logStr)
self.logStr = ""
}
@ -86,7 +91,12 @@ func (self *Vm) Endl() *Vm {
}
func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm {
return &Vm{vars: vars, state: state, stateManager: stateManager}
lt := LogTyPretty
if ethutil.Config.Diff {
lt = LogTyDiff
}
return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: lt}
}
var Pow256 = ethutil.BigPow(2, 256)
@ -103,7 +113,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
}
}()
vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.object.Address(), closure.Gas, closure.Args)
// Debug hook
if vm.Dbg != nil {
vm.Dbg.SetCode(closure.Script)
}
// Don't bother with the execution if there's no code.
if len(closure.Script) == 0 {
return closure.Return(nil), nil
}
vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.Address(), closure.Gas, closure.Args)
var (
op OpCode
@ -132,6 +152,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
// Get the opcode (it must be an opcode!)
op = OpCode(val.Uint())
// XXX Leave this Println intact. Don't change this to the log system.
// Used for creating diffs between implementations
if vm.logTy == LogTyDiff {
b := pc.Bytes()
if len(b) == 0 {
b = []byte{0}
}
fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes())
}
gas := new(big.Int)
addStepGasUsage := func(amount *big.Int) {
if amount.Cmp(ethutil.Big0) >= 0 {
@ -167,7 +198,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
require(2)
newMemSize = stack.Peek().Uint64() + 32
case MLOAD:
require(1)
newMemSize = stack.Peek().Uint64() + 32
case MSTORE8:
require(2)
newMemSize = stack.Peek().Uint64() + 1
@ -415,7 +448,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
require(2)
val, th := stack.Popn()
if th.Cmp(big.NewInt(32)) < 0 {
stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64()))
byt := big.NewInt(int64(val.Bytes()[th.Int64()]))
stack.Push(byt)
vm.Printf(" => 0x%x", byt.Bytes())
} else {
stack.Push(ethutil.BigFalse)
}
@ -427,13 +463,26 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64()))
stack.Push(ethutil.BigD(data))
vm.Printf(" => %x", data)
// 0x30 range
case ADDRESS:
stack.Push(ethutil.BigD(closure.Object().Address()))
stack.Push(ethutil.BigD(closure.Address()))
vm.Printf(" => %x", closure.Address())
case BALANCE:
stack.Push(closure.object.Amount)
require(1)
addr := stack.Pop().Bytes()
balance := vm.state.GetBalance(addr)
stack.Push(balance)
vm.Printf(" => %v (%x)", balance, addr)
case ORIGIN:
stack.Push(ethutil.BigD(vm.vars.Origin))
vm.Printf(" => %v", vm.vars.Origin)
case CALLER:
caller := closure.caller.Address()
stack.Push(ethutil.BigD(caller))
@ -441,6 +490,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
vm.Printf(" => %x", caller)
case CALLVALUE:
stack.Push(vm.vars.Value)
vm.Printf(" => %v", vm.vars.Value)
case CALLDATALOAD:
require(1)
offset := stack.Pop().Int64()
@ -499,8 +550,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
}
code := closure.Script[cOff : cOff+l]
fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff)
mem.Set(mOff, l, code)
fmt.Println(Code(mem.Get(mOff, l)))
case GASPRICE:
stack.Push(closure.Price)
@ -562,8 +615,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case MSTORE8:
require(2)
val, mStart := stack.Popn()
base.And(val, new(big.Int).SetInt64(0xff))
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
//base.And(val, new(big.Int).SetInt64(0xff))
//mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
mem.store[mStart.Int64()] = byte(val.Int64() & 0xff)
vm.Printf(" => 0x%x", val)
case SLOAD:
@ -623,9 +677,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
)
// Generate a new address
addr := ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce)
addr := ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64())
for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ {
ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce+i)
ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()+i)
}
closure.object.Nonce++
@ -638,14 +692,15 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
contract.AddAmount(value)
// Set the init script
contract.initScript = mem.Get(offset.Int64(), size.Int64())
initCode := mem.Get(offset.Int64(), size.Int64())
//fmt.Printf("%x\n", initCode)
// Transfer all remaining gas to the new
// contract so it may run the init script
gas := new(big.Int).Set(closure.Gas)
closure.UseGas(closure.Gas)
// Create the closure
c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price)
c := NewClosure(closure, contract, initCode, vm.state, gas, closure.Price)
// Call the closure and set the return value as
// main script.
contract.script, err = Call(vm, c, nil)
@ -665,6 +720,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
vm.Printf("CREATE success")
}
vm.Endl()
// Debug hook
if vm.Dbg != nil {
vm.Dbg.SetCode(closure.Script)
}
case CALL:
require(7)
@ -683,10 +743,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
if closure.object.Amount.Cmp(value) < 0 {
vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount)
closure.ReturnGas(gas, nil, nil)
stack.Push(ethutil.BigFalse)
} else {
//snapshot := vm.state.Copy()
snapshot := vm.state.Copy()
stateObject := vm.state.GetOrNewStateObject(addr.Bytes())
@ -702,13 +763,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
vmlogger.Debugf("Closure execution failed. %v\n", err)
//vm.state.Set(snapshot)
vm.state.ResetStateObject(stateObject)
vm.state.Set(snapshot)
} else {
stack.Push(ethutil.BigTrue)
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
}
// Debug hook
if vm.Dbg != nil {
vm.Dbg.SetCode(closure.Script)
}
}
case RETURN:
require(2)
@ -721,18 +786,12 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case SUICIDE:
require(1)
receiver := vm.state.GetAccount(stack.Pop().Bytes())
receiver := vm.state.GetOrNewStateObject(stack.Pop().Bytes())
receiver.AddAmount(closure.object.Amount)
closure.object.MarkForDeletion()
/*
trie := closure.object.state.trie
trie.NewIterator().Each(func(key string, v *ethutil.Value) {
trie.Delete(key)
})
*/
fallthrough
case STOP: // Stop the closure
vm.Endl()
@ -752,6 +811,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
if vm.Dbg != nil {
for _, instrNo := range vm.Dbg.BreakPoints() {
if pc.Cmp(big.NewInt(instrNo)) == 0 {
vm.Stepping = true
if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) {
return nil, nil
}

View File

@ -2,9 +2,9 @@ package ethcrypto
import (
"code.google.com/p/go.crypto/ripemd160"
"code.google.com/p/go.crypto/sha3"
"crypto/sha256"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/sha3"
)
func Sha256Bin(data []byte) []byte {

View File

@ -3,7 +3,9 @@ package ethcrypto
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
@ -12,6 +14,14 @@ import (
func InitWords() []string {
_, thisfile, _, _ := runtime.Caller(1)
filename := path.Join(path.Dir(thisfile), "mnemonic.words.lst")
if _, err := os.Stat(filename); os.IsNotExist(err) {
fmt.Printf("reading mnemonic word list file 'mnemonic.words.lst' from source folder failed, looking in current folder.")
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
panic(fmt.Errorf("problem getting current folder: ", err))
}
filename = path.Join(dir, "mnemonic.words.lst")
}
content, err := ioutil.ReadFile(filename)
if err != nil {
panic(fmt.Errorf("reading mnemonic word list file 'mnemonic.words.lst' failed: ", err))

View File

@ -6,7 +6,6 @@ import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethrpc"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
@ -21,6 +20,8 @@ import (
"time"
)
const seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt"
var ethlogger = ethlog.NewLogger("SERV")
func eachPeer(peers *list.List, callback func(*Peer, *list.Element)) {
@ -72,7 +73,7 @@ type Ethereum struct {
listening bool
reactor *ethreact.ReactorEngine
reactor *ethutil.ReactorEngine
RpcServer *ethrpc.JsonRpcServer
@ -107,7 +108,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager
keyManager: keyManager,
clientIdentity: clientIdentity,
}
ethereum.reactor = ethreact.New()
ethereum.reactor = ethutil.NewReactorEngine()
ethereum.txPool = ethchain.NewTxPool(ethereum)
ethereum.blockChain = ethchain.NewBlockChain(ethereum)
@ -119,7 +120,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager
return ethereum, nil
}
func (s *Ethereum) Reactor() *ethreact.ReactorEngine {
func (s *Ethereum) Reactor() *ethutil.ReactorEngine {
return s.reactor
}
@ -351,7 +352,6 @@ func (s *Ethereum) ReapDeadPeerHandler() {
// Start the ethereum
func (s *Ethereum) Start(seed bool) {
s.reactor.Start()
// Bind to addr and port
ln, err := net.Listen("tcp", ":"+s.Port)
if err != nil {
@ -418,7 +418,7 @@ func (s *Ethereum) Seed() {
s.ProcessPeerList(peers)
} else {
// Fallback to servers.poc3.txt
resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt")
resp, err := http.Get(seedTextFileUri)
if err != nil {
ethlogger.Warnln("Fetching seed failed:", err)
return
@ -463,9 +463,6 @@ func (s *Ethereum) Stop() {
s.txPool.Stop()
s.stateManager.Stop()
s.reactor.Flush()
s.reactor.Stop()
ethlogger.Infoln("Server stopped")
close(s.shutdownChan)
}

View File

@ -97,7 +97,6 @@ func Reset() {
}
<-status
}
logSystems = nil
}
// waits until log messages are drained (dispatched to log writers)
@ -116,6 +115,7 @@ func NewLogger(tag string) *Logger {
}
func AddLogSystem(logSystem LogSystem) {
var mutex = &sync.Mutex{}
mutex.Lock()
defer mutex.Unlock()
if logSystems == nil {
@ -128,14 +128,16 @@ func AddLogSystem(logSystem LogSystem) {
}
func (logger *Logger) sendln(level LogLevel, v ...interface{}) {
if logSystems != nil {
send(newPrintlnLogMessage(level, logger.tag, v...))
if logMessages != nil {
msg := newPrintlnLogMessage(level, logger.tag, v...)
logMessages <- msg
}
}
func (logger *Logger) sendf(level LogLevel, format string, v ...interface{}) {
if logSystems != nil {
send(newPrintfLogMessage(level, logger.tag, format, v...))
if logMessages != nil {
msg := newPrintfLogMessage(level, logger.tag, format, v...)
logMessages <- msg
}
}

View File

@ -54,8 +54,9 @@ func TestLoggerPrintln(t *testing.T) {
Flush()
Reset()
output := testLogSystem.Output
fmt.Println(quote(output))
if output != "[TEST] error\n[TEST] warn\n" {
t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", testLogSystem.Output)
t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", output)
}
}
@ -71,7 +72,7 @@ func TestLoggerPrintf(t *testing.T) {
Reset()
output := testLogSystem.Output
if output != "[TEST] error to { 2}\n[TEST] warn" {
t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", testLogSystem.Output)
t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", output)
}
}
@ -88,10 +89,10 @@ func TestMultipleLogSystems(t *testing.T) {
output0 := testLogSystem0.Output
output1 := testLogSystem1.Output
if output0 != "[TEST] error\n" {
t.Error("Expected logger 0 output '[TEST] error\\n', got ", testLogSystem0.Output)
t.Error("Expected logger 0 output '[TEST] error\\n', got ", output0)
}
if output1 != "[TEST] error\n[TEST] warn\n" {
t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", testLogSystem1.Output)
t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", output1)
}
}
@ -104,7 +105,6 @@ func TestFileLogSystem(t *testing.T) {
logger.Errorf("error to %s\n", filename)
logger.Warnln("warn")
Flush()
Reset()
contents, _ := ioutil.ReadFile(filename)
output := string(contents)
if output != "[TEST] error to test.log\n[TEST] warn\n" {
@ -117,7 +117,5 @@ func TestFileLogSystem(t *testing.T) {
func TestNoLogSystem(t *testing.T) {
logger := NewLogger("TEST")
logger.Warnln("warn")
fmt.Println("1")
Flush()
Reset()
}

View File

@ -4,7 +4,7 @@ import (
"bytes"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"sort"
)
@ -15,19 +15,19 @@ type Miner struct {
pow ethchain.PoW
ethereum ethchain.EthManager
coinbase []byte
reactChan chan ethreact.Event
reactChan chan ethutil.React
txs ethchain.Transactions
uncles []*ethchain.Block
block *ethchain.Block
powChan chan []byte
powQuitChan chan ethreact.Event
powQuitChan chan ethutil.React
quitChan chan bool
}
func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
reactChan := make(chan ethreact.Event, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
powQuitChan := make(chan ethreact.Event, 1) // This is the channel that can exit the miner thread
reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
powQuitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread
quitChan := make(chan bool, 1)
ethereum.Reactor().Subscribe("newBlock", reactChan)

View File

@ -1,40 +0,0 @@
# ethreact
ethereum event reactor. Component of the ethereum stack.
various events like state change on an account or new block found are broadcast to subscribers.
Broadcasting to subscribers is running on its own routine and globally order preserving.
## Clients
### subscribe
eventChannel := make(chan ethreact.Event)
reactor.Subscribe(event, eventChannel)
The same channel can be subscribed to multiple events but only once for each event. In order to allow order of events to be preserved, broadcast of events is synchronous within the main broadcast loop. Therefore any blocking subscriber channels will be skipped, i.e. missing broadcasting events while they are blocked.
### unsubscribe
reactor.Unsubscribe(event, eventChannel)
### Processing events
event.Resource is of type interface{}. The actual type of event.Resource depends on event.Name and may need to be cast for processing.
var event ethreact.Event
for {
select {
case event = <-eventChannel:
processTransaction(event.Resource.(Transaction))
}
}
## Broadcast
reactor := ethreact.New()
reactor.Start()
reactor.Post(name, resource)
reactor.Flush() // wait till all broadcast messages are dispatched
reactor.Stop() // stop the main broadcast loop immediately (even if there are unbroadcast events left)

View File

@ -1,63 +0,0 @@
package ethreact
import (
"fmt"
"testing"
)
func TestReactorAdd(t *testing.T) {
reactor := New()
ch := make(chan Event)
reactor.Subscribe("test", ch)
if reactor.eventHandlers["test"] == nil {
t.Error("Expected new eventHandler to be created")
}
reactor.Unsubscribe("test", ch)
if reactor.eventHandlers["test"] != nil {
t.Error("Expected eventHandler to be removed")
}
}
func TestReactorEvent(t *testing.T) {
var name string
reactor := New()
// Buffer the channel, so it doesn't block for this test
cap := 20
ch := make(chan Event, cap)
reactor.Subscribe("even", ch)
reactor.Subscribe("odd", ch)
reactor.Post("even", "disappears") // should not broadcast if engine not started
reactor.Start()
for i := 0; i < cap; i++ {
if i%2 == 0 {
name = "even"
} else {
name = "odd"
}
reactor.Post(name, i)
}
reactor.Post("test", cap) // this should not block
i := 0
reactor.Flush()
close(ch)
for event := range ch {
fmt.Printf("%d: %v", i, event)
if i%2 == 0 {
name = "even"
} else {
name = "odd"
}
if val, ok := event.Resource.(int); ok {
if i != val || event.Name != name {
t.Error("Expected event %d to be of type %s and resource %d, got ", i, name, i, val)
}
} else {
t.Error("Unable to cast")
}
i++
}
if i != cap {
t.Error("excpected exactly %d events, got ", i)
}
reactor.Stop()
}

View File

@ -3,8 +3,20 @@ package ethutil
import (
"fmt"
"math/big"
"runtime"
)
func IsWindows() bool {
return runtime.GOOS == "windows"
}
func WindonizePath(path string) string {
if string(path[0]) == "/" && IsWindows() {
path = path[1:]
}
return path
}
// The different number of units
var (
Douglas = BigPow(10, 42)

View File

@ -13,6 +13,7 @@ type ConfigManager struct {
ExecPath string
Debug bool
Diff bool
Paranoia bool
conf *globalconf.GlobalConf

87
ethutil/reactor.go Normal file
View File

@ -0,0 +1,87 @@
package ethutil
import (
"sync"
)
type ReactorEvent struct {
mut sync.Mutex
event string
chans []chan React
}
// Post the specified reactor resource on the channels
// currently subscribed
func (e *ReactorEvent) Post(react React) {
e.mut.Lock()
defer e.mut.Unlock()
for _, ch := range e.chans {
go func(ch chan React) {
ch <- react
}(ch)
}
}
// Add a subscriber to this event
func (e *ReactorEvent) Add(ch chan React) {
e.mut.Lock()
defer e.mut.Unlock()
e.chans = append(e.chans, ch)
}
// Remove a subscriber
func (e *ReactorEvent) Remove(ch chan React) {
e.mut.Lock()
defer e.mut.Unlock()
for i, c := range e.chans {
if c == ch {
e.chans = append(e.chans[:i], e.chans[i+1:]...)
}
}
}
// Basic reactor resource
type React struct {
Resource interface{}
Event string
}
// The reactor basic engine. Acts as bridge
// between the events and the subscribers/posters
type ReactorEngine struct {
patterns map[string]*ReactorEvent
}
func NewReactorEngine() *ReactorEngine {
return &ReactorEngine{patterns: make(map[string]*ReactorEvent)}
}
// Subscribe a channel to the specified event
func (reactor *ReactorEngine) Subscribe(event string, ch chan React) {
ev := reactor.patterns[event]
// Create a new event if one isn't available
if ev == nil {
ev = &ReactorEvent{event: event}
reactor.patterns[event] = ev
}
// Add the channel to reactor event handler
ev.Add(ch)
}
func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) {
ev := reactor.patterns[event]
if ev != nil {
ev.Remove(ch)
}
}
func (reactor *ReactorEngine) Post(event string, resource interface{}) {
ev := reactor.patterns[event]
if ev != nil {
ev.Post(React{Resource: resource, Event: event})
}
}

30
ethutil/reactor_test.go Normal file
View File

@ -0,0 +1,30 @@
package ethutil
import "testing"
func TestReactorAdd(t *testing.T) {
engine := NewReactorEngine()
ch := make(chan React)
engine.Subscribe("test", ch)
if len(engine.patterns) != 1 {
t.Error("Expected patterns to be 1, got", len(engine.patterns))
}
}
func TestReactorEvent(t *testing.T) {
engine := NewReactorEngine()
// Buffer 1, so it doesn't block for this test
ch := make(chan React, 1)
engine.Subscribe("test", ch)
engine.Post("test", "hello")
value := <-ch
if val, ok := value.Resource.(string); ok {
if val != "hello" {
t.Error("Expected Resource to be 'hello', got", val)
}
} else {
t.Error("Unable to cast")
}
}

View File

@ -4,7 +4,6 @@ import (
"fmt"
"github.com/obscuren/mutan"
"github.com/obscuren/mutan/backends"
"github.com/obscuren/serpent-go"
"strings"
)
@ -15,13 +14,15 @@ func Compile(script string, silent bool) (ret []byte, err error) {
if len(line) > 1 && line[0:2] == "#!" {
switch line {
case "#!serpent":
byteCode, err := serpent.Compile(script)
if err != nil {
return nil, err
}
/*
case "#!serpent":
byteCode, err := serpent.Compile(script)
if err != nil {
return nil, err
}
return byteCode, nil
return byteCode, nil
*/
}
} else {

View File

@ -279,7 +279,7 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) {
var totalBytes int
for {
// Give buffering some time
conn.SetReadDeadline(time.Now().Add(50 * time.Millisecond))
conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
// Create a new temporarily buffer
b := make([]byte, 1440)
// Wait for a message from this peer

18
peer.go
View File

@ -21,7 +21,7 @@ const (
// The size of the output buffer for writing messages
outputBufferSize = 50
// Current protocol version
ProtocolVersion = 21
ProtocolVersion = 23
// Interval for ping/pong message
pingPongTimer = 2 * time.Second
)
@ -252,7 +252,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) {
}
}
peerlogger.DebugDetailln("<=", msg.Type, msg.Data)
peerlogger.DebugDetailf("(%v) <= %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data)
err := ethwire.WriteMessage(p.conn, msg)
if err != nil {
@ -326,7 +326,7 @@ func (p *Peer) HandleInbound() {
peerlogger.Debugln(err)
}
for _, msg := range msgs {
peerlogger.DebugDetailln("=>", msg.Type, msg.Data)
peerlogger.DebugDetailf("(%v) => %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data)
switch msg.Type {
case ethwire.MsgHandshakeTy:
@ -419,6 +419,16 @@ func (p *Peer) HandleInbound() {
if err != nil {
// If the parent is unknown try to catch up with this peer
if ethchain.IsParentErr(err) {
/*
b := ethchain.NewBlockFromRlpValue(msg.Data.Get(0))
peerlogger.Infof("Attempting to catch (%x). Parent known\n", b.Hash())
p.catchingUp = false
p.CatchupWithPeer(b.Hash())
peerlogger.Infoln(b)
*/
peerlogger.Infoln("Attempting to catch. Parent known")
p.catchingUp = false
p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
@ -744,7 +754,7 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) {
if !p.catchingUp {
// Make sure nobody else is catching up when you want to do this
p.catchingUp = true
msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)})
msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(10)})
p.QueueMessage(msg)
peerlogger.DebugDetailf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr())