From ec040908e9e69e524811b6ade95227a3764de4ae Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 10:52:39 +0200 Subject: [PATCH 01/30] Protocol bump --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index a93d22d93a..e11ac0a570 100644 --- a/peer.go +++ b/peer.go @@ -21,7 +21,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 21 + ProtocolVersion = 22 // Interval for ping/pong message pingPongTimer = 2 * time.Second ) From 1199941475452e8d62fb2d5b634672e3f7c48bfd Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 10:52:58 +0200 Subject: [PATCH 02/30] Connect to peer node by default --- ethereum.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethereum.go b/ethereum.go index 35d98e8311..f4c497ca47 100644 --- a/ethereum.go +++ b/ethereum.go @@ -430,6 +430,8 @@ func (s *Ethereum) Seed() { s.ConnectToPeer(string(body)) } + + s.ConnectToPeer("54.204.10.41:30303") } func (s *Ethereum) peerHandler(listener net.Listener) { From d40cba3042564f3471aa20a5cf477cafcacc2189 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 10:53:20 +0200 Subject: [PATCH 03/30] changed state reset --- ethchain/state.go | 4 +++- ethchain/state_transition.go | 14 ++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 20af94fe83..5d023df7b1 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -161,7 +161,9 @@ func (self *State) Set(state *State) { panic("Tried setting 'state' to nil through 'Set'") } - *self = *state + self.trie = state.trie + self.stateObjects = state.stateObjects + //*self = *state } func (s *State) Put(key, object []byte) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 6ea9a837d7..a92aa4a339 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -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,6 +176,10 @@ func (self *StateTransition) TransitionState() (err error) { return } + snapshot := self.state.Copy() + + receiver = self.Receiver() + // If the receiver is nil it's a contract (\0*32). if receiver == nil { // Create a new state object for the contract @@ -192,8 +194,6 @@ func (self *StateTransition) TransitionState() (err error) { return } - //snapshot := self.state.Copy() - // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { // Evaluate the initialization script @@ -203,8 +203,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 +213,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) } From 6fe9b4ab5e839be96eb1c4a619bc14fab622d8d1 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Mon, 7 Jul 2014 10:59:16 +0200 Subject: [PATCH 04/30] Revert "ethreact - Feature/ethutil refactor" --- ethchain/dagger.go | 5 +- ethchain/state_manager.go | 3 +- ethereum.go | 11 +-- ethlog/loggers.go | 57 ++++-------- ethlog/loggers_test.go | 23 ++--- ethminer/miner.go | 12 +-- ethreact/README.md | 40 --------- ethreact/reactor.go | 181 -------------------------------------- ethreact/reactor_test.go | 63 ------------- ethutil/reactor.go | 87 ++++++++++++++++++ ethutil/reactor_test.go | 30 +++++++ 11 files changed, 159 insertions(+), 353 deletions(-) delete mode 100644 ethreact/README.md delete mode 100644 ethreact/reactor.go delete mode 100644 ethreact/reactor_test.go create mode 100644 ethutil/reactor.go create mode 100644 ethutil/reactor_test.go diff --git a/ethchain/dagger.go b/ethchain/dagger.go index adf1c2f05e..4dda21ff5d 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -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 diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 52a73beb82..f3fd929137 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -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 diff --git a/ethereum.go b/ethereum.go index 69fcc338e7..f4c497ca47 100644 --- a/ethereum.go +++ b/ethereum.go @@ -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" @@ -72,7 +71,7 @@ type Ethereum struct { listening bool - reactor *ethreact.ReactorEngine + reactor *ethutil.ReactorEngine RpcServer *ethrpc.JsonRpcServer @@ -107,7 +106,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 +118,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 +350,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 { @@ -465,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) } diff --git a/ethlog/loggers.go b/ethlog/loggers.go index d7707cf9e4..219c782408 100644 --- a/ethlog/loggers.go +++ b/ethlog/loggers.go @@ -40,9 +40,6 @@ func (msg *logMessage) send(logger LogSystem) { var logMessages chan (*logMessage) var logSystems []LogSystem var quit chan bool -var drained chan bool -var shutdown chan bool -var mutex = sync.Mutex{} type LogLevel uint8 @@ -60,41 +57,29 @@ func start() { out: for { select { - case <-quit: - break out case msg := <-logMessages: for _, logSystem := range logSystems { if logSystem.GetLogLevel() >= msg.LogLevel { msg.send(logSystem) } } - case drained <- true: - default: - drained <- true // this blocks until a message is sent to the queu - } - } - close(shutdown) -} - -func Reset() { - mutex.Lock() - defer mutex.Unlock() - if logSystems != nil { - quit <- true - select { - case <-drained: + case <-quit: + break out } - <-shutdown } - logSystems = nil } // waits until log messages are drained (dispatched to log writers) func Flush() { - mutex.Lock() - defer mutex.Unlock() - if logSystems != nil { - <-drained + quit <- true + +done: + for { + select { + case <-logMessages: + default: + break done + } } } @@ -107,34 +92,28 @@ func NewLogger(tag string) *Logger { } func AddLogSystem(logSystem LogSystem) { + var mutex = &sync.Mutex{} mutex.Lock() defer mutex.Unlock() if logSystems == nil { logMessages = make(chan *logMessage) quit = make(chan bool) - drained = make(chan bool, 1) - shutdown = make(chan bool, 1) go start() } logSystems = append(logSystems, logSystem) } -func send(msg *logMessage) { - select { - case <-drained: - } - logMessages <- msg -} - 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 } } diff --git a/ethlog/loggers_test.go b/ethlog/loggers_test.go index 9fff471c18..89f4166810 100644 --- a/ethlog/loggers_test.go +++ b/ethlog/loggers_test.go @@ -28,6 +28,10 @@ func (t *TestLogSystem) GetLogLevel() LogLevel { return t.level } +func quote(s string) string { + return fmt.Sprintf("'%s'", s) +} + func TestLoggerPrintln(t *testing.T) { logger := NewLogger("TEST") testLogSystem := &TestLogSystem{level: WarnLevel} @@ -37,10 +41,10 @@ func TestLoggerPrintln(t *testing.T) { logger.Infoln("info") logger.Debugln("debug") 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 ", quote(testLogSystem.Output)) } } @@ -53,10 +57,10 @@ func TestLoggerPrintf(t *testing.T) { logger.Infof("info") logger.Debugf("debug") Flush() - Reset() output := testLogSystem.Output + fmt.Println(quote(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 ", quote(testLogSystem.Output)) } } @@ -69,14 +73,13 @@ func TestMultipleLogSystems(t *testing.T) { logger.Errorln("error") logger.Warnln("warn") Flush() - Reset() 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 ", quote(testLogSystem0.Output)) } 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 ", quote(testLogSystem1.Output)) } } @@ -89,11 +92,11 @@ func TestFileLogSystem(t *testing.T) { logger.Errorf("error to %s\n", filename) logger.Warnln("warn") Flush() - Reset() contents, _ := ioutil.ReadFile(filename) output := string(contents) + fmt.Println(quote(output)) if output != "[TEST] error to test.log\n[TEST] warn\n" { - t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", output) + t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", quote(output)) } else { os.Remove(filename) } @@ -102,7 +105,5 @@ func TestFileLogSystem(t *testing.T) { func TestNoLogSystem(t *testing.T) { logger := NewLogger("TEST") logger.Warnln("warn") - fmt.Println("1") Flush() - Reset() } diff --git a/ethminer/miner.go b/ethminer/miner.go index 8224c5441b..71d4b2428a 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -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) diff --git a/ethreact/README.md b/ethreact/README.md deleted file mode 100644 index 592b50b96a..0000000000 --- a/ethreact/README.md +++ /dev/null @@ -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) - - - diff --git a/ethreact/reactor.go b/ethreact/reactor.go deleted file mode 100644 index f42f71202b..0000000000 --- a/ethreact/reactor.go +++ /dev/null @@ -1,181 +0,0 @@ -package ethreact - -import ( - "github.com/ethereum/eth-go/ethlog" - "sync" -) - -var logger = ethlog.NewLogger("REACTOR") - -type EventHandler struct { - lock sync.RWMutex - name string - chans []chan Event -} - -// Post the Event with the reactor resource on the channels -// currently subscribed to the event -func (e *EventHandler) Post(event Event) { - e.lock.RLock() - defer e.lock.RUnlock() - - // if we want to preserve order pushing to subscibed channels - // dispatching should be syncrounous - // this means if subscribed event channel is blocked (closed or has fixed capacity) - // the reactor dispatch will be blocked, so we need to mitigate by skipping - // rogue blocking subscribers - for i, ch := range e.chans { - select { - case ch <- event: - default: - logger.Warnf("subscribing channel %d to event %s blocked. skipping\n", i, event.Name) - } - } -} - -// Add a subscriber to this event -func (e *EventHandler) Add(ch chan Event) { - e.lock.Lock() - defer e.lock.Unlock() - - e.chans = append(e.chans, ch) -} - -// Remove a subscriber -func (e *EventHandler) Remove(ch chan Event) int { - e.lock.Lock() - defer e.lock.Unlock() - - for i, c := range e.chans { - if c == ch { - e.chans = append(e.chans[:i], e.chans[i+1:]...) - } - } - return len(e.chans) -} - -// Basic reactor resource -type Event struct { - Resource interface{} - Name string -} - -// The reactor basic engine. Acts as bridge -// between the events and the subscribers/posters -type ReactorEngine struct { - lock sync.RWMutex - eventChannel chan Event - eventHandlers map[string]*EventHandler - quit chan bool - shutdownChannel chan bool - running bool - drained chan bool -} - -func New() *ReactorEngine { - return &ReactorEngine{ - eventHandlers: make(map[string]*EventHandler), - eventChannel: make(chan Event), - quit: make(chan bool, 1), - drained: make(chan bool, 1), - shutdownChannel: make(chan bool, 1), - } -} - -func (reactor *ReactorEngine) Start() { - reactor.lock.Lock() - defer reactor.lock.Unlock() - if !reactor.running { - go func() { - out: - for { - select { - case <-reactor.quit: - break out - case event := <-reactor.eventChannel: - // needs to be called syncronously to keep order of events - reactor.dispatch(event) - case reactor.drained <- true: - default: - reactor.drained <- true // blocking till message is coming in - } - } - reactor.lock.Lock() - defer reactor.lock.Unlock() - reactor.running = false - logger.Infoln("stopped") - close(reactor.shutdownChannel) - }() - reactor.running = true - logger.Infoln("started") - } -} - -func (reactor *ReactorEngine) Stop() { - reactor.lock.RLock() - if reactor.running { - reactor.quit <- true - select { - case <-reactor.drained: - } - } - reactor.lock.RUnlock() - <-reactor.shutdownChannel -} - -func (reactor *ReactorEngine) Flush() { - <-reactor.drained -} - -// Subscribe a channel to the specified event -func (reactor *ReactorEngine) Subscribe(event string, eventChannel chan Event) { - reactor.lock.Lock() - defer reactor.lock.Unlock() - - eventHandler := reactor.eventHandlers[event] - // Create a new event handler if one isn't available - if eventHandler == nil { - eventHandler = &EventHandler{name: event} - reactor.eventHandlers[event] = eventHandler - } - // Add the events channel to reactor event handler - eventHandler.Add(eventChannel) - logger.Debugf("added new subscription to %s", event) -} - -func (reactor *ReactorEngine) Unsubscribe(event string, eventChannel chan Event) { - reactor.lock.Lock() - defer reactor.lock.Unlock() - - eventHandler := reactor.eventHandlers[event] - if eventHandler != nil { - len := eventHandler.Remove(eventChannel) - if len == 0 { - reactor.eventHandlers[event] = nil - } - logger.Debugf("removed subscription to %s", event) - } -} - -func (reactor *ReactorEngine) Post(event string, resource interface{}) { - reactor.lock.Lock() - defer reactor.lock.Unlock() - - if reactor.running { - reactor.eventChannel <- Event{Resource: resource, Name: event} - select { - case <-reactor.drained: - } - } -} - -func (reactor *ReactorEngine) dispatch(event Event) { - name := event.Name - eventHandler := reactor.eventHandlers[name] - // if no subscriptions to this event type - no event handler created - // then noone to notify - if eventHandler != nil { - // needs to be called syncronously - eventHandler.Post(event) - } -} diff --git a/ethreact/reactor_test.go b/ethreact/reactor_test.go deleted file mode 100644 index 801a8abd01..0000000000 --- a/ethreact/reactor_test.go +++ /dev/null @@ -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() -} diff --git a/ethutil/reactor.go b/ethutil/reactor.go new file mode 100644 index 0000000000..7cf1452456 --- /dev/null +++ b/ethutil/reactor.go @@ -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}) + } +} diff --git a/ethutil/reactor_test.go b/ethutil/reactor_test.go new file mode 100644 index 0000000000..48c2f0df35 --- /dev/null +++ b/ethutil/reactor_test.go @@ -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") + } +} From 68fba4b781652c0181ca58cf176e96a303acffe4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 11:17:48 +0200 Subject: [PATCH 05/30] Fixed state reset on err --- ethchain/state_transition.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index a92aa4a339..10a795cb82 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -176,8 +176,6 @@ func (self *StateTransition) TransitionState() (err error) { return } - snapshot := self.state.Copy() - receiver = self.Receiver() // If the receiver is nil it's a contract (\0*32). @@ -194,6 +192,8 @@ func (self *StateTransition) TransitionState() (err error) { return } + snapshot := self.state.Copy() + // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { // Evaluate the initialization script From 890745e8469b3d6ee7175db94edfb618b6bc8bc5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:58:20 +0200 Subject: [PATCH 06/30] Increased timeout --- ethwire/messaging.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 5319d07116..a2e0651dc9 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -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(200 * time.Millisecond)) // Create a new temporarily buffer b := make([]byte, 1440) // Wait for a message from this peer From 96ac061e68ffd79f1aa22e12113b0cf58e418c5a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:58:28 +0200 Subject: [PATCH 07/30] Log change --- ethchain/block_chain.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index df735d6797..f72a777066 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -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) { From 42bb3d8aaeb4753ac491c31c746b065dbcbb3781 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:58:54 +0200 Subject: [PATCH 08/30] Removed old if statement. No longer needed --- ethchain/closure.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index cc769de305..1f7f8d703c 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -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 } From b01cb2406f94745277fe05dfa74c6e5d42af1c6a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:59:09 +0200 Subject: [PATCH 09/30] Fixed state reset case --- ethchain/state.go | 16 +++++++++++++++- ethchain/state_object.go | 1 + ethchain/state_transition.go | 16 +++++++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 5d023df7b1..6abf21c390 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -67,11 +67,19 @@ 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 { + println(ethutil.Bytes2Hex(stateObject.Address())) self.UpdateStateObject(stateObject) } } + + // FIXME trie delete is broken + valid, t2 := ethtrie.ParanoiaCheck(self.trie) + if !valid { + self.trie = t2 + } + } // Purges the current trie. @@ -100,6 +108,12 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { self.manifest.AddObjectChange(stateObject) } +func (self *State) DeleteStateObject(stateObject *StateObject) { + self.trie.Delete(string(stateObject.Address())) + + delete(self.stateObjects, string(stateObject.Address())) +} + func (self *State) GetStateObject(addr []byte) *StateObject { stateObject := self.stateObjects[string(addr)] if stateObject != nil { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5a43de35c6..2c7f36e65c 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -84,6 +84,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 { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 10a795cb82..314d858f24 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -176,15 +176,23 @@ func (self *StateTransition) TransitionState() (err error) { return } - receiver = self.Receiver() + /* 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) { From 78aad9a19268d02519e3d777061ebc7a877b0a1d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:59:32 +0200 Subject: [PATCH 10/30] Getting rid of deprecated methods --- ethchain/vm.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 769333649d..71605b0693 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -721,18 +721,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() From 14d13167a723a0fa8ccfcf120131efe96cfc6256 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:59:59 +0200 Subject: [PATCH 11/30] Remove debug println --- ethchain/state.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethchain/state.go b/ethchain/state.go index 6abf21c390..f5c0382265 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -69,7 +69,6 @@ func (self *State) Update() { if stateObject.remove { self.DeleteStateObject(stateObject) } else { - println(ethutil.Bytes2Hex(stateObject.Address())) self.UpdateStateObject(stateObject) } } From e4e704f48074161a175cc125c5fabdf94c095ca8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 16:05:59 +0200 Subject: [PATCH 12/30] Fix quit --- ethlog/loggers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethlog/loggers.go b/ethlog/loggers.go index 219c782408..ec481edd8a 100644 --- a/ethlog/loggers.go +++ b/ethlog/loggers.go @@ -97,7 +97,7 @@ func AddLogSystem(logSystem LogSystem) { defer mutex.Unlock() if logSystems == nil { logMessages = make(chan *logMessage) - quit = make(chan bool) + quit = make(chan bool, 1) go start() } logSystems = append(logSystems, logSystem) From 6cb35836a20e54765a06f64d9df667e6742d3cfa Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 16:06:09 +0200 Subject: [PATCH 13/30] Upped protocol version number --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index e11ac0a570..cc2863a332 100644 --- a/peer.go +++ b/peer.go @@ -21,7 +21,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 22 + ProtocolVersion = 23 // Interval for ping/pong message pingPongTimer = 2 * time.Second ) From 794e65b60e3d9cd954f9d2aa082d18fe9431c200 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 22:08:09 +0200 Subject: [PATCH 14/30] Updated peer server --- ethereum.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index f4c497ca47..a032ef5151 100644 --- a/ethereum.go +++ b/ethereum.go @@ -431,7 +431,7 @@ func (s *Ethereum) Seed() { s.ConnectToPeer(string(body)) } - s.ConnectToPeer("54.204.10.41:30303") + s.ConnectToPeer("54.72.69.180:30303") } func (s *Ethereum) peerHandler(listener net.Listener) { From dcbd97d29c35913c0d13d5da434cb3567fc98ee6 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 9 Jul 2014 10:59:49 +0200 Subject: [PATCH 15/30] Check current folder for mnemonic words if it fails in source folder. For binary support --- ethcrypto/mnemonic.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ethcrypto/mnemonic.go b/ethcrypto/mnemonic.go index 6134f85f72..7258467929 100644 --- a/ethcrypto/mnemonic.go +++ b/ethcrypto/mnemonic.go @@ -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)) From 67e5689f874940c99e4742a5c8c2a6a194cb2003 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 12:51:19 +0200 Subject: [PATCH 16/30] Fixed BYTE opcode --- ethchain/vm.go | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 71605b0693..3b58d61060 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -22,6 +22,9 @@ var ( GasMemory = big.NewInt(1) GasData = big.NewInt(5) GasTx = big.NewInt(500) + + LogTyPretty byte = 0x1 + LogTyDiff byte = 0x2 ) type Debugger interface { @@ -44,6 +47,7 @@ type Vm struct { Verbose bool + logTy byte logStr string err error @@ -69,7 +73,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 +81,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 +90,7 @@ func (self *Vm) Endl() *Vm { } func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { - return &Vm{vars: vars, state: state, stateManager: stateManager} + return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: LogTyPretty} } var Pow256 = ethutil.BigPow(2, 256) @@ -132,6 +136,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.object.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) + } + gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { if amount.Cmp(ethutil.Big0) >= 0 { @@ -415,7 +430,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) } @@ -562,8 +580,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: From 639f1fd3396419fb712b875cfacc333538fcc4f3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:03:26 +0200 Subject: [PATCH 17/30] Log received and send to --- peer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peer.go b/peer.go index cc2863a332..13b81d1a89 100644 --- a/peer.go +++ b/peer.go @@ -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: From bea468f1e595e3de9c8c479e9151c28f0f102973 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:03:48 +0200 Subject: [PATCH 18/30] Increased timeout to 500ms --- ethwire/messaging.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index a2e0651dc9..f13b723538 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -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(200 * 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 From d52e5f7130b58ec9ead7bb20478919f06b0b1a01 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:04:19 +0200 Subject: [PATCH 19/30] Removed hardcoded ip --- ethereum.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/ethereum.go b/ethereum.go index a032ef5151..35d98e8311 100644 --- a/ethereum.go +++ b/ethereum.go @@ -430,8 +430,6 @@ func (s *Ethereum) Seed() { s.ConnectToPeer(string(body)) } - - s.ConnectToPeer("54.72.69.180:30303") } func (s *Ethereum) peerHandler(listener net.Listener) { From e504088b79f55dd08749f08f434cb85a0033898f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:05:06 +0200 Subject: [PATCH 20/30] Consensus and bug fixes * Ensure that each state object has an address that is 20 bytes * Byte logging for vm * changed diff output --- ethchain/state.go | 9 +++++-- ethchain/state_manager.go | 7 ++++++ ethchain/state_object.go | 53 +++++++++++++++++++++++++++++++-------- ethchain/vm.go | 2 ++ 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index f5c0382265..1553663761 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -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" @@ -36,7 +37,8 @@ func (s *State) Reset() { continue } - stateObject.state.Reset() + //stateObject.state.Reset() + stateObject.Reset() } s.Empty() @@ -69,6 +71,10 @@ func (self *State) Update() { if stateObject.remove { self.DeleteStateObject(stateObject) } else { + stateObject.Sync() + + fmt.Printf("%x %x\n", stateObject.Address(), stateObject.state.Root()) + self.UpdateStateObject(stateObject) } } @@ -78,7 +84,6 @@ func (self *State) Update() { if !valid { self.trie = t2 } - } // Purges the current trie. diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f3fd929137..a5afa50963 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -66,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 { @@ -165,6 +170,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() diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 2c7f36e65c..ebc0508638 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -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 @@ -95,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) @@ -249,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() diff --git a/ethchain/vm.go b/ethchain/vm.go index 3b58d61060..56456fdab5 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -182,7 +182,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 From b7ff773ecf78f8dd66a6615fc608cabee5a35ce6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:06:46 +0200 Subject: [PATCH 21/30] Removed debug log --- ethchain/state.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 1553663761..d93ab3e01e 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,7 +1,6 @@ package ethchain import ( - "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -73,8 +72,6 @@ func (self *State) Update() { } else { stateObject.Sync() - fmt.Printf("%x %x\n", stateObject.Address(), stateObject.state.Root()) - self.UpdateStateObject(stateObject) } } From 9688ebef523fdd368f7d0596f4529b7e3bc26775 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:31:48 +0200 Subject: [PATCH 22/30] Return from execution immediately if there's no code --- ethchain/vm.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethchain/vm.go b/ethchain/vm.go index 56456fdab5..c63b5392fd 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -107,6 +107,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } }() + // 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.object.Address(), closure.Gas, closure.Args) var ( From 04561c4ddc363189bdb7377a271d6a734f09eae1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 17:58:16 +0200 Subject: [PATCH 23/30] Updated VM & added helper methods to state * VM BALANCE opcode updated to pop 1 item and use that to retrieve the address' balance * GetBalance and GetNonce on state that'll always return something valid --- ethchain/state.go | 151 ++++++++++++++++++++++++++-------------------- ethchain/vm.go | 20 ++++-- 2 files changed, 101 insertions(+), 70 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index d93ab3e01e..6d45c9e32c 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -26,79 +26,36 @@ func NewState(trie *ethtrie.Trie) *State { return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, stateObject := range s.stateObjects { - if stateObject.state == nil { - continue - } - - //stateObject.state.Reset() - stateObject.Reset() - } - - s.Empty() +// Iterate over each storage address and yield callback +func (s *State) EachStorage(cb ethtrie.EachCallback) { + it := s.trie.NewIterator() + it.Each(cb) } -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, stateObject := range s.stateObjects { - s.UpdateStateObject(stateObject) - - if stateObject.state == nil { - continue - } - - stateObject.state.Sync() +// 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 } - s.trie.Sync() - - s.Empty() -} - -func (self *State) Empty() { - self.stateObjects = make(map[string]*StateObject) + return ethutil.Big0 } -func (self *State) Update() { - for _, stateObject := range self.stateObjects { - if stateObject.remove { - self.DeleteStateObject(stateObject) - } else { - stateObject.Sync() - - self.UpdateStateObject(stateObject) - } - } - - // FIXME trie delete is broken - valid, t2 := ethtrie.ParanoiaCheck(self.trie) - if !valid { - self.trie = t2 +func (self *State) GetNonce(addr []byte) uint64 { + stateObject := self.GetStateObject(addr) + if stateObject != nil { + return stateObject.Nonce } -} -// Purges the current trie. -func (s *State) Purge() int { - return s.trie.NewIterator().Purge() + return 0 } -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() -} +// +// 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() @@ -109,12 +66,14 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { 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 { @@ -132,6 +91,7 @@ func (self *State) GetStateObject(addr []byte) *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 { @@ -141,6 +101,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { 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) @@ -150,10 +111,15 @@ func (self *State) NewStateObject(addr []byte) *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) } @@ -181,14 +147,67 @@ func (self *State) Set(state *State) { //*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 } +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + //stateObject.state.Reset() + stateObject.Reset() + } + + s.Empty() +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, stateObject := range s.stateObjects { + s.UpdateStateObject(stateObject) + + if stateObject.state == nil { + continue + } + + stateObject.state.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 { + if stateObject.remove { + self.DeleteStateObject(stateObject) + } else { + stateObject.Sync() + + self.UpdateStateObject(stateObject) + } + } + + // FIXME trie delete is broken + valid, t2 := ethtrie.ParanoiaCheck(self.trie) + if !valid { + self.trie = t2 + } +} + // Object manifest // // The object manifest is used to keep changes to the state so we can keep track of the changes diff --git a/ethchain/vm.go b/ethchain/vm.go index c63b5392fd..f57d6a751a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -452,13 +452,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())) + + vm.Printf(" => %x", closure.Object().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)) @@ -712,7 +725,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(ethutil.BigFalse) } else { - //snapshot := vm.state.Copy() + snapshot := vm.state.Copy() stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) @@ -728,8 +741,7 @@ 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) From 5c7e96d895f18e774c89b26cd99d998d4d08e1f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 18:19:38 +0200 Subject: [PATCH 24/30] Removed serpent --- ethutil/script.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ethutil/script.go b/ethutil/script.go index f5c53f84c7..b796e7c1eb 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -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 { From ff151f9fbcfea2d21139ec778fc7c1ac32282d71 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 21:54:36 +0200 Subject: [PATCH 25/30] vm output --- ethchain/vm.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethchain/vm.go b/ethchain/vm.go index f57d6a751a..6a64d3ff38 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -479,6 +479,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() From 9010857677ac374e09bab62a89f2fb52c11ed6d3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 11 Jul 2014 16:04:09 +0200 Subject: [PATCH 26/30] Special diff output for execution --- ethchain/asm.go | 4 ++++ ethchain/state.go | 11 +++++++++++ ethchain/state_manager.go | 8 ++++++++ ethchain/vm.go | 37 ++++++++++++++++++++++++++++++------- ethereum.go | 4 +++- ethutil/config.go | 1 + 6 files changed, 57 insertions(+), 8 deletions(-) diff --git a/ethchain/asm.go b/ethchain/asm.go index 09d6af56fc..2697953fd8 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -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} diff --git a/ethchain/state.go b/ethchain/state.go index 6d45c9e32c..8df79dcef2 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -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" @@ -208,6 +209,16 @@ func (self *State) Update() { } } +// 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()) + }) + } +} + // Object manifest // // The object manifest is used to keep changes to the state so we can keep track of the changes diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a5afa50963..62fcda8a5c 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -150,6 +150,10 @@ done: receipts = append(receipts, receipt) handled = append(handled, tx) + + if ethutil.Config.Diff { + state.CreateOutputForDiff() + } } parent.GasUsed = totalUsedGas @@ -183,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 { diff --git a/ethchain/vm.go b/ethchain/vm.go index 6a64d3ff38..3ad4472ca2 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -31,6 +31,7 @@ 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 { @@ -90,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, logTy: LogTyPretty} + lt := LogTyPretty + if ethutil.Config.Diff { + lt = LogTyDiff + } + + return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: lt} } var Pow256 = ethutil.BigPow(2, 256) @@ -107,12 +113,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } }() + // 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.object.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.Address(), closure.Gas, closure.Args) var ( op OpCode @@ -149,7 +160,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { b = []byte{0} } - fmt.Printf("%x %x %x %x\n", closure.object.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) + fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) } gas := new(big.Int) @@ -456,9 +467,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { 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.Object().Address()) + vm.Printf(" => %x", closure.Address()) case BALANCE: require(1) @@ -664,9 +675,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++ @@ -706,6 +717,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) @@ -749,6 +765,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { mem.Set(retOffset.Int64(), retSize.Int64(), ret) } + + // Debug hook + if vm.Dbg != nil { + vm.Dbg.SetCode(closure.Script) + } } case RETURN: require(2) @@ -786,6 +807,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 } diff --git a/ethereum.go b/ethereum.go index 35d98e8311..2806dfd9dd 100644 --- a/ethereum.go +++ b/ethereum.go @@ -20,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)) { @@ -416,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 diff --git a/ethutil/config.go b/ethutil/config.go index c9b86100b4..2f3d706fe6 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -13,6 +13,7 @@ type ConfigManager struct { ExecPath string Debug bool + Diff bool Paranoia bool conf *globalconf.GlobalConf From 54715586ab147a62342a9462f3a73cc2f750d148 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 12 Jul 2014 11:10:47 +0200 Subject: [PATCH 27/30] Changed sha3 to official one --- ethchain/vm.go | 5 +++-- ethcrypto/crypto.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 3ad4472ca2..f7ce8c2ce7 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -690,14 +690,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) diff --git a/ethcrypto/crypto.go b/ethcrypto/crypto.go index b4bb881a01..19f8c9e559 100644 --- a/ethcrypto/crypto.go +++ b/ethcrypto/crypto.go @@ -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 { From ee3ba0b1d611401864bf0a646e9608d5ba03be34 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 13 Jul 2014 17:45:39 +0200 Subject: [PATCH 28/30] Catch up per 10 --- peer.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 13b81d1a89..0a4f08af59 100644 --- a/peer.go +++ b/peer.go @@ -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()) From 6426f3635eddaa1477e643886fd3c0eaf1fa6158 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 13 Jul 2014 17:56:14 +0200 Subject: [PATCH 29/30] Forgot to return gas when CALL's value transfer fails --- ethchain/vm.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethchain/vm.go b/ethchain/vm.go index f7ce8c2ce7..f1794ff772 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -550,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) @@ -741,6 +743,7 @@ 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 { From 8845fb7eae3e51fd3e55c47c377bf1a9e0cfe2a9 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 14 Jul 2014 15:24:38 +0200 Subject: [PATCH 30/30] Add windows helper functions --- ethutil/common.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ethutil/common.go b/ethutil/common.go index 6d88a1ed2a..2fd031a20a 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -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)