From 4d77b7facecfea7069af15f19429585687c47fbb Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 7 Jul 2014 12:30:25 +0100 Subject: [PATCH 01/64] remove extra case in main loop --- ethreact/reactor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethreact/reactor.go b/ethreact/reactor.go index f42f71202..8e72ca903 100644 --- a/ethreact/reactor.go +++ b/ethreact/reactor.go @@ -95,7 +95,7 @@ func (reactor *ReactorEngine) Start() { case event := <-reactor.eventChannel: // needs to be called syncronously to keep order of events reactor.dispatch(event) - case reactor.drained <- true: + // case reactor.drained <- true: default: reactor.drained <- true // blocking till message is coming in } From 5c03adbdededd31cb73f64ced01e33154347e193 Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 14 Jul 2014 18:37:01 +0100 Subject: [PATCH 02/64] fix logger channel blocking --- ethlog/loggers.go | 67 +++++++++++++++++++++--------------------- ethlog/loggers_test.go | 15 ++++++++++ 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/ethlog/loggers.go b/ethlog/loggers.go index d7707cf9e..4e950cadd 100644 --- a/ethlog/loggers.go +++ b/ethlog/loggers.go @@ -39,9 +39,8 @@ func (msg *logMessage) send(logger LogSystem) { var logMessages chan (*logMessage) var logSystems []LogSystem -var quit chan bool +var quit chan chan error var drained chan bool -var shutdown chan bool var mutex = sync.Mutex{} type LogLevel uint8 @@ -55,44 +54,54 @@ const ( DebugDetailLevel ) -// log messages are dispatched to log writers -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 +func dispatch(msg *logMessage) { + for _, logSystem := range logSystems { + if logSystem.GetLogLevel() >= msg.LogLevel { + msg.send(logSystem) } } - close(shutdown) +} + +// log messages are dispatched to log writers +func start() { + for { + select { + case status := <-quit: + status <- nil + return + case msg := <-logMessages: + dispatch(msg) + default: + drained <- true // this blocks until a message is sent to the queue + } + } +} + +func send(msg *logMessage) { + logMessages <- msg + select { + case <-drained: + default: + } } func Reset() { mutex.Lock() defer mutex.Unlock() if logSystems != nil { - quit <- true + status := make(chan error) + quit <- status select { case <-drained: + default: } - <-shutdown + <-status } logSystems = nil } // waits until log messages are drained (dispatched to log writers) func Flush() { - mutex.Lock() - defer mutex.Unlock() if logSystems != nil { <-drained } @@ -110,22 +119,14 @@ func AddLogSystem(logSystem LogSystem) { mutex.Lock() defer mutex.Unlock() if logSystems == nil { - logMessages = make(chan *logMessage) - quit = make(chan bool) + logMessages = make(chan *logMessage, 5) + quit = make(chan chan error, 1) 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...)) diff --git a/ethlog/loggers_test.go b/ethlog/loggers_test.go index 9fff471c1..0e1c12e55 100644 --- a/ethlog/loggers_test.go +++ b/ethlog/loggers_test.go @@ -28,6 +28,21 @@ func (t *TestLogSystem) GetLogLevel() LogLevel { return t.level } +func TestLoggerFlush(t *testing.T) { + logger := NewLogger("TEST") + testLogSystem := &TestLogSystem{level: WarnLevel} + AddLogSystem(testLogSystem) + for i := 0; i < 5; i++ { + logger.Errorf(".") + } + Flush() + Reset() + output := testLogSystem.Output + if output != "[TEST] .[TEST] .[TEST] .[TEST] .[TEST] ." { + t.Error("Expected complete logger output '[TEST] .[TEST] .[TEST] .[TEST] .[TEST] .', got ", output) + } +} + func TestLoggerPrintln(t *testing.T) { logger := NewLogger("TEST") testLogSystem := &TestLogSystem{level: WarnLevel} From dc11b5c55e2888a7a3dac51fedc3864d112136ce Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 14 Jul 2014 18:40:18 +0100 Subject: [PATCH 03/64] fix reactor channel blocking --- ethreact/reactor.go | 53 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/ethreact/reactor.go b/ethreact/reactor.go index 8e72ca903..a26f82a97 100644 --- a/ethreact/reactor.go +++ b/ethreact/reactor.go @@ -7,6 +7,10 @@ import ( var logger = ethlog.NewLogger("REACTOR") +const ( + eventBufferSize int = 10 +) + type EventHandler struct { lock sync.RWMutex name string @@ -21,7 +25,7 @@ func (e *EventHandler) Post(event Event) { // 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) + // this means if subscribed event channel is blocked // the reactor dispatch will be blocked, so we need to mitigate by skipping // rogue blocking subscribers for i, ch := range e.chans { @@ -63,22 +67,20 @@ type Event struct { // 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 + lock sync.RWMutex + eventChannel chan Event + eventHandlers map[string]*EventHandler + quit chan chan error + 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), + eventHandlers: make(map[string]*EventHandler), + eventChannel: make(chan Event, eventBufferSize), + quit: make(chan chan error, 1), + drained: make(chan bool, 1), } } @@ -87,24 +89,22 @@ func (reactor *ReactorEngine) Start() { defer reactor.lock.Unlock() if !reactor.running { go func() { - out: for { select { - case <-reactor.quit: - break out + case status := <-reactor.quit: + reactor.lock.Lock() + defer reactor.lock.Unlock() + reactor.running = false + logger.Infoln("stopped") + status <- nil + return 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") @@ -112,15 +112,15 @@ func (reactor *ReactorEngine) Start() { } func (reactor *ReactorEngine) Stop() { - reactor.lock.RLock() if reactor.running { - reactor.quit <- true + status := make(chan error) + reactor.quit <- status select { case <-reactor.drained: + default: } + <-status } - reactor.lock.RUnlock() - <-reactor.shutdownChannel } func (reactor *ReactorEngine) Flush() { @@ -165,6 +165,7 @@ func (reactor *ReactorEngine) Post(event string, resource interface{}) { reactor.eventChannel <- Event{Resource: resource, Name: event} select { case <-reactor.drained: + default: } } } From d1c89727dcf10c87bd1df68da9508cec047c56cf Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 14 Jul 2014 19:02:34 +0100 Subject: [PATCH 04/64] fix send overwritten by merge --- ethlog/loggers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethlog/loggers.go b/ethlog/loggers.go index f13186102..59021d169 100644 --- a/ethlog/loggers.go +++ b/ethlog/loggers.go @@ -130,14 +130,14 @@ func AddLogSystem(logSystem LogSystem) { func (logger *Logger) sendln(level LogLevel, v ...interface{}) { if logMessages != nil { msg := newPrintlnLogMessage(level, logger.tag, v...) - logMessages <- msg + send(msg) } } func (logger *Logger) sendf(level LogLevel, format string, v ...interface{}) { if logMessages != nil { msg := newPrintfLogMessage(level, logger.tag, format, v...) - logMessages <- msg + send(msg) } } From 0ecc5c815e4550d7e8dca7b4ab4c549b10bf0b19 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 15 Jul 2014 00:15:37 +0100 Subject: [PATCH 05/64] reactor test --- ethreact/reactor_test.go | 63 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 ethreact/reactor_test.go diff --git a/ethreact/reactor_test.go b/ethreact/reactor_test.go new file mode 100644 index 000000000..801a8abd0 --- /dev/null +++ b/ethreact/reactor_test.go @@ -0,0 +1,63 @@ +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() +} From 1735ec0362e84455126d8c1bd380ecae436d1167 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 15 Jul 2014 01:11:06 +0100 Subject: [PATCH 06/64] use ethreact.Event and ethreact.ReactorEngine --- ethchain/dagger.go | 5 ++- ethchain/state_manager.go | 3 +- ethereum.go | 10 +++-- ethminer/miner.go | 12 +++--- ethutil/reactor.go | 87 --------------------------------------- ethutil/reactor_test.go | 30 -------------- 6 files changed, 18 insertions(+), 129 deletions(-) delete mode 100644 ethutil/reactor.go delete mode 100644 ethutil/reactor_test.go diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 4dda21ff5..adf1c2f05 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -3,6 +3,7 @@ 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" @@ -14,7 +15,7 @@ import ( var powlogger = ethlog.NewLogger("POW") type PoW interface { - Search(block *Block, reactChan chan ethutil.React) []byte + Search(block *Block, reactChan chan ethreact.Event) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -22,7 +23,7 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { +func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []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 62fcda8a5..3eafd2d6e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,6 +6,7 @@ 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" @@ -36,7 +37,7 @@ type EthManager interface { BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) - Reactor() *ethutil.ReactorEngine + Reactor() *ethreact.ReactorEngine PeerCount() int IsMining() bool IsListening() bool diff --git a/ethereum.go b/ethereum.go index 2806dfd9d..c2d2f5241 100644 --- a/ethereum.go +++ b/ethereum.go @@ -6,6 +6,7 @@ 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" @@ -73,7 +74,7 @@ type Ethereum struct { listening bool - reactor *ethutil.ReactorEngine + reactor *ethreact.ReactorEngine RpcServer *ethrpc.JsonRpcServer @@ -108,7 +109,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager keyManager: keyManager, clientIdentity: clientIdentity, } - ethereum.reactor = ethutil.NewReactorEngine() + ethereum.reactor = ethreact.New() ethereum.txPool = ethchain.NewTxPool(ethereum) ethereum.blockChain = ethchain.NewBlockChain(ethereum) @@ -120,7 +121,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager return ethereum, nil } -func (s *Ethereum) Reactor() *ethutil.ReactorEngine { +func (s *Ethereum) Reactor() *ethreact.ReactorEngine { return s.reactor } @@ -352,6 +353,7 @@ 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 { @@ -462,6 +464,8 @@ 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/ethminer/miner.go b/ethminer/miner.go index 71d4b2428..8224c5441 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/ethutil" + "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethwire" "sort" ) @@ -15,19 +15,19 @@ type Miner struct { pow ethchain.PoW ethereum ethchain.EthManager coinbase []byte - reactChan chan ethutil.React + reactChan chan ethreact.Event txs ethchain.Transactions uncles []*ethchain.Block block *ethchain.Block powChan chan []byte - powQuitChan chan ethutil.React + powQuitChan chan ethreact.Event quitChan chan bool } func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { - 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 + 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 quitChan := make(chan bool, 1) ethereum.Reactor().Subscribe("newBlock", reactChan) diff --git a/ethutil/reactor.go b/ethutil/reactor.go deleted file mode 100644 index 7cf145245..000000000 --- a/ethutil/reactor.go +++ /dev/null @@ -1,87 +0,0 @@ -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 deleted file mode 100644 index 48c2f0df3..000000000 --- a/ethutil/reactor_test.go +++ /dev/null @@ -1,30 +0,0 @@ -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 017d36e6b2e127084448dfb38bd1b8de7424e1c9 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 15 Jul 2014 01:12:45 +0100 Subject: [PATCH 07/64] properly unsubscribe react channels when miner stops - fixes write on closed chan crash --- ethminer/miner.go | 58 +++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index 8224c5441..5151ee885 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -25,30 +25,10 @@ type Miner struct { } 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 - quitChan := make(chan bool, 1) - - ethereum.Reactor().Subscribe("newBlock", reactChan) - ethereum.Reactor().Subscribe("newTx:pre", reactChan) - - // We need the quit chan to be a Reactor event. - // The POW search method is actually blocking and if we don't - // listen to the reactor events inside of the pow itself - // The miner overseer will never get the reactor events themselves - // Only after the miner will find the sha - ethereum.Reactor().Subscribe("newBlock", powQuitChan) - ethereum.Reactor().Subscribe("newTx:pre", powQuitChan) - miner := Miner{ - pow: ðchain.EasyPow{}, - ethereum: ethereum, - coinbase: coinbase, - reactChan: reactChan, - powChan: powChan, - powQuitChan: powQuitChan, - quitChan: quitChan, + pow: ðchain.EasyPow{}, + ethereum: ethereum, + coinbase: coinbase, } // Insert initial TXs in our little miner 'pool' @@ -59,9 +39,27 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { } func (miner *Miner) Start() { + miner.reactChan = make(chan ethreact.Event, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in + miner.powChan = make(chan []byte, 1) // This is the channel that receives valid sha hashes for a given block + miner.powQuitChan = make(chan ethreact.Event, 1) // This is the channel that can exit the miner thread + miner.quitChan = make(chan bool, 1) + // Prepare inital block //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) go miner.listener() + + reactor := miner.ethereum.Reactor() + reactor.Subscribe("newBlock", miner.reactChan) + reactor.Subscribe("newTx:pre", miner.reactChan) + + // We need the quit chan to be a Reactor event. + // The POW search method is actually blocking and if we don't + // listen to the reactor events inside of the pow itself + // The miner overseer will never get the reactor events themselves + // Only after the miner will find the sha + reactor.Subscribe("newBlock", miner.powQuitChan) + reactor.Subscribe("newTx:pre", miner.powQuitChan) + logger.Infoln("Started") } @@ -127,12 +125,18 @@ out: } } -func (self *Miner) Stop() { +func (miner *Miner) Stop() { logger.Infoln("Stopping...") - self.quitChan <- true + miner.quitChan <- true - close(self.powQuitChan) - close(self.quitChan) + reactor := miner.ethereum.Reactor() + reactor.Unsubscribe("newBlock", miner.powQuitChan) + reactor.Unsubscribe("newTx:pre", miner.powQuitChan) + reactor.Unsubscribe("newBlock", miner.reactChan) + reactor.Unsubscribe("newTx:pre", miner.reactChan) + + close(miner.powQuitChan) + close(miner.quitChan) } func (self *Miner) mineNewBlock() { From 67528cf9709519458ab5500cb7cf54664dd20167 Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 21 Jul 2014 15:10:56 +0100 Subject: [PATCH 08/64] ethreact/README.md --- ethreact/README.md | 28 ++++++++++++++++++++++++++++ ethreact/reactor.go | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 ethreact/README.md diff --git a/ethreact/README.md b/ethreact/README.md new file mode 100644 index 000000000..61af8a572 --- /dev/null +++ b/ethreact/README.md @@ -0,0 +1,28 @@ +## Reactor + +Reactor is the internal broadcast engine that allows components to be notified of ethereum stack events such as finding new blocks or change in state. +Event notification is handled via subscription: + + var blockChan = make(chan ethreact.Event, 10) + reactor.Subscribe("newBlock", blockChan) + +ethreact.Event broadcast on the channel are + + type Event struct { + Resource interface{} + Name string + } + +Resource is polimorphic depending on the event type and should be typecast before use, e.g: + + b := <-blockChan: + block := b.Resource.(*ethchain.Block) + +Events are guaranteed to be broadcast in order but the broadcast never blocks or leaks which means while the subscribing event channel is blocked (e.g., full if buffered) further messages will be skipped. + +The engine allows arbitrary events to be posted and subscribed to. + + ethereum.Reactor().Post("newBlock", newBlock) + + + \ No newline at end of file diff --git a/ethreact/reactor.go b/ethreact/reactor.go index a26f82a97..7fe2356db 100644 --- a/ethreact/reactor.go +++ b/ethreact/reactor.go @@ -58,7 +58,7 @@ func (e *EventHandler) Remove(ch chan Event) int { return len(e.chans) } -// Basic reactor resource +// Basic reactor event type Event struct { Resource interface{} Name string From 194c58858cd230a9a08b0eb14650720341a5580e Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 21 Jul 2014 19:12:04 +0100 Subject: [PATCH 09/64] send zero event to miner.powQuitChan fixes miner hanging --- ethminer/miner.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index 8659d2889..e51b37e05 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -133,6 +133,9 @@ func (miner *Miner) listener() { func (miner *Miner) Stop() { logger.Infoln("Stopping...") + + miner.powQuitChan <- ethreact.Event{} + status := make(chan error) miner.quitChan <- status <-status @@ -143,9 +146,6 @@ func (miner *Miner) Stop() { reactor.Unsubscribe("newBlock", miner.reactChan) reactor.Unsubscribe("newTx:pre", miner.reactChan) - close(miner.powQuitChan) - close(miner.quitChan) - reactor.Post("miner:stop", miner) } From 41bd38147c2e5968283facf641b2444c09f53d14 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Jul 2014 11:24:44 +0200 Subject: [PATCH 10/64] Clean up and util methods --- ethchain/block.go | 13 ++++--------- ethereum.go | 13 +++++++------ ethutil/bytes.go | 1 + ethutil/config.go | 6 +++--- ethutil/path.go | 40 ++++++++++++++++++++++++++++++++++++++++ ethvm/vm.go | 5 +++-- peer.go | 15 +++++++++------ 7 files changed, 67 insertions(+), 26 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 437525e35..e00bcb24f 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -3,13 +3,14 @@ package ethchain import ( "bytes" "fmt" + "math/big" + _ "strconv" + "time" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "math/big" - _ "strconv" - "time" ) type BlockInfo struct { @@ -63,12 +64,6 @@ type Block struct { TxSha []byte } -// New block takes a raw encoded string -// XXX DEPRICATED -func NewBlockFromData(raw []byte) *Block { - return NewBlockFromBytes(raw) -} - func NewBlockFromBytes(raw []byte) *Block { block := &Block{} block.RlpDecode(raw) diff --git a/ethereum.go b/ethereum.go index 18c1f8a23..799e9cb39 100644 --- a/ethereum.go +++ b/ethereum.go @@ -3,12 +3,6 @@ package eth import ( "container/list" "fmt" - "github.com/ethereum/eth-go/ethchain" - "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethrpc" - "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" "io/ioutil" "math/rand" "net" @@ -18,6 +12,13 @@ import ( "sync" "sync/atomic" "time" + + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethrpc" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" ) const seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt" diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 34fff7d42..53b8cf645 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -98,6 +98,7 @@ func Bytes2Hex(d []byte) string { func Hex2Bytes(str string) []byte { h, _ := hex.DecodeString(str) + return h } diff --git a/ethutil/config.go b/ethutil/config.go index 41bece21d..81052318e 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -3,8 +3,9 @@ package ethutil import ( "flag" "fmt" - "github.com/rakyll/globalconf" "os" + + "github.com/rakyll/globalconf" ) // Config struct @@ -28,8 +29,7 @@ var Config *ConfigManager func ReadConfig(ConfigFile string, Datadir string, EnvPrefix string) *ConfigManager { if Config == nil { // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags - _, err := os.Stat(ConfigFile) - if err != nil && os.IsNotExist(err) { + if !FileExist(ConfigFile) { fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile) os.Create(ConfigFile) } diff --git a/ethutil/path.go b/ethutil/path.go index 97f58ab7e..27022bcfa 100644 --- a/ethutil/path.go +++ b/ethutil/path.go @@ -1,6 +1,8 @@ package ethutil import ( + "io/ioutil" + "os" "os/user" "strings" ) @@ -18,3 +20,41 @@ func ExpandHomePath(p string) (path string) { return } + +func FileExist(filePath string) bool { + _, err := os.Stat(filePath) + if err != nil && os.IsNotExist(err) { + return false + } + + return true +} + +func ReadAllFile(filePath string) (string, error) { + file, err := os.Open(filePath) + if err != nil { + return "", err + } + + data, err := ioutil.ReadAll(file) + if err != nil { + return "", err + } + + return string(data), nil +} + +func WriteFile(filePath string, content []byte) error { + fh, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, os.ModePerm) + if err != nil { + return err + } + defer fh.Close() + + _, err = fh.Write(content) + if err != nil { + return err + } + + return nil +} diff --git a/ethvm/vm.go b/ethvm/vm.go index a93b56e60..e0a9d831b 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -2,11 +2,12 @@ package ethvm import ( "fmt" + "math" + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" - "math" - "math/big" ) type Debugger interface { diff --git a/peer.go b/peer.go index ffba695ca..691a2f575 100644 --- a/peer.go +++ b/peer.go @@ -4,15 +4,16 @@ import ( "bytes" "container/list" "fmt" - "github.com/ethereum/eth-go/ethchain" - "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" "net" "strconv" "strings" "sync/atomic" "time" + + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" ) var peerlogger = ethlog.NewLogger("PEER") @@ -197,10 +198,12 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { } func (self *Peer) Connect(addr string) (conn net.Conn, err error) { - for attempts := 0; attempts < 5; attempts++ { + const maxTries = 3 + for attempts := 0; attempts < maxTries; attempts++ { conn, err = net.DialTimeout("tcp", addr, 10*time.Second) if err != nil { - peerlogger.Debugf("Peer connection failed. Retrying (%d/5)\n", attempts+1) + //peerlogger.Debugf("Peer connection failed. Retrying (%d/%d) (%s)\n", attempts+1, maxTries, addr) + time.Sleep(time.Duration(attempts*20) * time.Second) continue } From 8e7c4f91e33bd99d3a4d320cdc59cf0bab3831b6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 10:33:30 +0200 Subject: [PATCH 11/64] Added ops --- ethutil/value.go | 60 +++++++++++++++++++++++++++++++++++++++++-- ethutil/value_test.go | 15 +++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/ethutil/value.go b/ethutil/value.go index 735a71dbc..635683e66 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -1,7 +1,6 @@ package ethutil import ( - "bytes" "fmt" "math/big" "reflect" @@ -67,7 +66,8 @@ func (val *Value) Uint() uint64 { } else if Val, ok := val.Val.(uint); ok { return uint64(Val) } else if Val, ok := val.Val.([]byte); ok { - return ReadVarint(bytes.NewReader(Val)) + return new(big.Int).SetBytes(Val).Uint64() + //return ReadVarint(bytes.NewReader(Val)) } else if Val, ok := val.Val.(*big.Int); ok { return Val.Uint64() } @@ -207,6 +207,13 @@ func (val *Value) Cmp(o *Value) bool { return reflect.DeepEqual(val.Val, o.Val) } +func (self *Value) DeepCmp(o *Value) bool { + a := NewValue(self.BigInt()) + b := NewValue(o.BigInt()) + + return a.Cmp(b) +} + func (val *Value) Encode() []byte { return Encode(val.Val) } @@ -262,6 +269,55 @@ func (val *Value) Append(v interface{}) *Value { return val } +const ( + valOpAdd = iota + valOpDiv + valOpMul + valOpPow + valOpSub +) + +// Math stuff +func (self *Value) doOp(op int, other interface{}) *Value { + left := self.BigInt() + right := NewValue(other).BigInt() + + switch op { + case valOpAdd: + self.Val = left.Add(left, right) + case valOpDiv: + self.Val = left.Div(left, right) + case valOpMul: + self.Val = left.Mul(left, right) + case valOpPow: + self.Val = left.Exp(left, right, Big0) + case valOpSub: + self.Val = left.Sub(left, right) + } + + return self +} + +func (self *Value) Add(other interface{}) *Value { + return self.doOp(valOpAdd, other) +} + +func (self *Value) Sub(other interface{}) *Value { + return self.doOp(valOpSub, other) +} + +func (self *Value) Div(other interface{}) *Value { + return self.doOp(valOpDiv, other) +} + +func (self *Value) Mul(other interface{}) *Value { + return self.doOp(valOpMul, other) +} + +func (self *Value) Pow(other interface{}) *Value { + return self.doOp(valOpPow, other) +} + type ValueIterator struct { value *Value currentValue *Value diff --git a/ethutil/value_test.go b/ethutil/value_test.go index a100f44bc..710cbd887 100644 --- a/ethutil/value_test.go +++ b/ethutil/value_test.go @@ -63,3 +63,18 @@ func TestIterator(t *testing.T) { i++ } } + +func TestMath(t *testing.T) { + a := NewValue(1) + a.Add(1).Add(1) + + if !a.DeepCmp(NewValue(3)) { + t.Error("Expected 3, got", a) + } + + a = NewValue(2) + a.Sub(1).Sub(1) + if !a.DeepCmp(NewValue(0)) { + t.Error("Expected 0, got", a) + } +} From d1d2b660dcc3c7539940a5e3d5a48ad10487bd8f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 15:55:08 +0200 Subject: [PATCH 12/64] Prot --- peer.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/peer.go b/peer.go index 691a2f575..f4314e35c 100644 --- a/peer.go +++ b/peer.go @@ -22,7 +22,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 23 + ProtocolVersion = 25 // Interval for ping/pong message pingPongTimer = 2 * time.Second ) @@ -436,19 +436,20 @@ 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)) + 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") + peerlogger.Infof("Attempting to catch (%x). Parent unknown\n", b.Hash()) p.catchingUp = false - p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) + + p.CatchupWithPeer(b.Hash()) + + peerlogger.Infoln(b) + + /* + peerlogger.Infoln("Attempting to catch. Parent known") + p.catchingUp = false + p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) + */ } else if ethchain.IsValidationErr(err) { fmt.Println("Err:", err) p.catchingUp = false From 6e94c024e476a0e96b81d1cdd60dbb88b723593a Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 23:31:33 +0200 Subject: [PATCH 13/64] Added big data test and updating to reader --- ethutil/rlp.go | 143 +++++++++++++++++++++++--------------------- ethutil/rlp_test.go | 11 ++++ 2 files changed, 87 insertions(+), 67 deletions(-) diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 195ef0efb..333a84927 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -55,8 +55,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { return reader.Next(int(char - 0x80)) case char <= 0xbf: - buff := bytes.NewReader(reader.Next(int(char - 0xb8))) - length := ReadVarint(buff) + length := ReadVarInt(reader.Next(int(char - 0xb7))) return reader.Next(int(length)) @@ -72,76 +71,22 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { } return slice - + case char <= 0xff: + length := ReadVarInt(reader.Next(int(char - 0xf7))) + for i := uint64(0); i < length; i++ { + obj := DecodeWithReader(reader) + if obj != nil { + slice = append(slice, obj) + } else { + break + } + } + default: } return slice } -// TODO Use a bytes.Buffer instead of a raw byte slice. -// Cleaner code, and use draining instead of seeking the next bytes to read -func Decode(data []byte, pos uint64) (interface{}, uint64) { - var slice []interface{} - char := int(data[pos]) - switch { - case char <= 0x7f: - return data[pos], pos + 1 - - case char <= 0xb7: - b := uint64(data[pos]) - 0x80 - - return data[pos+1 : pos+1+b], pos + 1 + b - - case char <= 0xbf: - b := uint64(data[pos]) - 0xb7 - - b2 := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+b])) - - return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 - - case char <= 0xf7: - b := uint64(data[pos]) - 0xc0 - prevPos := pos - pos++ - for i := uint64(0); i < b; { - var obj interface{} - - // Get the next item in the data list and append it - obj, prevPos = Decode(data, pos) - slice = append(slice, obj) - - // Increment i by the amount bytes read in the previous - // read - i += (prevPos - pos) - pos = prevPos - } - return slice, pos - - case char <= 0xff: - l := uint64(data[pos]) - 0xf7 - b := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+l])) - - pos = pos + l + 1 - - prevPos := b - for i := uint64(0); i < uint64(b); { - var obj interface{} - - obj, prevPos = Decode(data, pos) - slice = append(slice, obj) - - i += (prevPos - pos) - pos = prevPos - } - return slice, pos - - default: - panic(fmt.Sprintf("byte not supported: %q", char)) - } - - return slice, 0 -} - var ( directRlp = big.NewInt(0x7f) numberRlp = big.NewInt(0xb7) @@ -223,3 +168,67 @@ func Encode(object interface{}) []byte { return buff.Bytes() } + +// TODO Use a bytes.Buffer instead of a raw byte slice. +// Cleaner code, and use draining instead of seeking the next bytes to read +func Decode(data []byte, pos uint64) (interface{}, uint64) { + var slice []interface{} + char := int(data[pos]) + switch { + case char <= 0x7f: + return data[pos], pos + 1 + + case char <= 0xb7: + b := uint64(data[pos]) - 0x80 + + return data[pos+1 : pos+1+b], pos + 1 + b + + case char <= 0xbf: + b := uint64(data[pos]) - 0xb7 + + b2 := ReadVarInt(data[pos+1 : pos+1+b]) + + return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 + + case char <= 0xf7: + b := uint64(data[pos]) - 0xc0 + prevPos := pos + pos++ + for i := uint64(0); i < b; { + var obj interface{} + + // Get the next item in the data list and append it + obj, prevPos = Decode(data, pos) + slice = append(slice, obj) + + // Increment i by the amount bytes read in the previous + // read + i += (prevPos - pos) + pos = prevPos + } + return slice, pos + + case char <= 0xff: + l := uint64(data[pos]) - 0xf7 + b := ReadVarInt(data[pos+1 : pos+1+l]) + + pos = pos + l + 1 + + prevPos := b + for i := uint64(0); i < uint64(b); { + var obj interface{} + + obj, prevPos = Decode(data, pos) + slice = append(slice, obj) + + i += (prevPos - pos) + pos = prevPos + } + return slice, pos + + default: + panic(fmt.Sprintf("byte not supported: %q", char)) + } + + return slice, 0 +} diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 095c01ecc..90057ab42 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -44,6 +44,17 @@ func TestValueSlice(t *testing.T) { } } +func TestLargeData(t *testing.T) { + data := make([]byte, 100000) + enc := Encode(data) + value := NewValue(enc) + value.Decode() + + if value.Len() != len(data) { + t.Error("Expected data to be", len(data), "got", value.Len()) + } +} + func TestValue(t *testing.T) { value := NewValueFromBytes([]byte("\xcd\x83dog\x83god\x83cat\x01")) if value.Get(0).Str() != "dog" { From 6fd2401cdf792996c0183f896412831dd335377a Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 23:33:18 +0200 Subject: [PATCH 14/64] Fixed issue with var int reading. Reading uneven byte slices were broken. --- ethutil/bytes.go | 30 +++++++++++++++++++++++++++--- ethutil/value.go | 1 - 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 53b8cf645..eca2cc366 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -45,15 +45,15 @@ func BytesToNumber(b []byte) uint64 { // // Read a variable length number in big endian byte order func ReadVarint(reader *bytes.Reader) (ret uint64) { - if reader.Len() == 8 { + if reader.Len() > 4 { var num uint64 binary.Read(reader, binary.BigEndian, &num) ret = uint64(num) - } else if reader.Len() == 4 { + } else if reader.Len() > 2 { var num uint32 binary.Read(reader, binary.BigEndian, &num) ret = uint64(num) - } else if reader.Len() == 2 { + } else if reader.Len() > 0 { var num uint16 binary.Read(reader, binary.BigEndian, &num) ret = uint64(num) @@ -66,6 +66,30 @@ func ReadVarint(reader *bytes.Reader) (ret uint64) { return ret } +func ReadVarInt(buff []byte) (ret uint64) { + switch l := len(buff); { + case l > 4: + d := LeftPadBytes(buff, 8) + binary.Read(bytes.NewReader(d), binary.BigEndian, &ret) + case l > 2: + var num uint32 + d := LeftPadBytes(buff, 4) + binary.Read(bytes.NewReader(d), binary.BigEndian, &num) + ret = uint64(num) + case l > 1: + var num uint16 + d := LeftPadBytes(buff, 2) + binary.Read(bytes.NewReader(d), binary.BigEndian, &num) + ret = uint64(num) + default: + var num uint8 + binary.Read(bytes.NewReader(buff), binary.BigEndian, &num) + ret = uint64(num) + } + + return +} + // Binary length // // Returns the true binary length of the given number diff --git a/ethutil/value.go b/ethutil/value.go index 635683e66..85dc44ed6 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -67,7 +67,6 @@ func (val *Value) Uint() uint64 { return uint64(Val) } else if Val, ok := val.Val.([]byte); ok { return new(big.Int).SetBytes(Val).Uint64() - //return ReadVarint(bytes.NewReader(Val)) } else if Val, ok := val.Val.(*big.Int); ok { return Val.Uint64() } From 5ca29381175d553bb764040e8cd892a4ba370645 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 23:33:33 +0200 Subject: [PATCH 15/64] Fixed --- ethutil/bytes.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index eca2cc366..4027e3986 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -44,28 +44,6 @@ func BytesToNumber(b []byte) uint64 { // Read variable int // // Read a variable length number in big endian byte order -func ReadVarint(reader *bytes.Reader) (ret uint64) { - if reader.Len() > 4 { - var num uint64 - binary.Read(reader, binary.BigEndian, &num) - ret = uint64(num) - } else if reader.Len() > 2 { - var num uint32 - binary.Read(reader, binary.BigEndian, &num) - ret = uint64(num) - } else if reader.Len() > 0 { - var num uint16 - binary.Read(reader, binary.BigEndian, &num) - ret = uint64(num) - } else { - var num uint8 - binary.Read(reader, binary.BigEndian, &num) - ret = uint64(num) - } - - return ret -} - func ReadVarInt(buff []byte) (ret uint64) { switch l := len(buff); { case l > 4: From 74d701202583b49d29f5dbca00aec419bdee8e1d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 23:33:59 +0200 Subject: [PATCH 16/64] Added temp seed --- ethereum.go | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/ethereum.go b/ethereum.go index 799e9cb39..395eba954 100644 --- a/ethereum.go +++ b/ethereum.go @@ -3,10 +3,8 @@ package eth import ( "container/list" "fmt" - "io/ioutil" "math/rand" "net" - "net/http" "strconv" "strings" "sync" @@ -21,7 +19,10 @@ import ( "github.com/ethereum/eth-go/ethwire" ) -const seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt" +const ( + seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt" + seedNodeAddress = "54.76.56.74:30303" +) var ethlogger = ethlog.NewLogger("SERV") @@ -421,22 +422,10 @@ func (s *Ethereum) Seed() { } // Connect to Peer list s.ProcessPeerList(peers) - } else { - // Fallback to servers.poc3.txt - resp, err := http.Get(seedTextFileUri) - if err != nil { - ethlogger.Warnln("Fetching seed failed:", err) - return - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - ethlogger.Warnln("Reading seed failed:", err) - return - } - - s.ConnectToPeer(string(body)) } + + // XXX tmp + s.ConnectToPeer(seedNodeAddress) } func (s *Ethereum) peerHandler(listener net.Listener) { From 27f892265312255811867fab83acbeefa1626cec Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Jul 2014 23:34:21 +0200 Subject: [PATCH 17/64] Increased block request amount --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index f4314e35c..d977b2086 100644 --- a/peer.go +++ b/peer.go @@ -786,7 +786,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(30)}) + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(100)}) p.QueueMessage(msg) peerlogger.DebugDetailf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) From 1f9894c0845a5259adbfd30fe3a86631e6403b8d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Jul 2014 00:31:15 +0200 Subject: [PATCH 18/64] Old code removed and renamed amount to balance --- ethchain/block.go | 27 ------------ ethchain/block_chain.go | 7 ++-- ethchain/state_transition.go | 15 +++---- ethchain/transaction_pool.go | 79 ++---------------------------------- ethpub/types.go | 7 ++-- ethrpc/packages.go | 7 ++-- ethstate/state.go | 5 ++- ethstate/state_object.go | 39 +++++++++--------- ethvm/vm.go | 10 ++--- 9 files changed, 52 insertions(+), 144 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index e00bcb24f..ac56f58c3 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -125,33 +125,6 @@ func (block *Block) Transactions() []*Transaction { return block.transactions } -func (block *Block) PayFee(addr []byte, fee *big.Int) bool { - contract := block.state.GetStateObject(addr) - // If we can't pay the fee return - if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ { - fmt.Println("Contract has insufficient funds", contract.Amount, fee) - - return false - } - - base := new(big.Int) - contract.Amount = base.Sub(contract.Amount, fee) - block.state.Trie.Update(string(addr), string(contract.RlpEncode())) - - data := block.state.Trie.Get(string(block.Coinbase)) - - // Get the ether (Coinbase) and add the fee (gief fee to miner) - account := ethstate.NewStateObjectFromBytes(block.Coinbase, []byte(data)) - - base = new(big.Int) - account.Amount = base.Add(account.Amount, fee) - - //block.state.Trie.Update(string(block.Coinbase), string(ether.RlpEncode())) - block.state.UpdateStateObject(account) - - return true -} - func (block *Block) CalcGasLimit(parent *Block) *big.Int { if block.Number.Cmp(big.NewInt(0)) == 0 { return ethutil.BigPow(10, 6) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 1a2662787..250903798 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,11 +2,12 @@ package ethchain import ( "bytes" + "math" + "math/big" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "math" - "math/big" ) var chainlogger = ethlog.NewLogger("CHAIN") @@ -280,7 +281,7 @@ func AddTestNetFunds(block *Block) { } { codedAddr := ethutil.Hex2Bytes(addr) account := block.state.GetAccount(codedAddr) - account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) + account.Balance = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 266328ce8..02a8e0e82 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,11 +2,12 @@ package ethchain import ( "fmt" + "math/big" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethvm" - "math/big" ) /* @@ -94,8 +95,8 @@ func (self *StateTransition) BuyGas() error { var err error sender := self.Sender() - if sender.Amount.Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Amount) + if sender.Balance.Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance) } coinbase := self.Coinbase() @@ -178,8 +179,8 @@ func (self *StateTransition) TransitionState() (err error) { return } - if sender.Amount.Cmp(self.value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) + if sender.Balance.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) } var snapshot *ethstate.State @@ -240,8 +241,8 @@ func (self *StateTransition) TransitionState() (err error) { } func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObject) error { - if sender.Amount.Cmp(self.value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) + if sender.Balance.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) } // Subtract the amount from the senders account diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 21c6ea3de..b0d62fd91 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -4,11 +4,12 @@ import ( "bytes" "container/list" "fmt" + "math/big" + "sync" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethwire" - "math/big" - "sync" ) var txplogger = ethlog.NewLogger("TXP") @@ -91,78 +92,6 @@ func (pool *TxPool) addTransaction(tx *Transaction) { pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) } -/* -// Process transaction validates the Tx and processes funds from the -// sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (gas *big.Int, err error) { - fmt.Printf("state root before update %x\n", state.Root()) - defer func() { - if r := recover(); r != nil { - txplogger.Infoln(r) - err = fmt.Errorf("%v", r) - } - }() - - gas = new(big.Int) - addGas := func(g *big.Int) { gas.Add(gas, g) } - addGas(GasTx) - - // Get the sender - sender := state.GetAccount(tx.Sender()) - - if sender.Nonce != tx.Nonce { - err = NonceError(tx.Nonce, sender.Nonce) - return - } - - sender.Nonce += 1 - defer func() { - //state.UpdateStateObject(sender) - // Notify all subscribers - pool.Ethereum.Reactor().Post("newTx:post", tx) - }() - - txTotalBytes := big.NewInt(int64(len(tx.Data))) - txTotalBytes.Div(txTotalBytes, ethutil.Big32) - addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) - - rGas := new(big.Int).Set(gas) - rGas.Mul(gas, tx.GasPrice) - - // Make sure there's enough in the sender's account. Having insufficient - // funds won't invalidate this transaction but simple ignores it. - totAmount := new(big.Int).Add(tx.Value, rGas) - if sender.Amount.Cmp(totAmount) < 0 { - err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) - return - } - state.UpdateStateObject(sender) - fmt.Printf("state root after sender update %x\n", state.Root()) - - // Get the receiver - receiver := state.GetAccount(tx.Recipient) - - // Send Tx to self - if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - // Subtract the fee - sender.SubAmount(rGas) - } else { - // Subtract the amount from the senders account - sender.SubAmount(totAmount) - - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(tx.Value) - - state.UpdateStateObject(receiver) - fmt.Printf("state root after receiver update %x\n", state.Root()) - } - - txplogger.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) - - return -} -*/ - func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Get the last block so we can retrieve the sender and receiver from // the merkle trie @@ -183,7 +112,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { totAmount := new(big.Int).Set(tx.Value) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. - if sender.Amount.Cmp(totAmount) < 0 { + if sender.Balance.Cmp(totAmount) < 0 { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } diff --git a/ethpub/types.go b/ethpub/types.go index 5cfa2705e..faf75bbe1 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -3,12 +3,13 @@ package ethpub import ( "encoding/json" "fmt" + "strings" + "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "strings" ) // Peer interface exposed to QML @@ -175,9 +176,9 @@ func (c *PStateObject) GetStorage(address string) string { return "" } -func (c *PStateObject) Value() string { +func (c *PStateObject) Balance() string { if c.object != nil { - return c.object.Amount.String() + return c.object.Balance.String() } return "" diff --git a/ethrpc/packages.go b/ethrpc/packages.go index 0662f0edd..d307d0314 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -3,10 +3,11 @@ package ethrpc import ( "encoding/json" "errors" - "github.com/ethereum/eth-go/ethpub" - "github.com/ethereum/eth-go/ethutil" "math/big" "strings" + + "github.com/ethereum/eth-go/ethpub" + "github.com/ethereum/eth-go/ethutil" ) type EthereumApi struct { @@ -272,7 +273,7 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *string) error { return err } state := p.ethp.GetStateObject(args.Address) - *reply = NewSuccessRes(BalanceRes{Balance: state.Value(), Address: args.Address}) + *reply = NewSuccessRes(BalanceRes{Balance: state.Balance(), Address: args.Address}) return nil } diff --git a/ethstate/state.go b/ethstate/state.go index 51b585d4d..693a591c3 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -1,11 +1,12 @@ package ethstate import ( + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "math/big" ) var statelogger = ethlog.NewLogger("STATE") @@ -33,7 +34,7 @@ func NewState(trie *ethtrie.Trie) *State { func (self *State) GetBalance(addr []byte) *big.Int { stateObject := self.GetStateObject(addr) if stateObject != nil { - return stateObject.Amount + return stateObject.Balance } return ethutil.Big0 diff --git a/ethstate/state_object.go b/ethstate/state_object.go index ab14b8604..5932fbee6 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -2,10 +2,11 @@ package ethstate import ( "fmt" + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "math/big" ) type Code []byte @@ -30,7 +31,7 @@ type StateObject struct { // Address of the object address []byte // Shared attributes - Amount *big.Int + Balance *big.Int CodeHash []byte Nonce uint64 // Contract related attributes @@ -78,7 +79,7 @@ func NewStateObject(addr []byte) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. address := ethutil.Address(addr) - object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} + object := &StateObject{address: address, Balance: new(big.Int), gasPool: new(big.Int)} object.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) object.storage = make(Storage) object.gasPool = new(big.Int) @@ -86,9 +87,9 @@ func NewStateObject(addr []byte) *StateObject { return object } -func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { +func NewContract(address []byte, balance *big.Int, root []byte) *StateObject { contract := NewStateObject(address) - contract.Amount = Amount + contract.Balance = balance contract.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) return contract @@ -103,7 +104,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { func (self *StateObject) MarkForDeletion() { self.remove = true - statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) + statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Balance) } func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { @@ -190,19 +191,19 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { } func (c *StateObject) AddAmount(amount *big.Int) { - c.SetAmount(new(big.Int).Add(c.Amount, amount)) + c.SetBalance(new(big.Int).Add(c.Balance, amount)) - statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Balance, amount) } func (c *StateObject) SubAmount(amount *big.Int) { - c.SetAmount(new(big.Int).Sub(c.Amount, amount)) + c.SetBalance(new(big.Int).Sub(c.Balance, amount)) - statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Balance, amount) } -func (c *StateObject) SetAmount(amount *big.Int) { - c.Amount = amount +func (c *StateObject) SetBalance(amount *big.Int) { + c.Balance = amount } // @@ -213,8 +214,8 @@ func (c *StateObject) SetAmount(amount *big.Int) { func (c *StateObject) ReturnGas(gas, price *big.Int) {} func (c *StateObject) ConvertGas(gas, price *big.Int) error { total := new(big.Int).Mul(gas, price) - if total.Cmp(c.Amount) > 0 { - return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total) + if total.Cmp(c.Balance) > 0 { + return fmt.Errorf("insufficient amount: %v, %v", c.Balance, total) } c.SubAmount(total) @@ -247,12 +248,12 @@ func (self *StateObject) RefundGas(gas, price *big.Int) { rGas := new(big.Int).Set(gas) rGas.Mul(rGas, price) - self.Amount.Sub(self.Amount, rGas) + self.Balance.Sub(self.Balance, rGas) } func (self *StateObject) Copy() *StateObject { stateObject := NewStateObject(self.Address()) - stateObject.Amount.Set(self.Amount) + stateObject.Balance.Set(self.Balance) stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash) stateObject.Nonce = self.Nonce if self.State != nil { @@ -290,7 +291,7 @@ func (c *StateObject) Init() Code { // Debug stuff func (self *StateObject) CreateOutputForDiff() { - fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Amount.Bytes(), self.Nonce) + fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Balance.Bytes(), self.Nonce) self.EachStorage(func(addr string, value *ethutil.Value) { fmt.Printf("%x %x\n", addr, value.Bytes()) }) @@ -309,14 +310,14 @@ func (c *StateObject) RlpEncode() []byte { root = "" } - return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethcrypto.Sha3Bin(c.Code)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, ethcrypto.Sha3Bin(c.Code)}) } func (c *StateObject) RlpDecode(data []byte) { decoder := ethutil.NewValueFromBytes(data) c.Nonce = decoder.Get(0).Uint() - c.Amount = decoder.Get(1).BigInt() + c.Balance = decoder.Get(1).BigInt() c.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*ethutil.Value) c.gasPool = new(big.Int) diff --git a/ethvm/vm.go b/ethvm/vm.go index e0a9d831b..e469fa826 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -682,7 +682,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Create a new contract contract := self.env.State().NewStateObject(addr) - if contract.Amount.Cmp(value) >= 0 { + if contract.Balance.Cmp(value) >= 0 { closure.object.SubAmount(value) contract.AddAmount(value) @@ -700,7 +700,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // main script. contract.Code, _, err = c.Call(self, nil) } else { - err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) } if err != nil { @@ -736,8 +736,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - if closure.object.Amount.Cmp(value) < 0 { - vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + if closure.object.Balance.Cmp(value) < 0 { + vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) closure.ReturnGas(gas, nil) @@ -784,7 +784,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { receiver := self.env.State().GetOrNewStateObject(stack.Pop().Bytes()) - receiver.AddAmount(closure.object.Amount) + receiver.AddAmount(closure.object.Balance) closure.object.MarkForDeletion() From 42d47ecfb09ac0b419db5722602d9b02e21f2457 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Jul 2014 11:26:38 +0200 Subject: [PATCH 19/64] Removed peer disconnect on pong timeout. Fixes #106 This mechanism wasn't very accurate so it has been removed. --- peer.go | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/peer.go b/peer.go index d977b2086..4b0523e70 100644 --- a/peer.go +++ b/peer.go @@ -294,12 +294,14 @@ out: // Ping timer case <-pingTimer.C: - timeSince := time.Since(time.Unix(p.lastPong, 0)) - if !p.pingStartTime.IsZero() && p.lastPong != 0 && timeSince > (pingPongTimer+30*time.Second) { - peerlogger.Infof("Peer did not respond to latest pong fast enough, it took %s, disconnecting.\n", timeSince) - p.Stop() - return - } + /* + timeSince := time.Since(time.Unix(p.lastPong, 0)) + if !p.pingStartTime.IsZero() && p.lastPong != 0 && timeSince > (pingPongTimer+30*time.Second) { + peerlogger.Infof("Peer did not respond to latest pong fast enough, it took %s, disconnecting.\n", timeSince) + p.Stop() + return + } + */ p.writeMessage(ethwire.NewMessage(ethwire.MsgPingTy, "")) p.pingStartTime = time.Now() @@ -354,7 +356,7 @@ func (p *Peer) HandleInbound() { } case ethwire.MsgDiscTy: p.Stop() - peerlogger.Infoln("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint())) + peerlogger.Infoln("Disconnect peer: ", DiscReason(msg.Data.Get(0).Uint())) case ethwire.MsgPingTy: // Respond back with pong p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) @@ -363,11 +365,17 @@ func (p *Peer) HandleInbound() { // last pong so the peer handler knows this peer is still // active. p.lastPong = time.Now().Unix() - p.pingTime = time.Now().Sub(p.pingStartTime) + p.pingTime = time.Since(p.pingStartTime) case ethwire.MsgBlockTy: // Get all blocks and process them - var block, lastBlock *ethchain.Block - var err error + //var block, lastBlock *ethchain.Block + //var err error + + var ( + block, lastBlock *ethchain.Block + blockChain = p.ethereum.BlockChain() + err error + ) // Make sure we are actually receiving anything if msg.Data.Len()-1 > 1 && p.diverted { @@ -383,11 +391,11 @@ func (p *Peer) HandleInbound() { for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) // Do we have this block on our chain? If so we can continue - if !p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { + if !blockChain.HasBlock(block.Hash()) { // We don't have this block, but we do have a block with the same prevHash, diversion time! - if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { + if blockChain.HasBlockWithPrevHash(block.PrevHash) { p.diverted = false - if !p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { + if !blockChain.FindCanonicalChainFromMsg(msg, block.PrevHash) { p.SyncWithPeerToLastKnown() break nextMsg } From 5a2d62e4d9e551f16f094216da70b7a6f5d2bf00 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Jul 2014 13:06:59 +0200 Subject: [PATCH 20/64] Added better data parser --- ethutil/bytes.go | 20 ++++++++++++++++++++ ethutil/bytes_test.go | 14 ++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 ethutil/bytes_test.go diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 4027e3986..49fc229d3 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -131,6 +131,26 @@ func FormatData(data string) []byte { return BigToBytes(d, 256) } +func ParseData(data ...interface{}) (ret []byte) { + for _, item := range data { + switch t := item.(type) { + case string: + var str []byte + if IsHex(t) { + str = Hex2Bytes(t[2:]) + } else { + str = []byte(t) + } + + ret = append(ret, RightPadBytes(str, 32)...) + case []byte: + ret = append(ret, LeftPadBytes(t, 32)...) + } + } + + return +} + func RightPadBytes(slice []byte, l int) []byte { if l < len(slice) { return slice diff --git a/ethutil/bytes_test.go b/ethutil/bytes_test.go new file mode 100644 index 000000000..381efe7a2 --- /dev/null +++ b/ethutil/bytes_test.go @@ -0,0 +1,14 @@ +package ethutil + +import ( + "bytes" + "testing" +) + +func TestParseData(t *testing.T) { + data := ParseData("hello", "world", "0x0106") + exp := "68656c6c6f000000000000000000000000000000000000000000000000000000776f726c640000000000000000000000000000000000000000000000000000000106000000000000000000000000000000000000000000000000000000000000" + if bytes.Compare(data, Hex2Bytes(exp)) != 0 { + t.Error("Error parsing data") + } +} From 5ede1224e48fd82961bd4a0b2ec1a3eda0b6d99b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 1 Aug 2014 10:21:43 +0200 Subject: [PATCH 21/64] minor rlp things --- ethutil/rlp.go | 21 ++++++++------------- ethutil/value.go | 7 +++++-- peer.go | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 333a84927..cf7f97ffd 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -32,12 +32,14 @@ const ( RlpEmptyStr = 0x40 ) +const rlpEof = -1 + func Char(c []byte) int { if len(c) > 0 { return int(c[0]) } - return 0 + return rlpEof } func DecodeWithReader(reader *bytes.Buffer) interface{} { @@ -46,8 +48,6 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { // Read the next byte char := Char(reader.Next(1)) switch { - case char == 0: - return nil case char <= 0x7f: return char @@ -63,11 +63,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { length := int(char - 0xc0) for i := 0; i < length; i++ { obj := DecodeWithReader(reader) - if obj != nil { - slice = append(slice, obj) - } else { - break - } + slice = append(slice, obj) } return slice @@ -75,13 +71,12 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { length := ReadVarInt(reader.Next(int(char - 0xf7))) for i := uint64(0); i < length; i++ { obj := DecodeWithReader(reader) - if obj != nil { - slice = append(slice, obj) - } else { - break - } + slice = append(slice, obj) } + + return slice default: + panic(fmt.Sprintf("byte not supported: %q", char)) } return slice diff --git a/ethutil/value.go b/ethutil/value.go index 85dc44ed6..3128cd724 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -221,12 +221,15 @@ func (val *Value) Encode() []byte { func (self *Value) Decode() { v, _ := Decode(self.Bytes(), 0) self.Val = v + //self.Val = DecodeWithReader(bytes.NewBuffer(self.Bytes())) } func NewValueFromBytes(data []byte) *Value { if len(data) != 0 { - data, _ := Decode(data, 0) - return NewValue(data) + value := NewValue(data) + value.Decode() + + return value } return NewValue(nil) diff --git a/peer.go b/peer.go index 4b0523e70..fa683e488 100644 --- a/peer.go +++ b/peer.go @@ -403,7 +403,7 @@ func (p *Peer) HandleInbound() { } } } - if !p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) { + if !blockChain.HasBlock(lastBlock.Hash()) { // If we can't find a common ancenstor we need to request more blocks. // FIXME: At one point this won't scale anymore since we are not asking for an offset // we just keep increasing the amount of blocks. From 3debeb7236d2c8474fa9049cc91dc26bf1040b3f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 4 Aug 2014 10:38:18 +0200 Subject: [PATCH 22/64] ethtrie.NewTrie => ethtrie.New --- ethchain/block.go | 24 ++++----------------- ethchain/block_chain.go | 10 ++++----- ethchain/state_transition.go | 2 +- ethstate/state_object.go | 24 +++------------------ ethtrie/slice.go | 12 +++++++---- ethtrie/trie.go | 11 +++++----- ethtrie/trie_test.go | 41 ++++++++++++++++++------------------ ethvm/vm_test.go | 10 ++++----- 8 files changed, 52 insertions(+), 82 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index ac56f58c3..e4486f8e4 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -100,7 +100,7 @@ func CreateBlock(root interface{}, } block.SetUncles([]*Block{}) - block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, root)) + block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, root)) return block } @@ -220,26 +220,10 @@ func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { func (block *Block) setTransactions(txs []*Transaction) { block.transactions = txs - - /* - trie := ethtrie.NewTrie(ethutil.Config.Db, "") - for i, tx := range txs { - trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) - } - - switch trie.Root.(type) { - case string: - block.TxSha = []byte(trie.Root.(string)) - case []byte: - block.TxSha = trie.Root.([]byte) - default: - panic(fmt.Sprintf("invalid root type %T", trie.Root)) - } - */ } func CreateTxSha(receipts Receipts) (sha []byte) { - trie := ethtrie.NewTrie(ethutil.Config.Db, "") + trie := ethtrie.New(ethutil.Config.Db, "") for i, receipt := range receipts { trie.Update(string(ethutil.NewValue(i).Encode()), string(ethutil.NewValue(receipt.RlpData()).Encode())) } @@ -281,7 +265,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() @@ -323,7 +307,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 250903798..736fe52c7 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -132,7 +132,7 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte // Start with the newest block we got, all the way back to the common block we both know for _, block := range blocks { if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - chainlogger.Infoln("[CHAIN] We have found the common parent block, breaking") + chainlogger.Infoln("We have found the common parent block, breaking") break } chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) @@ -145,13 +145,13 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { i++ if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - chainlogger.Infoln("We have found the common parent block, breaking") + chainlogger.Infoln("Found the common parent block") break } anOtherBlock := bc.GetBlock(block.PrevHash) if anOtherBlock == nil { // We do not want to count the genesis block for difficulty since that's not being sent - chainlogger.Infoln("At genesis block, breaking") + chainlogger.Infoln("Found genesis block. Stop") break } curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) @@ -159,11 +159,11 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte chainlogger.Infoln("Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - chainlogger.Infof("The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) + chainlogger.Infof("Resetting to block %x. Changing chain.") bc.ResetTillBlockHash(commonBlockHash) return false } else { - chainlogger.Infoln("Our chain showed the incoming chain who is boss. Ignoring.") + chainlogger.Infoln("Current chain is longest chain. Ignoring incoming chain.") return true } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 02a8e0e82..8f1561c00 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -278,7 +278,7 @@ func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject contract := state.NewStateObject(addr) contract.InitCode = tx.Data - contract.State = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) + contract.State = ethstate.NewState(ethtrie.New(ethutil.Config.Db, "")) return contract } diff --git a/ethstate/state_object.go b/ethstate/state_object.go index 5932fbee6..309e3e762 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -57,30 +57,12 @@ func (self *StateObject) Reset() { self.State.Reset() } -/* -// Converts an transaction in to a state object -func MakeContract(tx *Transaction, state *State) *StateObject { - // Create contract if there's no recipient - if tx.IsContract() { - addr := tx.CreationAddress() - - contract := state.NewStateObject(addr) - contract.initCode = tx.Data - contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) - - return contract - } - - return nil -} -*/ - func NewStateObject(addr []byte) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. address := ethutil.Address(addr) object := &StateObject{address: address, Balance: new(big.Int), gasPool: new(big.Int)} - object.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) + object.State = NewState(ethtrie.New(ethutil.Config.Db, "")) object.storage = make(Storage) object.gasPool = new(big.Int) @@ -90,7 +72,7 @@ func NewStateObject(addr []byte) *StateObject { func NewContract(address []byte, balance *big.Int, root []byte) *StateObject { contract := NewStateObject(address) contract.Balance = balance - contract.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) + contract.State = NewState(ethtrie.New(ethutil.Config.Db, string(root))) return contract } @@ -318,7 +300,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.Nonce = decoder.Get(0).Uint() c.Balance = decoder.Get(1).BigInt() - c.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.State = NewState(ethtrie.New(ethutil.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*ethutil.Value) c.gasPool = new(big.Int) diff --git a/ethtrie/slice.go b/ethtrie/slice.go index b9d5d1285..cf4e8df7a 100644 --- a/ethtrie/slice.go +++ b/ethtrie/slice.go @@ -1,6 +1,6 @@ package ethtrie -import () +import "math" // Helper function for comparing slices func CompareIntSlice(a, b []int) bool { @@ -17,9 +17,13 @@ func CompareIntSlice(a, b []int) bool { // Returns the amount of nibbles that match each other from 0 ... func MatchingNibbleLength(a, b []int) int { - i := 0 - for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { - i += 1 + var i, length = 0, int(math.Min(float64(len(a)), float64(len(b)))) + + for i < length { + if a[i] != b[i] { + break + } + i++ } return i diff --git a/ethtrie/trie.go b/ethtrie/trie.go index f0f3fe5a8..38ae0754d 100644 --- a/ethtrie/trie.go +++ b/ethtrie/trie.go @@ -3,16 +3,17 @@ package ethtrie import ( "bytes" "fmt" - "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethutil" _ "reflect" "sync" + + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethutil" ) func __ignore() { fmt.Println("") } func ParanoiaCheck(t1 *Trie) (bool, *Trie) { - t2 := NewTrie(ethutil.Config.Db, "") + t2 := New(ethutil.Config.Db, "") t1.NewIterator().Each(func(key string, v *ethutil.Value) { t2.Update(key, v.Str()) @@ -158,7 +159,7 @@ func copyRoot(root interface{}) interface{} { return prevRootCopy } -func NewTrie(db ethutil.Database, Root interface{}) *Trie { +func New(db ethutil.Database, Root interface{}) *Trie { // Make absolute sure the root is copied r := copyRoot(Root) p := copyRoot(Root) @@ -221,7 +222,7 @@ func (t *Trie) Cmp(trie *Trie) bool { // Returns a copy of this trie func (t *Trie) Copy() *Trie { - trie := NewTrie(t.cache.db, t.Root) + trie := New(t.cache.db, t.Root) for key, node := range t.cache.nodes { trie.cache.nodes[key] = node.Copy() } diff --git a/ethtrie/trie_test.go b/ethtrie/trie_test.go index 3989a8f45..2661f8f25 100644 --- a/ethtrie/trie_test.go +++ b/ethtrie/trie_test.go @@ -5,13 +5,14 @@ import ( _ "encoding/hex" _ "encoding/json" "fmt" - "github.com/ethereum/eth-go/ethutil" _ "io/ioutil" _ "math/rand" _ "net/http" _ "reflect" "testing" _ "time" + + "github.com/ethereum/eth-go/ethutil" ) const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ" @@ -38,14 +39,14 @@ func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } -func New() (*MemDatabase, *Trie) { +func NewTrie() (*MemDatabase, *Trie) { db, _ := NewMemDatabase() - return db, NewTrie(db, "") + return db, New(db, "") } /* func TestTrieSync(t *testing.T) { - db, trie := New() + db, trie := NewTrie() trie.Update("dog", LONG_WORD) if len(db.db) != 0 { @@ -59,7 +60,7 @@ func TestTrieSync(t *testing.T) { } func TestTrieDirtyTracking(t *testing.T) { - _, trie := New() + _, trie := NewTrie() trie.Update("dog", LONG_WORD) if !trie.cache.IsDirty { t.Error("Expected trie to be dirty") @@ -79,7 +80,7 @@ func TestTrieDirtyTracking(t *testing.T) { } func TestTrieReset(t *testing.T) { - _, trie := New() + _, trie := NewTrie() trie.Update("cat", LONG_WORD) if len(trie.cache.nodes) == 0 { @@ -94,7 +95,7 @@ func TestTrieReset(t *testing.T) { } func TestTrieGet(t *testing.T) { - _, trie := New() + _, trie := NewTrie() trie.Update("cat", LONG_WORD) x := trie.Get("cat") @@ -104,7 +105,7 @@ func TestTrieGet(t *testing.T) { } func TestTrieUpdating(t *testing.T) { - _, trie := New() + _, trie := NewTrie() trie.Update("cat", LONG_WORD) trie.Update("cat", LONG_WORD+"1") x := trie.Get("cat") @@ -114,8 +115,8 @@ func TestTrieUpdating(t *testing.T) { } func TestTrieCmp(t *testing.T) { - _, trie1 := New() - _, trie2 := New() + _, trie1 := NewTrie() + _, trie2 := NewTrie() trie1.Update("doge", LONG_WORD) trie2.Update("doge", LONG_WORD) @@ -131,7 +132,7 @@ func TestTrieCmp(t *testing.T) { } func TestTrieDelete(t *testing.T) { - _, trie := New() + _, trie := NewTrie() trie.Update("cat", LONG_WORD) exp := trie.Root trie.Update("dog", LONG_WORD) @@ -150,7 +151,7 @@ func TestTrieDelete(t *testing.T) { } func TestTrieDeleteWithValue(t *testing.T) { - _, trie := New() + _, trie := NewTrie() trie.Update("c", LONG_WORD) exp := trie.Root trie.Update("ca", LONG_WORD) @@ -164,7 +165,7 @@ func TestTrieDeleteWithValue(t *testing.T) { } func TestTriePurge(t *testing.T) { - _, trie := New() + _, trie := NewTrie() trie.Update("c", LONG_WORD) trie.Update("ca", LONG_WORD) trie.Update("cat", LONG_WORD) @@ -248,7 +249,7 @@ func CreateTests(uri string, cb func(Test)) map[string]Test { func TestRemote(t *testing.T) { CreateTests("https://raw.githubusercontent.com/ethereum/tests/develop/trietest.json", func(test Test) { - _, trie := New() + _, trie := NewTrie() for key, value := range test.In { trie.Update(get(key), get(value)) } @@ -263,12 +264,12 @@ func TestRemote(t *testing.T) { func TestTrieReplay(t *testing.T) { CreateTests("https://raw.githubusercontent.com/ethereum/tests/develop/trietest.json", func(test Test) { - _, trie := New() + _, trie := NewTrie() for key, value := range test.In { trie.Update(get(key), get(value)) } - _, trie2 := New() + _, trie2 := NewTrie() trie.NewIterator().Each(func(key string, v *ethutil.Value) { trie2.Update(key, v.Str()) }) @@ -314,7 +315,7 @@ func TestRegression(t *testing.T) { roots := make(map[string]int) for i := 0; i < MaxTest; i++ { - _, trie := New() + _, trie := NewTrie() data := RandomData() for _, test := range data { @@ -333,7 +334,7 @@ func TestRegression(t *testing.T) { } func TestDelete(t *testing.T) { - _, trie := New() + _, trie := NewTrie() trie.Update("a", "jeffreytestlongstring") trie.Update("aa", "otherstring") @@ -352,7 +353,7 @@ func TestDelete(t *testing.T) { trie.Update("aaaa", "testmegood") fmt.Println("aa =>", trie.Get("aa")) - _, t2 := New() + _, t2 := NewTrie() trie.NewIterator().Each(func(key string, v *ethutil.Value) { if key == "aaaa" { t2.Update(key, v.Str()) @@ -369,7 +370,7 @@ func TestDelete(t *testing.T) { */ func TestRndCase(t *testing.T) { - _, trie := New() + _, trie := NewTrie() data := []struct{ k, v string }{ {"0000000000000000000000000000000000000000000000000000000000000001", "a07573657264617461000000000000000000000000000000000000000000000000"}, diff --git a/ethvm/vm_test.go b/ethvm/vm_test.go index 501d0c284..5b3a9aef1 100644 --- a/ethvm/vm_test.go +++ b/ethvm/vm_test.go @@ -2,14 +2,14 @@ package ethvm import ( "fmt" - "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethstate" - "github.com/ethereum/eth-go/ethutil" "log" "math/big" "os" "testing" + + "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" ) type TestEnv struct { @@ -27,9 +27,7 @@ func (self TestEnv) State() *ethstate.State { return nil } func TestVm(t *testing.T) { ethlog.AddLogSystem(ethlog.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlog.LogLevel(4))) - db, _ := ethdb.NewMemDatabase() ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - ethutil.Config.Db = db stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'}) callerClosure := NewClosure(stateObject, stateObject, []byte{0x60, 0x01}, big.NewInt(1000000), big.NewInt(0)) From 03ce15df4c7ef51d4373233ab5c3766282b31771 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 4 Aug 2014 10:42:40 +0200 Subject: [PATCH 23/64] ethstate.NewState => ethstate.New --- ethchain/block.go | 6 +++--- ethchain/state_transition.go | 2 +- ethstate/state.go | 4 ++-- ethstate/state_object.go | 6 +++--- ethstate/state_test.go | 5 +++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index e4486f8e4..321af6183 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -100,7 +100,7 @@ func CreateBlock(root interface{}, } block.SetUncles([]*Block{}) - block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, root)) + block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, root)) return block } @@ -265,7 +265,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() @@ -307,7 +307,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8f1561c00..dfcbfcc04 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -278,7 +278,7 @@ func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject contract := state.NewStateObject(addr) contract.InitCode = tx.Data - contract.State = ethstate.NewState(ethtrie.New(ethutil.Config.Db, "")) + contract.State = ethstate.New(ethtrie.New(ethutil.Config.Db, "")) return contract } diff --git a/ethstate/state.go b/ethstate/state.go index 693a591c3..10bcf6335 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -26,7 +26,7 @@ type State struct { } // Create a new state from a given trie -func NewState(trie *ethtrie.Trie) *State { +func New(trie *ethtrie.Trie) *State { return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } @@ -128,7 +128,7 @@ func (s *State) Cmp(other *State) bool { func (self *State) Copy() *State { if self.Trie != nil { - state := NewState(self.Trie.Copy()) + state := New(self.Trie.Copy()) for k, stateObject := range self.stateObjects { state.stateObjects[k] = stateObject.Copy() } diff --git a/ethstate/state_object.go b/ethstate/state_object.go index 309e3e762..67d09edd8 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -62,7 +62,7 @@ func NewStateObject(addr []byte) *StateObject { address := ethutil.Address(addr) object := &StateObject{address: address, Balance: new(big.Int), gasPool: new(big.Int)} - object.State = NewState(ethtrie.New(ethutil.Config.Db, "")) + object.State = New(ethtrie.New(ethutil.Config.Db, "")) object.storage = make(Storage) object.gasPool = new(big.Int) @@ -72,7 +72,7 @@ func NewStateObject(addr []byte) *StateObject { func NewContract(address []byte, balance *big.Int, root []byte) *StateObject { contract := NewStateObject(address) contract.Balance = balance - contract.State = NewState(ethtrie.New(ethutil.Config.Db, string(root))) + contract.State = New(ethtrie.New(ethutil.Config.Db, string(root))) return contract } @@ -300,7 +300,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.Nonce = decoder.Get(0).Uint() c.Balance = decoder.Get(1).BigInt() - c.State = NewState(ethtrie.New(ethutil.Config.Db, decoder.Get(2).Interface())) + c.State = New(ethtrie.New(ethutil.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*ethutil.Value) c.gasPool = new(big.Int) diff --git a/ethstate/state_test.go b/ethstate/state_test.go index cd13e80bc..00c9de9d6 100644 --- a/ethstate/state_test.go +++ b/ethstate/state_test.go @@ -1,10 +1,11 @@ package ethstate import ( + "testing" + "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "testing" ) var ZeroHash256 = make([]byte, 32) @@ -14,7 +15,7 @@ func TestSnapshot(t *testing.T) { ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") ethutil.Config.Db = db - state := NewState(ethtrie.NewTrie(db, "")) + state := New(ethtrie.New(db, "")) stateObject := state.GetOrNewStateObject([]byte("aa")) From 342cc122b43f01301d0188de1e333c32ed64ae8c Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 4 Aug 2014 16:25:53 +0200 Subject: [PATCH 24/64] Added general Pipe API --- ethpipe/config.go | 47 +++++++++++++++ ethpipe/pipe.go | 135 +++++++++++++++++++++++++++++++++++++++++++ ethpipe/pipe_test.go | 57 ++++++++++++++++++ ethpipe/vm_env.go | 33 +++++++++++ ethpipe/world.go | 60 +++++++++++++++++++ ethutil/value.go | 13 +++++ 6 files changed, 345 insertions(+) create mode 100644 ethpipe/config.go create mode 100644 ethpipe/pipe.go create mode 100644 ethpipe/pipe_test.go create mode 100644 ethpipe/vm_env.go create mode 100644 ethpipe/world.go diff --git a/ethpipe/config.go b/ethpipe/config.go new file mode 100644 index 000000000..764f5596f --- /dev/null +++ b/ethpipe/config.go @@ -0,0 +1,47 @@ +package ethpipe + +import ( + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" +) + +var cnfCtr = ethutil.Hex2Bytes("661005d2720d855f1d9976f88bb10c1a3398c77f") + +type object struct { + *ethstate.StateObject +} + +func (self object) StorageString(str string) *ethutil.Value { + if ethutil.IsHex(str) { + return self.Storage(ethutil.Hex2Bytes(str[2:])) + } else { + return self.Storage(ethutil.RightPadBytes([]byte(str), 32)) + } +} + +func (self object) Storage(addr []byte) *ethutil.Value { + return self.StateObject.GetStorage(ethutil.BigD(addr)) +} + +type config struct { + pipe *Pipe +} + +func (self *config) Get(name string) object { + configCtrl := self.pipe.World().safeGet(cnfCtr) + var addr []byte + + switch name { + case "NameReg": + addr = []byte{0} + default: + addr = ethutil.RightPadBytes([]byte(name), 32) + } + + objectAddr := configCtrl.GetStorage(ethutil.BigD(addr)) + return object{self.pipe.World().safeGet(objectAddr.Bytes())} +} + +func (self *config) Exist() bool { + return self.pipe.World().Get(cnfCtr) != nil +} diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go new file mode 100644 index 000000000..710fc4e7c --- /dev/null +++ b/ethpipe/pipe.go @@ -0,0 +1,135 @@ +package ethpipe + +import ( + "strings" + + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethvm" +) + +var logger = ethlog.NewLogger("PIPE") + +type Pipe struct { + obj ethchain.EthManager + stateManager *ethchain.StateManager + blockChain *ethchain.BlockChain + world *world +} + +func New(obj ethchain.EthManager) *Pipe { + pipe := &Pipe{ + obj: obj, + stateManager: obj.StateManager(), + blockChain: obj.BlockChain(), + } + pipe.world = NewWorld(pipe) + + return pipe +} + +func (self *Pipe) Balance(addr []byte) *ethutil.Value { + return ethutil.NewValue(self.World().safeGet(addr).Balance) +} + +func (self *Pipe) Nonce(addr []byte) uint64 { + return self.World().safeGet(addr).Nonce +} + +func (self *Pipe) Execute(addr []byte, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { + return self.ExecuteObject(self.World().safeGet(addr), data, value, gas, price) +} + +func (self *Pipe) ExecuteObject(object *ethstate.StateObject, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { + var ( + initiator = ethstate.NewStateObject([]byte{0}) + state = self.World().State().Copy() + block = self.blockChain.CurrentBlock + ) + + vm := ethvm.New(NewEnv(state, block, value.BigInt(), initiator.Address())) + + closure := ethvm.NewClosure(initiator, object, object.Code, gas.BigInt(), price.BigInt()) + ret, _, err := closure.Call(vm, data) + + return ret, err +} + +func (self *Pipe) Block(hash []byte) *ethchain.Block { + return self.blockChain.GetBlock(hash) +} + +func (self *Pipe) Storage(addr, storageAddr []byte) *ethutil.Value { + return self.World().safeGet(addr).GetStorage(ethutil.BigD(storageAddr)) +} + +func (self *Pipe) ToAddress(priv []byte) []byte { + pair, err := ethcrypto.NewKeyPairFromSec(priv) + if err != nil { + return nil + } + + return pair.Address() +} + +func (self *Pipe) TransactString(key *ethcrypto.KeyPair, rec string, value, gas, price *ethutil.Value, data []byte) error { + // Check if an address is stored by this address + var hash []byte + addr := self.World().Config().Get("NameReg").StorageString(rec).Bytes() + if len(addr) > 0 { + hash = addr + } else if ethutil.IsHex(rec) { + hash = ethutil.Hex2Bytes(rec[2:]) + } else { + hash = ethutil.Hex2Bytes(rec) + } + + return self.Transact(key, hash, value, gas, price, data) +} + +func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price *ethutil.Value, data []byte) error { + var hash []byte + var contractCreation bool + if rec == nil { + contractCreation = true + } + + var tx *ethchain.Transaction + // Compile and assemble the given data + if contractCreation { + script, err := ethutil.Compile(string(data), false) + if err != nil { + return err + } + + tx = ethchain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), script) + } else { + data := ethutil.StringToByteFunc(string(data), func(s string) (ret []byte) { + slice := strings.Split(s, "\n") + for _, dataItem := range slice { + d := ethutil.FormatData(dataItem) + ret = append(ret, d...) + } + return + }) + + tx = ethchain.NewTransactionMessage(hash, value.BigInt(), gas.BigInt(), price.BigInt(), data) + } + + acc := self.stateManager.TransState().GetOrNewStateObject(key.Address()) + tx.Nonce = acc.Nonce + acc.Nonce += 1 + self.stateManager.TransState().UpdateStateObject(acc) + + tx.Sign(key.PrivateKey) + self.obj.TxPool().QueueTransaction(tx) + + if contractCreation { + logger.Infof("Contract addr %x", tx.CreationAddress()) + } + + return nil +} diff --git a/ethpipe/pipe_test.go b/ethpipe/pipe_test.go new file mode 100644 index 000000000..d0b8ef948 --- /dev/null +++ b/ethpipe/pipe_test.go @@ -0,0 +1,57 @@ +package ethpipe + +import ( + "testing" + + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" +) + +func Val(v interface{}) *ethutil.Value { + return ethutil.NewValue(v) +} + +func TestNew(t *testing.T) { + pipe := New(nil) + + var addr, privy, recp, data []byte + var object *ethstate.StateObject + var key *ethcrypto.KeyPair + + world := pipe.World() + world.Get(addr) + world.Coinbase() + world.IsMining() + world.IsListening() + world.State() + peers := world.Peers() + peers.Len() + + // Shortcut functions + pipe.Balance(addr) + pipe.Nonce(addr) + pipe.Block(addr) + pipe.Storage(addr, addr) + pipe.ToAddress(privy) + // Doesn't change state + pipe.Execute(addr, nil, Val(0), Val(1000000), Val(10)) + // Doesn't change state + pipe.ExecuteObject(object, nil, Val(0), Val(1000000), Val(10)) + + conf := world.Config() + namereg := conf.Get("NameReg") + namereg.Storage(addr) + + var err error + // Transact + err = pipe.Transact(key, recp, ethutil.NewValue(0), ethutil.NewValue(0), ethutil.NewValue(0), nil) + if err != nil { + t.Error(err) + } + // Create + err = pipe.Transact(key, nil, ethutil.NewValue(0), ethutil.NewValue(0), ethutil.NewValue(0), data) + if err != nil { + t.Error(err) + } +} diff --git a/ethpipe/vm_env.go b/ethpipe/vm_env.go new file mode 100644 index 000000000..c06a2a763 --- /dev/null +++ b/ethpipe/vm_env.go @@ -0,0 +1,33 @@ +package ethpipe + +import ( + "math/big" + + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethstate" +) + +type VMEnv struct { + state *ethstate.State + block *ethchain.Block + value *big.Int + sender []byte +} + +func NewEnv(state *ethstate.State, block *ethchain.Block, value *big.Int, sender []byte) *VMEnv { + return &VMEnv{ + state: state, + block: block, + value: value, + sender: sender, + } +} + +func (self *VMEnv) Origin() []byte { return self.sender } +func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number } +func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } +func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } +func (self *VMEnv) Time() int64 { return self.block.Time } +func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } +func (self *VMEnv) Value() *big.Int { return self.value } +func (self *VMEnv) State() *ethstate.State { return self.state } diff --git a/ethpipe/world.go b/ethpipe/world.go new file mode 100644 index 000000000..507391521 --- /dev/null +++ b/ethpipe/world.go @@ -0,0 +1,60 @@ +package ethpipe + +import ( + "container/list" + + "github.com/ethereum/eth-go/ethstate" +) + +type world struct { + pipe *Pipe + cfg *config +} + +func NewWorld(pipe *Pipe) *world { + world := &world{pipe, nil} + world.cfg = &config{pipe} + + return world +} + +func (self *Pipe) World() *world { + return self.world +} + +func (self *world) State() *ethstate.State { + return self.pipe.stateManager.CurrentState() +} + +func (self *world) Get(addr []byte) *ethstate.StateObject { + return self.State().GetStateObject(addr) +} + +func (self *world) safeGet(addr []byte) *ethstate.StateObject { + object := self.Get(addr) + if object != nil { + return object + } + + return ethstate.NewStateObject(addr) +} + +func (self *world) Coinbase() *ethstate.StateObject { + return nil +} + +func (self *world) IsMining() bool { + return self.pipe.obj.IsMining() +} + +func (self *world) IsListening() bool { + return self.pipe.obj.IsListening() +} + +func (self *world) Peers() *list.List { + return self.obj.Peers() +} + +func (self *world) Config() *config { + return self.cfg +} diff --git a/ethutil/value.go b/ethutil/value.go index 3128cd724..2233b978c 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -122,6 +122,14 @@ func (val *Value) Bytes() []byte { return []byte{} } +func (val *Value) Err() error { + if err, ok := val.Val.(error); ok { + return err + } + + return nil +} + func (val *Value) Slice() []interface{} { if d, ok := val.Val.([]interface{}); ok { return d @@ -157,6 +165,11 @@ func (val *Value) IsStr() bool { return val.Type() == reflect.String } +func (self *Value) IsErr() bool { + _, ok := self.Val.(error) + return ok +} + // Special list checking function. Something is considered // a list if it's of type []interface{}. The list is usually // used in conjunction with rlp decoded streams. From 0f84b9c30d06a59f20a2d33ffd1281d5e6e2681a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 4 Aug 2014 16:34:55 +0200 Subject: [PATCH 25/64] Added exist method --- ethpipe/pipe.go | 4 ++++ ethpipe/pipe_test.go | 1 + 2 files changed, 5 insertions(+) diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index 710fc4e7c..ca0a3416c 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -75,6 +75,10 @@ func (self *Pipe) ToAddress(priv []byte) []byte { return pair.Address() } +func (self *Pipe) Exists(addr []byte) bool { + return self.World().Get(addr) != nil +} + func (self *Pipe) TransactString(key *ethcrypto.KeyPair, rec string, value, gas, price *ethutil.Value, data []byte) error { // Check if an address is stored by this address var hash []byte diff --git a/ethpipe/pipe_test.go b/ethpipe/pipe_test.go index d0b8ef948..071213050 100644 --- a/ethpipe/pipe_test.go +++ b/ethpipe/pipe_test.go @@ -34,6 +34,7 @@ func TestNew(t *testing.T) { pipe.Block(addr) pipe.Storage(addr, addr) pipe.ToAddress(privy) + pipe.Exists(addr) // Doesn't change state pipe.Execute(addr, nil, Val(0), Val(1000000), Val(10)) // Doesn't change state From c215bbadf13ec70e4d1b65e67d4ff4568d644542 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 Aug 2014 10:17:26 +0200 Subject: [PATCH 26/64] pipe --- ethpipe/world.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethpipe/world.go b/ethpipe/world.go index 507391521..42e19fe00 100644 --- a/ethpipe/world.go +++ b/ethpipe/world.go @@ -52,7 +52,7 @@ func (self *world) IsListening() bool { } func (self *world) Peers() *list.List { - return self.obj.Peers() + return self.pipe.obj.Peers() } func (self *world) Config() *config { From 4f0bda403ea332eeb477f8e56457423628772b19 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 Aug 2014 11:10:24 +0200 Subject: [PATCH 27/64] Added vm options for object execution --- ethpipe/config.go | 26 ++++---------------------- ethpipe/object.go | 26 ++++++++++++++++++++++++++ ethpipe/pipe.go | 33 ++++++++++++++++++++++----------- ethpipe/world.go | 12 ++++++------ 4 files changed, 58 insertions(+), 39 deletions(-) create mode 100644 ethpipe/object.go diff --git a/ethpipe/config.go b/ethpipe/config.go index 764f5596f..81d36d514 100644 --- a/ethpipe/config.go +++ b/ethpipe/config.go @@ -1,33 +1,14 @@ package ethpipe -import ( - "github.com/ethereum/eth-go/ethstate" - "github.com/ethereum/eth-go/ethutil" -) +import "github.com/ethereum/eth-go/ethutil" var cnfCtr = ethutil.Hex2Bytes("661005d2720d855f1d9976f88bb10c1a3398c77f") -type object struct { - *ethstate.StateObject -} - -func (self object) StorageString(str string) *ethutil.Value { - if ethutil.IsHex(str) { - return self.Storage(ethutil.Hex2Bytes(str[2:])) - } else { - return self.Storage(ethutil.RightPadBytes([]byte(str), 32)) - } -} - -func (self object) Storage(addr []byte) *ethutil.Value { - return self.StateObject.GetStorage(ethutil.BigD(addr)) -} - type config struct { pipe *Pipe } -func (self *config) Get(name string) object { +func (self *config) Get(name string) *object { configCtrl := self.pipe.World().safeGet(cnfCtr) var addr []byte @@ -39,7 +20,8 @@ func (self *config) Get(name string) object { } objectAddr := configCtrl.GetStorage(ethutil.BigD(addr)) - return object{self.pipe.World().safeGet(objectAddr.Bytes())} + + return &object{self.pipe.World().safeGet(objectAddr.Bytes())} } func (self *config) Exist() bool { diff --git a/ethpipe/object.go b/ethpipe/object.go new file mode 100644 index 000000000..ebfb5b904 --- /dev/null +++ b/ethpipe/object.go @@ -0,0 +1,26 @@ +package ethpipe + +import ( + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" +) + +type object struct { + *ethstate.StateObject +} + +func (self *object) StorageString(str string) *ethutil.Value { + if ethutil.IsHex(str) { + return self.Storage(ethutil.Hex2Bytes(str[2:])) + } else { + return self.Storage(ethutil.RightPadBytes([]byte(str), 32)) + } +} + +func (self *object) StorageValue(addr *ethutil.Value) *ethutil.Value { + return self.Storage(addr.Bytes()) +} + +func (self *object) Storage(addr []byte) *ethutil.Value { + return self.StateObject.GetStorage(ethutil.BigD(addr)) +} diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index ca0a3416c..876a953aa 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -13,11 +13,17 @@ import ( var logger = ethlog.NewLogger("PIPE") +type VmVars struct { + State *ethstate.State +} + type Pipe struct { obj ethchain.EthManager stateManager *ethchain.StateManager blockChain *ethchain.BlockChain world *world + + Vm VmVars } func New(obj ethchain.EthManager) *Pipe { @@ -40,19 +46,22 @@ func (self *Pipe) Nonce(addr []byte) uint64 { } func (self *Pipe) Execute(addr []byte, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { - return self.ExecuteObject(self.World().safeGet(addr), data, value, gas, price) + return self.ExecuteObject(&object{self.World().safeGet(addr)}, data, value, gas, price) } -func (self *Pipe) ExecuteObject(object *ethstate.StateObject, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { +func (self *Pipe) ExecuteObject(object *object, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { var ( - initiator = ethstate.NewStateObject([]byte{0}) - state = self.World().State().Copy() - block = self.blockChain.CurrentBlock + initiator = ethstate.NewStateObject([]byte{0}) + block = self.blockChain.CurrentBlock + stateObject = object.StateObject ) + if self.Vm.State == nil { + self.Vm.State = self.World().State().Copy() + } - vm := ethvm.New(NewEnv(state, block, value.BigInt(), initiator.Address())) + vm := ethvm.New(NewEnv(self.Vm.State, block, value.BigInt(), initiator.Address())) - closure := ethvm.NewClosure(initiator, object, object.Code, gas.BigInt(), price.BigInt()) + closure := ethvm.NewClosure(initiator, stateObject, object.Code, gas.BigInt(), price.BigInt()) ret, _, err := closure.Call(vm, data) return ret, err @@ -79,7 +88,7 @@ func (self *Pipe) Exists(addr []byte) bool { return self.World().Get(addr) != nil } -func (self *Pipe) TransactString(key *ethcrypto.KeyPair, rec string, value, gas, price *ethutil.Value, data []byte) error { +func (self *Pipe) TransactString(key *ethcrypto.KeyPair, rec string, value, gas, price *ethutil.Value, data []byte) ([]byte, error) { // Check if an address is stored by this address var hash []byte addr := self.World().Config().Get("NameReg").StorageString(rec).Bytes() @@ -94,7 +103,7 @@ func (self *Pipe) TransactString(key *ethcrypto.KeyPair, rec string, value, gas, return self.Transact(key, hash, value, gas, price, data) } -func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price *ethutil.Value, data []byte) error { +func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price *ethutil.Value, data []byte) ([]byte, error) { var hash []byte var contractCreation bool if rec == nil { @@ -106,7 +115,7 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price if contractCreation { script, err := ethutil.Compile(string(data), false) if err != nil { - return err + return nil, err } tx = ethchain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), script) @@ -133,7 +142,9 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price if contractCreation { logger.Infof("Contract addr %x", tx.CreationAddress()) + + return tx.CreationAddress(), nil } - return nil + return tx.Hash(), nil } diff --git a/ethpipe/world.go b/ethpipe/world.go index 42e19fe00..25e2a1952 100644 --- a/ethpipe/world.go +++ b/ethpipe/world.go @@ -26,17 +26,17 @@ func (self *world) State() *ethstate.State { return self.pipe.stateManager.CurrentState() } -func (self *world) Get(addr []byte) *ethstate.StateObject { - return self.State().GetStateObject(addr) +func (self *world) Get(addr []byte) *object { + return &object{self.State().GetStateObject(addr)} } func (self *world) safeGet(addr []byte) *ethstate.StateObject { - object := self.Get(addr) - if object != nil { - return object + object := self.State().GetStateObject(addr) + if object == nil { + object = ethstate.NewStateObject(addr) } - return ethstate.NewStateObject(addr) + return object } func (self *world) Coinbase() *ethstate.StateObject { From e71b198e3d8df1bd8b73bae9bc934b778a3115bf Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 Aug 2014 11:26:12 +0200 Subject: [PATCH 28/64] Renamed object to Object --- ethpipe/config.go | 4 ++-- ethpipe/object.go | 8 ++++---- ethpipe/pipe.go | 4 ++-- ethpipe/world.go | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ethpipe/config.go b/ethpipe/config.go index 81d36d514..588fc8d97 100644 --- a/ethpipe/config.go +++ b/ethpipe/config.go @@ -8,7 +8,7 @@ type config struct { pipe *Pipe } -func (self *config) Get(name string) *object { +func (self *config) Get(name string) *Object { configCtrl := self.pipe.World().safeGet(cnfCtr) var addr []byte @@ -21,7 +21,7 @@ func (self *config) Get(name string) *object { objectAddr := configCtrl.GetStorage(ethutil.BigD(addr)) - return &object{self.pipe.World().safeGet(objectAddr.Bytes())} + return &Object{self.pipe.World().safeGet(objectAddr.Bytes())} } func (self *config) Exist() bool { diff --git a/ethpipe/object.go b/ethpipe/object.go index ebfb5b904..f0032992c 100644 --- a/ethpipe/object.go +++ b/ethpipe/object.go @@ -5,11 +5,11 @@ import ( "github.com/ethereum/eth-go/ethutil" ) -type object struct { +type Object struct { *ethstate.StateObject } -func (self *object) StorageString(str string) *ethutil.Value { +func (self *Object) StorageString(str string) *ethutil.Value { if ethutil.IsHex(str) { return self.Storage(ethutil.Hex2Bytes(str[2:])) } else { @@ -17,10 +17,10 @@ func (self *object) StorageString(str string) *ethutil.Value { } } -func (self *object) StorageValue(addr *ethutil.Value) *ethutil.Value { +func (self *Object) StorageValue(addr *ethutil.Value) *ethutil.Value { return self.Storage(addr.Bytes()) } -func (self *object) Storage(addr []byte) *ethutil.Value { +func (self *Object) Storage(addr []byte) *ethutil.Value { return self.StateObject.GetStorage(ethutil.BigD(addr)) } diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index 876a953aa..c00731b84 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -46,10 +46,10 @@ func (self *Pipe) Nonce(addr []byte) uint64 { } func (self *Pipe) Execute(addr []byte, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { - return self.ExecuteObject(&object{self.World().safeGet(addr)}, data, value, gas, price) + return self.ExecuteObject(&Object{self.World().safeGet(addr)}, data, value, gas, price) } -func (self *Pipe) ExecuteObject(object *object, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { +func (self *Pipe) ExecuteObject(object *Object, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { var ( initiator = ethstate.NewStateObject([]byte{0}) block = self.blockChain.CurrentBlock diff --git a/ethpipe/world.go b/ethpipe/world.go index 25e2a1952..2a07f340c 100644 --- a/ethpipe/world.go +++ b/ethpipe/world.go @@ -26,8 +26,8 @@ func (self *world) State() *ethstate.State { return self.pipe.stateManager.CurrentState() } -func (self *world) Get(addr []byte) *object { - return &object{self.State().GetStateObject(addr)} +func (self *world) Get(addr []byte) *Object { + return &Object{self.State().GetStateObject(addr)} } func (self *world) safeGet(addr []byte) *ethstate.StateObject { From 3c78e418fbe70cfb574302f00962cf7fac50f69e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 Aug 2014 11:30:12 +0200 Subject: [PATCH 29/64] world => World --- ethpipe/pipe.go | 2 +- ethpipe/world.go | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index c00731b84..a9da66ab8 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -21,7 +21,7 @@ type Pipe struct { obj ethchain.EthManager stateManager *ethchain.StateManager blockChain *ethchain.BlockChain - world *world + world *World Vm VmVars } diff --git a/ethpipe/world.go b/ethpipe/world.go index 2a07f340c..2c6b0b4b9 100644 --- a/ethpipe/world.go +++ b/ethpipe/world.go @@ -6,31 +6,31 @@ import ( "github.com/ethereum/eth-go/ethstate" ) -type world struct { +type World struct { pipe *Pipe cfg *config } -func NewWorld(pipe *Pipe) *world { - world := &world{pipe, nil} +func NewWorld(pipe *Pipe) *World { + world := &World{pipe, nil} world.cfg = &config{pipe} return world } -func (self *Pipe) World() *world { +func (self *Pipe) World() *World { return self.world } -func (self *world) State() *ethstate.State { +func (self *World) State() *ethstate.State { return self.pipe.stateManager.CurrentState() } -func (self *world) Get(addr []byte) *Object { +func (self *World) Get(addr []byte) *Object { return &Object{self.State().GetStateObject(addr)} } -func (self *world) safeGet(addr []byte) *ethstate.StateObject { +func (self *World) safeGet(addr []byte) *ethstate.StateObject { object := self.State().GetStateObject(addr) if object == nil { object = ethstate.NewStateObject(addr) @@ -39,22 +39,22 @@ func (self *world) safeGet(addr []byte) *ethstate.StateObject { return object } -func (self *world) Coinbase() *ethstate.StateObject { +func (self *World) Coinbase() *ethstate.StateObject { return nil } -func (self *world) IsMining() bool { +func (self *World) IsMining() bool { return self.pipe.obj.IsMining() } -func (self *world) IsListening() bool { +func (self *World) IsListening() bool { return self.pipe.obj.IsListening() } -func (self *world) Peers() *list.List { +func (self *World) Peers() *list.List { return self.pipe.obj.Peers() } -func (self *world) Config() *config { +func (self *World) Config() *config { return self.cfg } From 4edf7cfb0543555921a79f572c749615c4997ea7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 Aug 2014 11:31:39 +0200 Subject: [PATCH 30/64] config => Config --- ethpipe/config.go | 6 +++--- ethpipe/world.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ethpipe/config.go b/ethpipe/config.go index 588fc8d97..5e57416d7 100644 --- a/ethpipe/config.go +++ b/ethpipe/config.go @@ -4,11 +4,11 @@ import "github.com/ethereum/eth-go/ethutil" var cnfCtr = ethutil.Hex2Bytes("661005d2720d855f1d9976f88bb10c1a3398c77f") -type config struct { +type Config struct { pipe *Pipe } -func (self *config) Get(name string) *Object { +func (self *Config) Get(name string) *Object { configCtrl := self.pipe.World().safeGet(cnfCtr) var addr []byte @@ -24,6 +24,6 @@ func (self *config) Get(name string) *Object { return &Object{self.pipe.World().safeGet(objectAddr.Bytes())} } -func (self *config) Exist() bool { +func (self *Config) Exist() bool { return self.pipe.World().Get(cnfCtr) != nil } diff --git a/ethpipe/world.go b/ethpipe/world.go index 2c6b0b4b9..72e116d09 100644 --- a/ethpipe/world.go +++ b/ethpipe/world.go @@ -8,12 +8,12 @@ import ( type World struct { pipe *Pipe - cfg *config + cfg *Config } func NewWorld(pipe *Pipe) *World { world := &World{pipe, nil} - world.cfg = &config{pipe} + world.cfg = &Config{pipe} return world } @@ -55,6 +55,6 @@ func (self *World) Peers() *list.List { return self.pipe.obj.Peers() } -func (self *World) Config() *config { +func (self *World) Config() *Config { return self.cfg } From da50c751480da32036f41ccbeb1f292694ca0286 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 6 Aug 2014 09:53:00 +0200 Subject: [PATCH 31/64] Added state dump method --- ethchain/block_chain.go | 16 ++++++++++---- ethcrypto/mnemonic.go | 3 --- ethpub/pub.go | 23 ++++++++++---------- ethstate/dump.go | 47 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 ethstate/dump.go diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 736fe52c7..3eba90fca 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -290,7 +290,6 @@ func (bc *BlockChain) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { block := NewBlockFromBytes(data) - //info := bc.BlockInfo(block) bc.CurrentBlock = block bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() @@ -301,9 +300,6 @@ func (bc *BlockChain) setLastBlock() { bc.genesisBlock.state.Trie.Sync() // Prepare the genesis block bc.Add(bc.genesisBlock) - - //chainlogger.Infof("root %x\n", bm.bc.genesisBlock.State().Root) - //bm.bc.genesisBlock.PrintHash() } // Set the last know difficulty (might be 0x0 as initial value, Genesis) @@ -339,6 +335,18 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block { return NewBlockFromBytes(data) } +func (self *BlockChain) GetBlockByNumber(num uint64) *Block { + block := self.CurrentBlock + for ; block.Number.Uint64() != num; block = self.GetBlock(block.PrevHash) { + } + + if block.Number.Uint64() == 0 && num != 0 { + return nil + } + + return block +} + func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { bi := BlockInfo{} data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) diff --git a/ethcrypto/mnemonic.go b/ethcrypto/mnemonic.go index b8df2ad6f..2d3ac85a3 100644 --- a/ethcrypto/mnemonic.go +++ b/ethcrypto/mnemonic.go @@ -13,12 +13,9 @@ import ( func InitWords(wordsPath string) { filename := path.Join(wordsPath, "mnemonic.words.lst") if _, err := os.Stat(filename); os.IsNotExist(err) { - fmt.Printf("reading mnemonic word list file from supplied path not found. Looked in %s. Trying next option.\n", filename) - dir := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "eth-go", "ethcrypto") filename = path.Join(dir, "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: %s.\n", filename) dir, err := filepath.Abs(filepath.Dir(os.Args[0])) if err != nil { panic(fmt.Errorf("problem getting current folder: ", err)) diff --git a/ethpub/pub.go b/ethpub/pub.go index 7cc7cf6ce..f971313d8 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -3,14 +3,15 @@ package ethpub import ( "bytes" "encoding/json" + "math/big" + "strings" + "sync/atomic" + "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" - "math/big" - "strings" - "sync/atomic" ) var logger = ethlog.NewLogger("PUB") @@ -165,14 +166,6 @@ func (lib *PEthereum) SecretToAddress(key string) string { return ethutil.Bytes2Hex(pair.Address()) } -func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) { - return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr) -} - -func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, script string) (*PReceipt, error) { - return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, script) -} - func FindAddressInNameReg(stateManager *ethchain.StateManager, name string) []byte { nameReg := EthereumConfig(stateManager).NameReg() if nameReg != nil { @@ -199,6 +192,14 @@ func FindNameInNameReg(stateManager *ethchain.StateManager, addr []byte) string return "" } +func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) { + return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr) +} + +func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, script string) (*PReceipt, error) { + return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, script) +} + func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { var hash []byte var contractCreation bool diff --git a/ethstate/dump.go b/ethstate/dump.go new file mode 100644 index 000000000..2406dfc49 --- /dev/null +++ b/ethstate/dump.go @@ -0,0 +1,47 @@ +package ethstate + +import ( + "encoding/json" + "fmt" + + "github.com/ethereum/eth-go/ethutil" +) + +type Account struct { + Balance string `json:"balance"` + Nonce uint64 `json:"nonce"` + CodeHash string `json:"codeHash"` + Storage map[string]string `json:"storage"` +} + +type World struct { + Root string `json:"root"` + Accounts map[string]Account `json:"accounts"` +} + +func (self *State) Dump() string { + world := World{ + Root: ethutil.Bytes2Hex(self.Trie.Root.([]byte)), + Accounts: make(map[string]Account), + } + + self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) { + stateObject := NewStateObjectFromBytes([]byte(key), value.Bytes()) + + account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.CodeHash)} + account.Storage = make(map[string]string) + + stateObject.EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + account.Storage[ethutil.Bytes2Hex([]byte(key))] = ethutil.Bytes2Hex(value.Bytes()) + }) + world.Accounts[ethutil.Bytes2Hex([]byte(key))] = account + }) + + json, err := json.MarshalIndent(world, "", " ") + if err != nil { + fmt.Println("dump err", err) + } + + return string(json) +} From 7272577fe651a20618cf428475e2e57976c9599d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 7 Aug 2014 15:11:54 +0200 Subject: [PATCH 32/64] Added dns lookup --- ethpipe/config.go | 5 +++++ ethpub/pub.go | 13 +++++++++++++ peer.go | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ethpipe/config.go b/ethpipe/config.go index 5e57416d7..66708b26e 100644 --- a/ethpipe/config.go +++ b/ethpipe/config.go @@ -15,6 +15,11 @@ func (self *Config) Get(name string) *Object { switch name { case "NameReg": addr = []byte{0} + case "DomainReg": + objectAddr := configCtrl.GetStorage(ethutil.BigD([]byte{0})) + domainAddr := (&Object{self.pipe.World().safeGet(objectAddr.Bytes())}).StorageString("DomainReg").Bytes() + + return &Object{self.pipe.World().safeGet(domainAddr)} default: addr = ethutil.RightPadBytes([]byte(name), 32) } diff --git a/ethpub/pub.go b/ethpub/pub.go index f971313d8..3fb4c4920 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" ) @@ -41,6 +42,7 @@ func (self helper) NameReg() *ethstate.StateObject { return nil } +// TODO Re-write / refactor type PEthereum struct { manager ethchain.EthManager stateManager *ethchain.StateManager @@ -65,6 +67,17 @@ func New(manager ethchain.EthManager) *PEthereum { } } +func (self *PEthereum) LookupDomain(domain string) string { + pipe := ethpipe.New(self.manager) + world := pipe.World() + + if len(domain) > 32 { + domain = string(ethcrypto.Sha3Bin([]byte(domain))) + } + + return strings.Trim(world.Config().Get("DomainReg").StorageString(domain).Str(), "\x00") +} + func (lib *PEthereum) GetBlock(hexHash string) *PBlock { hash := ethutil.Hex2Bytes(hexHash) block := lib.blockChain.GetBlock(hash) diff --git a/peer.go b/peer.go index fa683e488..bd20bb2b9 100644 --- a/peer.go +++ b/peer.go @@ -449,7 +449,7 @@ func (p *Peer) HandleInbound() { peerlogger.Infof("Attempting to catch (%x). Parent unknown\n", b.Hash()) p.catchingUp = false - p.CatchupWithPeer(b.Hash()) + p.CatchupWithPeer(b.PrevHash) peerlogger.Infoln(b) From d6b0ab3028ba8d7a565d35ab7b8054ee921ba683 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 7 Aug 2014 15:26:07 +0200 Subject: [PATCH 33/64] Changed to DnsReg --- ethpipe/config.go | 4 ++-- ethpub/pub.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethpipe/config.go b/ethpipe/config.go index 66708b26e..1e246c7b4 100644 --- a/ethpipe/config.go +++ b/ethpipe/config.go @@ -15,9 +15,9 @@ func (self *Config) Get(name string) *Object { switch name { case "NameReg": addr = []byte{0} - case "DomainReg": + case "DnsReg": objectAddr := configCtrl.GetStorage(ethutil.BigD([]byte{0})) - domainAddr := (&Object{self.pipe.World().safeGet(objectAddr.Bytes())}).StorageString("DomainReg").Bytes() + domainAddr := (&Object{self.pipe.World().safeGet(objectAddr.Bytes())}).StorageString("DnsReg").Bytes() return &Object{self.pipe.World().safeGet(domainAddr)} default: diff --git a/ethpub/pub.go b/ethpub/pub.go index 3fb4c4920..ab2aae599 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -75,7 +75,7 @@ func (self *PEthereum) LookupDomain(domain string) string { domain = string(ethcrypto.Sha3Bin([]byte(domain))) } - return strings.Trim(world.Config().Get("DomainReg").StorageString(domain).Str(), "\x00") + return strings.Trim(world.Config().Get("DnsReg").StorageString(domain).Str(), "\x00") } func (lib *PEthereum) GetBlock(hexHash string) *PBlock { From 3fc24013ef200f20eaa9deed6647270924126976 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 8 Aug 2014 12:04:18 +0100 Subject: [PATCH 34/64] Fixed issue with overflowing 256 bit integers --- ethvm/vm.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/ethvm/vm.go b/ethvm/vm.go index e469fa826..995fd897b 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -245,6 +245,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { base.Add(y, x) + ensure256(base) + self.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) @@ -255,6 +257,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { base.Sub(y, x) + ensure256(base) + self.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) @@ -265,6 +269,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { base.Mul(y, x) + ensure256(base) + self.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) @@ -277,6 +283,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { base.Div(y, x) } + ensure256(base) + self.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) @@ -289,6 +297,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { base.Div(y, x) } + ensure256(base) + self.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) @@ -300,6 +310,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { base.Mod(y, x) + ensure256(base) + self.Printf(" = %v", base) stack.Push(base) case SMOD: @@ -310,6 +322,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { base.Mod(y, x) + ensure256(base) + self.Printf(" = %v", base) stack.Push(base) @@ -321,6 +335,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { base.Exp(y, x, Pow256) + ensure256(base) + self.Printf(" = %v", base) stack.Push(base) @@ -838,3 +854,18 @@ func (self *Vm) Endl() *Vm { return self } + +func ensure256(x *big.Int) { + maxInt, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 0) + if x.Cmp(maxInt) >= 0 { + x.SetInt64(0) + + return + } + + // Could have done this with an OR, but big ints are costly. + + if x.Cmp(new(big.Int)) < 0 { + x.SetInt64(0) + } +} From c51db4c940a5ea679aee580a673a4ccdd2421b9a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 8 Aug 2014 14:36:59 +0100 Subject: [PATCH 35/64] Fixed stack issue --- ethchain/state_manager.go | 7 ++++--- ethpipe/config.go | 1 - ethvm/stack.go | 2 +- ethvm/vm.go | 26 +++++++++++++------------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 226b2fe73..f06622fcb 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -4,15 +4,16 @@ import ( "bytes" "container/list" "fmt" + "math/big" + "sync" + "time" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "math/big" - "sync" - "time" ) var statelogger = ethlog.NewLogger("STATE") diff --git a/ethpipe/config.go b/ethpipe/config.go index 1e246c7b4..6c24df640 100644 --- a/ethpipe/config.go +++ b/ethpipe/config.go @@ -18,7 +18,6 @@ func (self *Config) Get(name string) *Object { case "DnsReg": objectAddr := configCtrl.GetStorage(ethutil.BigD([]byte{0})) domainAddr := (&Object{self.pipe.World().safeGet(objectAddr.Bytes())}).StorageString("DnsReg").Bytes() - return &Object{self.pipe.World().safeGet(domainAddr)} default: addr = ethutil.RightPadBytes([]byte(name), 32) diff --git a/ethvm/stack.go b/ethvm/stack.go index c06d63652..f4b0be393 100644 --- a/ethvm/stack.go +++ b/ethvm/stack.go @@ -59,7 +59,7 @@ func (st *Stack) Peek() *big.Int { } func (st *Stack) Peekn() (*big.Int, *big.Int) { - ints := st.data[:2] + ints := st.data[len(st.data)-2:] return ints[0], ints[1] } diff --git a/ethvm/vm.go b/ethvm/vm.go index 995fd897b..a3c273f62 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -129,14 +129,14 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) }) } - - 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()) */ + + 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) @@ -856,12 +856,12 @@ func (self *Vm) Endl() *Vm { } func ensure256(x *big.Int) { - maxInt, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007913129639935", 0) - if x.Cmp(maxInt) >= 0 { - x.SetInt64(0) - - return - } + //max, _ := big.NewInt(0).SetString("115792089237316195423570985008687907853269984665640564039457584007913129639936", 0) + //if x.Cmp(max) >= 0 { + d := big.NewInt(1) + d.Lsh(d, 256).Sub(d, big.NewInt(1)) + x.And(x, d) + //} // Could have done this with an OR, but big ints are costly. From 27290e12772f4a354cfdc6383222597f66cefa21 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 9 Aug 2014 18:06:16 +0100 Subject: [PATCH 36/64] Fixed gas limit calculation --- ethchain/block.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 321af6183..5b06fd58d 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -130,8 +130,10 @@ func (block *Block) CalcGasLimit(parent *Block) *big.Int { return ethutil.BigPow(10, 6) } - previous := new(big.Int).Mul(big.NewInt(1023), parent.GasLimit) - current := new(big.Rat).Mul(new(big.Rat).SetInt(block.GasUsed), big.NewRat(6, 5)) + // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 + + previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit) + current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed), big.NewRat(6, 5)) curInt := new(big.Int).Div(current.Num(), current.Denom()) result := new(big.Int).Add(previous, curInt) From 024be32f0667c17b9240dda23a90612d17278b23 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 9 Aug 2014 18:09:55 +0100 Subject: [PATCH 37/64] Make sure all left padded zero's aren't included --- ethchain/transaction.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 5686a7edb..e1b48a3d3 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -3,10 +3,11 @@ package ethchain import ( "bytes" "fmt" + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" - "math/big" ) var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -130,7 +131,7 @@ func (tx *Transaction) RlpData() interface{} { // TODO Remove prefixing zero's - return append(data, tx.v, tx.r, tx.s) + return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes()) } func (tx *Transaction) RlpValue() *ethutil.Value { From 42d2bc28affe9bbd8d57a5eb3deab804e5c4a206 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 9 Aug 2014 18:10:11 +0100 Subject: [PATCH 38/64] Upped protocol version --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index bd20bb2b9..4cbe8b652 100644 --- a/peer.go +++ b/peer.go @@ -22,7 +22,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 25 + ProtocolVersion = 26 // Interval for ping/pong message pingPongTimer = 2 * time.Second ) From 2e5d28c73f1d97865def3ffe8c7ad0a4819f15f3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 11 Aug 2014 16:23:17 +0200 Subject: [PATCH 39/64] Added bloom filter & block filter methods --- ethchain/bloom.go | 47 +++++++++++++ ethchain/bloom_test.go | 20 ++++++ ethchain/filter.go | 146 ++++++++++++++++++++++++++++++++++++++++ ethchain/filter_test.go | 7 ++ ethstate/manifest.go | 67 ++++++++++++++++++ 5 files changed, 287 insertions(+) create mode 100644 ethchain/bloom.go create mode 100644 ethchain/bloom_test.go create mode 100644 ethchain/filter.go create mode 100644 ethchain/filter_test.go create mode 100644 ethstate/manifest.go diff --git a/ethchain/bloom.go b/ethchain/bloom.go new file mode 100644 index 000000000..320ce73fc --- /dev/null +++ b/ethchain/bloom.go @@ -0,0 +1,47 @@ +package ethchain + +type BloomFilter struct { + bin []byte +} + +func NewBloomFilter(bin []byte) *BloomFilter { + if bin == nil { + bin = make([]byte, 255) + } + + return &BloomFilter{ + bin: bin, + } +} + +func (self *BloomFilter) Set(addr []byte) { + if len(addr) < 8 { + chainlogger.Warnf("err: bloom set to small: %x\n", addr) + + return + } + + for _, i := range addr[len(addr)-8:] { + self.bin[i] = 1 + } +} + +func (self *BloomFilter) Search(addr []byte) bool { + if len(addr) < 8 { + chainlogger.Warnf("err: bloom search to small: %x\n", addr) + + return false + } + + for _, i := range addr[len(addr)-8:] { + if self.bin[i] == 0 { + return false + } + } + + return true +} + +func (self *BloomFilter) Bin() []byte { + return self.bin +} diff --git a/ethchain/bloom_test.go b/ethchain/bloom_test.go new file mode 100644 index 000000000..ea53d539c --- /dev/null +++ b/ethchain/bloom_test.go @@ -0,0 +1,20 @@ +package ethchain + +import "testing" + +func TestBloomFilter(t *testing.T) { + bf := NewBloomFilter(nil) + + a := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} + bf.Set(a) + + b := []byte{10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + + if bf.Search(a) == false { + t.Error("Expected 'a' to yield true using a bloom filter") + } + + if bf.Search(b) { + t.Error("Expected 'b' not to field trie using a bloom filter") + } +} diff --git a/ethchain/filter.go b/ethchain/filter.go new file mode 100644 index 000000000..c3b0a7f94 --- /dev/null +++ b/ethchain/filter.go @@ -0,0 +1,146 @@ +package ethchain + +import ( + "bytes" + "fmt" + + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" +) + +// Filtering interface +type Filter struct { + eth EthManager + earliest []byte + latest []byte + skip int + from, to []byte + max int +} + +// Create a new filter which uses a bloom filter on blocks to figure out whether a particular block +// is interesting or not. +func NewFilter(eth EthManager) *Filter { + return &Filter{eth: eth} +} + +// Set the earliest and latest block for filtering. +// -1 = latest block (i.e., the current block) +// hash = particular hash from-to +func (self *Filter) SetEarliestBlock(earliest interface{}) { + e := ethutil.NewValue(earliest) + + // Check for -1 (latest) otherwise assume bytes + if e.Int() == -1 { + self.earliest = self.eth.BlockChain().CurrentBlock.Hash() + } else if e.Len() > 0 { + self.earliest = e.Bytes() + } else { + panic(fmt.Sprintf("earliest has to be either -1 or a valid hash: %v (%T)", e, e.Val)) + } +} + +func (self *Filter) SetLatestBlock(latest interface{}) { + l := ethutil.NewValue(latest) + + // Check for -1 (latest) otherwise assume bytes + if l.Int() == -1 { + self.latest = self.eth.BlockChain().CurrentBlock.Hash() + } else if l.Len() > 0 { + self.latest = l.Bytes() + } else { + panic(fmt.Sprintf("latest has to be either -1 or a valid hash: %v", l)) + } +} + +func (self *Filter) SetFrom(addr []byte) { + self.from = addr +} + +func (self *Filter) SetTo(addr []byte) { + self.to = addr +} + +func (self *Filter) SetMax(max int) { + self.max = max +} + +func (self *Filter) SetSkip(skip int) { + self.skip = skip +} + +// Run filters messages with the current parameters set +func (self *Filter) Find() []*ethstate.Message { + var messages []*ethstate.Message + + block := self.eth.BlockChain().GetBlock(self.latest) + + // skip N blocks (useful for pagination) + if self.skip > 0 { + for i := 0; i < i; i++ { + block = self.eth.BlockChain().GetBlock(block.PrevHash) + } + } + + // Start block filtering + quit := false + for i := 1; !quit && block != nil; i++ { + // Mark last check + if self.max == i || (len(self.earliest) > 0 && bytes.Compare(block.Hash(), self.earliest) == 0) { + quit = true + } + + // Use bloom filtering to see if this block is interesting given the + // current parameters + if self.bloomFilter(block) { + // Get the messages of the block + msgs, err := self.eth.StateManager().GetMessages(block) + if err != nil { + chainlogger.Warnln("err: filter get messages ", err) + + break + } + + // Filter the messages for interesting stuff + for _, message := range msgs { + if len(self.to) > 0 && bytes.Compare(message.To, self.to) != 0 { + continue + } + + if len(self.from) > 0 && bytes.Compare(message.From, self.from) != 0 { + continue + } + + messages = append(messages, message) + } + } + + block = self.eth.BlockChain().GetBlock(block.PrevHash) + } + + return messages +} + +func (self *Filter) bloomFilter(block *Block) bool { + fk := append([]byte("bloom"), block.Hash()...) + bin, err := self.eth.Db().Get(fk) + if err != nil { + panic(err) + } + + bloom := NewBloomFilter(bin) + + if len(self.from) > 0 { + if !bloom.Search(self.from) { + return false + } + } + + if len(self.to) > 0 { + if !bloom.Search(self.to) { + return false + } + } + + return true +} diff --git a/ethchain/filter_test.go b/ethchain/filter_test.go new file mode 100644 index 000000000..6dce51b3b --- /dev/null +++ b/ethchain/filter_test.go @@ -0,0 +1,7 @@ +package ethchain + +import "testing" + +func TestFilter(t *testing.T) { + filter := NewFilter() +} diff --git a/ethstate/manifest.go b/ethstate/manifest.go new file mode 100644 index 000000000..b771127a6 --- /dev/null +++ b/ethstate/manifest.go @@ -0,0 +1,67 @@ +package ethstate + +import ( + "fmt" + "math/big" +) + +// Object manifest +// +// The object manifest is used to keep changes to the state so we can keep track of the changes +// that occurred during a state transitioning phase. +type Manifest struct { + // XXX These will be handy in the future. Not important for now. + objectAddresses map[string]bool + storageAddresses map[string]map[string]bool + + ObjectChanges map[string]*StateObject + StorageChanges map[string]map[string]*big.Int + + Messages []*Message +} + +func NewManifest() *Manifest { + m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} + m.Reset() + + return m +} + +func (m *Manifest) Reset() { + m.ObjectChanges = make(map[string]*StateObject) + m.StorageChanges = make(map[string]map[string]*big.Int) +} + +func (m *Manifest) AddObjectChange(stateObject *StateObject) { + m.ObjectChanges[string(stateObject.Address())] = stateObject +} + +func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { + if m.StorageChanges[string(stateObject.Address())] == nil { + m.StorageChanges[string(stateObject.Address())] = make(map[string]*big.Int) + } + + m.StorageChanges[string(stateObject.Address())][string(storageAddr)] = storage +} + +func (self *Manifest) AddMessage(msg *Message) *Message { + self.Messages = append(self.Messages, msg) + + return msg +} + +type Message struct { + To, From []byte + Input []byte + Output []byte + Path int + Origin []byte + Timestamp int64 + Coinbase []byte + Block []byte + Number *big.Int +} + +func (self *Message) String() string { + return fmt.Sprintf("Message{to: %x from: %x input: %x output: %x origin: %x coinbase: %x block: %x number: %v timestamp: %d path: %d", self.To, self.From, self.Input, self.Output, self.Origin, self.Coinbase, self.Block, self.Number, self.Timestamp, self.Path) +} From a760ce05b948e89bc564af20599dcf95698ac0eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 11 Aug 2014 16:23:38 +0200 Subject: [PATCH 40/64] Updated chain for filtering --- ethchain/block.go | 13 ------- ethchain/block_chain.go | 2 ++ ethchain/block_chain_test.go | 23 ++++++++---- ethchain/state_manager.go | 70 ++++++++++++++++++++++++++++++++++-- ethchain/state_transition.go | 12 ++++++- ethchain/vm_env.go | 4 ++- ethereum.go | 5 ++- ethpipe/vm_env.go | 1 + ethstate/state.go | 45 +++-------------------- ethutil/rlp.go | 9 ++--- ethutil/value.go | 24 +++++++++++++ ethvm/closure.go | 3 +- ethvm/vm.go | 22 ++++++++++-- ethwire/messaging.go | 5 +-- 14 files changed, 164 insertions(+), 74 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 5b06fd58d..5765abd51 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -142,19 +142,6 @@ func (block *Block) CalcGasLimit(parent *Block) *big.Int { min := big.NewInt(125000) return ethutil.BigMax(min, result) - /* - base := new(big.Int) - base2 := new(big.Int) - parentGL := bc.CurrentBlock.GasLimit - parentUsed := bc.CurrentBlock.GasUsed - - base.Mul(parentGL, big.NewInt(1024-1)) - base2.Mul(parentUsed, big.NewInt(6)) - base2.Div(base2, big.NewInt(5)) - base.Add(base, base2) - base.Div(base, big.NewInt(1024)) - */ - } func (block *Block) BlockInfo() BlockInfo { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 3eba90fca..611735707 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -300,6 +300,8 @@ func (bc *BlockChain) setLastBlock() { bc.genesisBlock.state.Trie.Sync() // Prepare the genesis block bc.Add(bc.genesisBlock) + fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) + bc.Ethereum.Db().Put(fk, make([]byte, 255)) } // Set the last know difficulty (might be 0x0 as initial value, Genesis) diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index bbc96c823..1edcf9c7b 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -3,16 +3,19 @@ package ethchain import ( "container/list" "fmt" + "testing" + + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "testing" ) // Implement our EthTest Manager type TestManager struct { stateManager *StateManager - reactor *ethutil.ReactorEngine + reactor *ethreact.ReactorEngine txPool *TxPool blockChain *BlockChain @@ -47,16 +50,24 @@ func (tm *TestManager) StateManager() *StateManager { return tm.stateManager } -func (tm *TestManager) Reactor() *ethutil.ReactorEngine { +func (tm *TestManager) Reactor() *ethreact.ReactorEngine { return tm.reactor } func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { fmt.Println("Broadcast not implemented") } -func NewTestManager() *TestManager { +func (tm *TestManager) ClientIdentity() ethwire.ClientIdentity { + return nil +} +func (tm *TestManager) KeyManager() *ethcrypto.KeyManager { + return nil +} - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") +func (tm *TestManager) Db() ethutil.Database { return nil } + +func NewTestManager() *TestManager { + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH") db, err := ethdb.NewMemDatabase() if err != nil { @@ -66,7 +77,7 @@ func NewTestManager() *TestManager { ethutil.Config.Db = db testManager := &TestManager{} - testManager.reactor = ethutil.NewReactorEngine() + testManager.reactor = ethreact.New() testManager.txPool = NewTxPool(testManager) testManager.blockChain = NewBlockChain(testManager) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f06622fcb..a60b28b3f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -45,6 +45,7 @@ type EthManager interface { Peers() *list.List KeyManager() *ethcrypto.KeyManager ClientIdentity() ethwire.ClientIdentity + Db() ethutil.Database } type StateManager struct { @@ -235,7 +236,12 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Add the block to the chain sm.bc.Add(block) - sm.notifyChanges(state) + + // Create a bloom bin for this block + filter := sm.createBloomFilter(state) + // Persist the data + fk := append([]byte("bloom"), block.Hash()...) + sm.Ethereum.Db().Put(fk, filter.Bin()) statelogger.Infof("Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { @@ -363,14 +369,74 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) notifyChanges(state *ethstate.State) { +// Manifest will handle both creating notifications and generating bloom bin data +func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { + bloomf := NewBloomFilter(nil) + for addr, stateObject := range state.Manifest().ObjectChanges { + // Set the bloom filter's bin + bloomf.Set([]byte(addr)) + sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { for addr, value := range mappedObjects { + // Set the bloom filter's bin + bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr))) + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } } + + return bloomf +} + +func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, err error) { + if !sm.bc.HasBlock(block.PrevHash) { + return nil, ParentError(block.PrevHash) + } + + sm.lastAttemptedBlock = block + + var ( + parent = sm.bc.GetBlock(block.PrevHash) + state = parent.State().Copy() + ) + + defer state.Reset() + + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { + fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) + } + + receipts, err := sm.ApplyDiff(state, parent, block) + if err != nil { + return nil, err + } + + txSha := CreateTxSha(receipts) + if bytes.Compare(txSha, block.TxSha) != 0 { + return nil, fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha) + } + + // Block validation + if err = sm.ValidateBlock(block); err != nil { + statelogger.Errorln("Error validating block:", err) + return nil, err + } + + // I'm not sure, but I don't know if there should be thrown + // any errors at this time. + if err = sm.AccumelateRewards(state, block); err != nil { + statelogger.Errorln("Error accumulating reward", err) + return nil, err + } + + if !block.State().Cmp(state) { + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) + return nil, err + } + + return state.Manifest().Messages, nil } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index dfcbfcc04..489ff2b6a 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -211,6 +211,13 @@ func (self *StateTransition) TransitionState() (err error) { snapshot = self.state.Copy() } + msg := self.state.Manifest().AddMessage(ðstate.Message{ + To: receiver.Address(), From: sender.Address(), + Input: self.tx.Data, + Origin: sender.Address(), + Block: self.block.Hash(), Timestamp: self.block.Time, Coinbase: self.block.Coinbase, Number: self.block.Number, + }) + // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { // Evaluate the initialization script @@ -226,14 +233,17 @@ func (self *StateTransition) TransitionState() (err error) { } receiver.Code = code + msg.Output = code } else { if len(receiver.Code) > 0 { - _, err = self.Eval(receiver.Code, receiver, "code") + ret, err := self.Eval(receiver.Code, receiver, "code") if err != nil { self.state.Set(snapshot) return fmt.Errorf("Error during code execution %v", err) } + + msg.Output = ret } } diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go index ddead77fd..30f9497fa 100644 --- a/ethchain/vm_env.go +++ b/ethchain/vm_env.go @@ -1,8 +1,9 @@ package ethchain import ( - "github.com/ethereum/eth-go/ethstate" "math/big" + + "github.com/ethereum/eth-go/ethstate" ) type VMEnv struct { @@ -25,5 +26,6 @@ func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } func (self *VMEnv) Time() int64 { return self.block.Time } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } +func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.tx.Value } func (self *VMEnv) State() *ethstate.State { return self.state } diff --git a/ethereum.go b/ethereum.go index 69bb93cff..c1c4c2f2f 100644 --- a/ethereum.go +++ b/ethereum.go @@ -44,8 +44,8 @@ type Ethereum struct { // Channel for shutting down the ethereum shutdownChan chan bool quit chan bool + // DB interface - //db *ethdb.LDBDatabase db ethutil.Database // State manager for processing new blocks and managing the over all states stateManager *ethchain.StateManager @@ -149,6 +149,9 @@ func (s *Ethereum) StateManager() *ethchain.StateManager { func (s *Ethereum) TxPool() *ethchain.TxPool { return s.txPool } +func (self *Ethereum) Db() ethutil.Database { + return self.db +} func (s *Ethereum) ServerCaps() Caps { return s.serverCaps diff --git a/ethpipe/vm_env.go b/ethpipe/vm_env.go index c06a2a763..822a9e5c7 100644 --- a/ethpipe/vm_env.go +++ b/ethpipe/vm_env.go @@ -29,5 +29,6 @@ func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } func (self *VMEnv) Time() int64 { return self.block.Time } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } +func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) State() *ethstate.State { return self.state } diff --git a/ethstate/state.go b/ethstate/state.go index 10bcf6335..19210916e 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -211,50 +211,13 @@ func (self *State) Update() { } } +func (self *State) Manifest() *Manifest { + return self.manifest +} + // Debug stuff func (self *State) CreateOutputForDiff() { for _, stateObject := range self.stateObjects { stateObject.CreateOutputForDiff() } } - -func (self *State) Manifest() *Manifest { - return self.manifest -} - -// Object manifest -// -// The object manifest is used to keep changes to the state so we can keep track of the changes -// that occurred during a state transitioning phase. -type Manifest struct { - // XXX These will be handy in the future. Not important for now. - objectAddresses map[string]bool - storageAddresses map[string]map[string]bool - - ObjectChanges map[string]*StateObject - StorageChanges map[string]map[string]*big.Int -} - -func NewManifest() *Manifest { - m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} - m.Reset() - - return m -} - -func (m *Manifest) Reset() { - m.ObjectChanges = make(map[string]*StateObject) - m.StorageChanges = make(map[string]map[string]*big.Int) -} - -func (m *Manifest) AddObjectChange(stateObject *StateObject) { - m.ObjectChanges[string(stateObject.Address())] = stateObject -} - -func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { - if m.StorageChanges[string(stateObject.Address())] == nil { - m.StorageChanges[string(stateObject.Address())] = make(map[string]*big.Int) - } - - m.StorageChanges[string(stateObject.Address())][string(storageAddr)] = storage -} diff --git a/ethutil/rlp.go b/ethutil/rlp.go index cf7f97ffd..17ff627eb 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -2,15 +2,16 @@ package ethutil import ( "bytes" - _ "encoding/binary" "fmt" - _ "log" - _ "math" "math/big" ) -type RlpEncodable interface { +type RlpEncode interface { RlpEncode() []byte +} + +type RlpEncodeDecode interface { + RlpEncode RlpValue() []interface{} } diff --git a/ethutil/value.go b/ethutil/value.go index 2233b978c..608d332ba 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -74,6 +74,30 @@ func (val *Value) Uint() uint64 { return 0 } +func (val *Value) Int() int64 { + if Val, ok := val.Val.(int8); ok { + return int64(Val) + } else if Val, ok := val.Val.(int16); ok { + return int64(Val) + } else if Val, ok := val.Val.(int32); ok { + return int64(Val) + } else if Val, ok := val.Val.(int64); ok { + return Val + } else if Val, ok := val.Val.(int); ok { + return int64(Val) + } else if Val, ok := val.Val.(float32); ok { + return int64(Val) + } else if Val, ok := val.Val.(float64); ok { + return int64(Val) + } else if Val, ok := val.Val.([]byte); ok { + return new(big.Int).SetBytes(Val).Int64() + } else if Val, ok := val.Val.(*big.Int); ok { + return Val.Int64() + } + + return 0 +} + func (val *Value) Byte() byte { if Val, ok := val.Val.(byte); ok { return Val diff --git a/ethvm/closure.go b/ethvm/closure.go index 505fd43fb..f9be952d4 100644 --- a/ethvm/closure.go +++ b/ethvm/closure.go @@ -3,9 +3,10 @@ package ethvm // TODO Re write VM to use values instead of big integers? import ( + "math/big" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" - "math/big" ) type ClosureRef interface { diff --git a/ethvm/vm.go b/ethvm/vm.go index a3c273f62..a0d4db591 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -52,6 +52,7 @@ type Environment interface { Time() int64 Difficulty() *big.Int Value() *big.Int + BlockHash() []byte } type Object interface { @@ -696,6 +697,12 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" (*) %x", addr).Endl() + msg := self.env.State().Manifest().AddMessage(ðstate.Message{ + To: addr, From: closure.Address(), + Origin: self.env.Origin(), + Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + }) + // Create a new contract contract := self.env.State().NewStateObject(addr) if contract.Balance.Cmp(value) >= 0 { @@ -704,7 +711,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Set the init script initCode := mem.Get(offset.Int64(), size.Int64()) - //fmt.Printf("%x\n", initCode) + msg.Input = initCode + // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) @@ -728,7 +736,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf("CREATE err %v", err) } else { stack.Push(ethutil.BigD(addr)) - self.Printf("CREATE success") + + msg.Output = contract.Code } self.Endl() @@ -752,6 +761,13 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) + msg := self.env.State().Manifest().AddMessage(ðstate.Message{ + To: addr.Bytes(), From: closure.Address(), + Input: args, + Origin: self.env.Origin(), + Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + }) + if closure.object.Balance.Cmp(value) < 0 { vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance) @@ -782,6 +798,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { mem.Set(retOffset.Int64(), retSize.Int64(), ret) } + msg.Output = ret + // Debug hook if self.Dbg != nil { self.Dbg.SetCode(closure.Code) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index f13b72353..d114a1c9d 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -6,9 +6,10 @@ import ( "bytes" "errors" "fmt" - "github.com/ethereum/eth-go/ethutil" "net" "time" + + "github.com/ethereum/eth-go/ethutil" ) // Connection interface describing the methods required to implement the wire protocol. @@ -109,7 +110,7 @@ func (self *Connection) Write(typ MsgType, v ...interface{}) error { slice := [][]interface{}{[]interface{}{byte(typ)}} for _, value := range v { - if encodable, ok := value.(ethutil.RlpEncodable); ok { + if encodable, ok := value.(ethutil.RlpEncodeDecode); ok { slice = append(slice, encodable.RlpValue()) } else if raw, ok := value.([]interface{}); ok { slice = append(slice, raw) From e85f3972b9b4648666c6b50fff04938e3206ff96 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 12 Aug 2014 14:56:10 +0200 Subject: [PATCH 41/64] inline mnemonic wordlist to support binary builds without extra asset --- ethcrypto/mnemonic.go | 40 +- ethcrypto/mnemonic.words.lst | 1626 --------------------------------- ethcrypto/mnemonic_words.go | 1630 ++++++++++++++++++++++++++++++++++ 3 files changed, 1636 insertions(+), 1660 deletions(-) delete mode 100644 ethcrypto/mnemonic.words.lst create mode 100644 ethcrypto/mnemonic_words.go diff --git a/ethcrypto/mnemonic.go b/ethcrypto/mnemonic.go index 2d3ac85a3..5fb620219 100644 --- a/ethcrypto/mnemonic.go +++ b/ethcrypto/mnemonic.go @@ -2,37 +2,9 @@ package ethcrypto import ( "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" "strconv" - "strings" ) -func InitWords(wordsPath string) { - filename := path.Join(wordsPath, "mnemonic.words.lst") - if _, err := os.Stat(filename); os.IsNotExist(err) { - dir := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "eth-go", "ethcrypto") - filename = path.Join(dir, "mnemonic.words.lst") - if _, err := os.Stat(filename); os.IsNotExist(err) { - 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("All options for finding the mnemonic word list file 'mnemonic.words.lst' failed: ", err)) - } - words = strings.Split(string(content), "\n") -} - -var words []string - // TODO: See if we can refactor this into a shared util lib if we need it multiple times func IndexOf(slice []string, value string) int64 { for p, v := range slice { @@ -45,7 +17,7 @@ func IndexOf(slice []string, value string) int64 { func MnemonicEncode(message string) []string { var out []string - n := int64(len(words)) + n := int64(len(MnemonicWords)) for i := 0; i < len(message); i += (len(message) / 8) { x := message[i : i+8] @@ -53,22 +25,22 @@ func MnemonicEncode(message string) []string { w1 := (bit % n) w2 := ((bit / n) + w1) % n w3 := ((bit / n / n) + w2) % n - out = append(out, words[w1], words[w2], words[w3]) + out = append(out, MnemonicWords[w1], MnemonicWords[w2], MnemonicWords[w3]) } return out } func MnemonicDecode(wordsar []string) string { var out string - n := int64(len(words)) + n := int64(len(MnemonicWords)) for i := 0; i < len(wordsar); i += 3 { word1 := wordsar[i] word2 := wordsar[i+1] word3 := wordsar[i+2] - w1 := IndexOf(words, word1) - w2 := IndexOf(words, word2) - w3 := IndexOf(words, word3) + w1 := IndexOf(MnemonicWords, word1) + w2 := IndexOf(MnemonicWords, word2) + w3 := IndexOf(MnemonicWords, word3) y := (w2 - w1) % n z := (w3 - w2) % n diff --git a/ethcrypto/mnemonic.words.lst b/ethcrypto/mnemonic.words.lst deleted file mode 100644 index 6bf412ce1..000000000 --- a/ethcrypto/mnemonic.words.lst +++ /dev/null @@ -1,1626 +0,0 @@ -like -just -love -know -never -want -time -out -there -make -look -eye -down -only -think -heart -back -then -into -about -more -away -still -them -take -thing -even -through -long -always -world -too -friend -tell -try -hand -thought -over -here -other -need -smile -again -much -cry -been -night -ever -little -said -end -some -those -around -mind -people -girl -leave -dream -left -turn -myself -give -nothing -really -off -before -something -find -walk -wish -good -once -place -ask -stop -keep -watch -seem -everything -wait -got -yet -made -remember -start -alone -run -hope -maybe -believe -body -hate -after -close -talk -stand -own -each -hurt -help -home -god -soul -new -many -two -inside -should -true -first -fear -mean -better -play -another -gone -change -use -wonder -someone -hair -cold -open -best -any -behind -happen -water -dark -laugh -stay -forever -name -work -show -sky -break -came -deep -door -put -black -together -upon -happy -such -great -white -matter -fill -past -please -burn -cause -enough -touch -moment -soon -voice -scream -anything -stare -sound -red -everyone -hide -kiss -truth -death -beautiful -mine -blood -broken -very -pass -next -forget -tree -wrong -air -mother -understand -lip -hit -wall -memory -sleep -free -high -realize -school -might -skin -sweet -perfect -blue -kill -breath -dance -against -fly -between -grow -strong -under -listen -bring -sometimes -speak -pull -person -become -family -begin -ground -real -small -father -sure -feet -rest -young -finally -land -across -today -different -guy -line -fire -reason -reach -second -slowly -write -eat -smell -mouth -step -learn -three -floor -promise -breathe -darkness -push -earth -guess -save -song -above -along -both -color -house -almost -sorry -anymore -brother -okay -dear -game -fade -already -apart -warm -beauty -heard -notice -question -shine -began -piece -whole -shadow -secret -street -within -finger -point -morning -whisper -child -moon -green -story -glass -kid -silence -since -soft -yourself -empty -shall -angel -answer -baby -bright -dad -path -worry -hour -drop -follow -power -war -half -flow -heaven -act -chance -fact -least -tired -children -near -quite -afraid -rise -sea -taste -window -cover -nice -trust -lot -sad -cool -force -peace -return -blind -easy -ready -roll -rose -drive -held -music -beneath -hang -mom -paint -emotion -quiet -clear -cloud -few -pretty -bird -outside -paper -picture -front -rock -simple -anyone -meant -reality -road -sense -waste -bit -leaf -thank -happiness -meet -men -smoke -truly -decide -self -age -book -form -alive -carry -escape -damn -instead -able -ice -minute -throw -catch -leg -ring -course -goodbye -lead -poem -sick -corner -desire -known -problem -remind -shoulder -suppose -toward -wave -drink -jump -woman -pretend -sister -week -human -joy -crack -grey -pray -surprise -dry -knee -less -search -bleed -caught -clean -embrace -future -king -son -sorrow -chest -hug -remain -sat -worth -blow -daddy -final -parent -tight -also -create -lonely -safe -cross -dress -evil -silent -bone -fate -perhaps -anger -class -scar -snow -tiny -tonight -continue -control -dog -edge -mirror -month -suddenly -comfort -given -loud -quickly -gaze -plan -rush -stone -town -battle -ignore -spirit -stood -stupid -yours -brown -build -dust -hey -kept -pay -phone -twist -although -ball -beyond -hidden -nose -taken -fail -float -pure -somehow -wash -wrap -angry -cheek -creature -forgotten -heat -rip -single -space -special -weak -whatever -yell -anyway -blame -job -choose -country -curse -drift -echo -figure -grew -laughter -neck -suffer -worse -yeah -disappear -foot -forward -knife -mess -somewhere -stomach -storm -beg -idea -lift -offer -breeze -field -five -often -simply -stuck -win -allow -confuse -enjoy -except -flower -seek -strength -calm -grin -gun -heavy -hill -large -ocean -shoe -sigh -straight -summer -tongue -accept -crazy -everyday -exist -grass -mistake -sent -shut -surround -table -ache -brain -destroy -heal -nature -shout -sign -stain -choice -doubt -glance -glow -mountain -queen -stranger -throat -tomorrow -city -either -fish -flame -rather -shape -spin -spread -ash -distance -finish -image -imagine -important -nobody -shatter -warmth -became -feed -flesh -funny -lust -shirt -trouble -yellow -attention -bare -bite -money -protect -amaze -appear -born -choke -completely -daughter -fresh -friendship -gentle -probably -six -deserve -expect -grab -middle -nightmare -river -thousand -weight -worst -wound -barely -bottle -cream -regret -relationship -stick -test -crush -endless -fault -itself -rule -spill -art -circle -join -kick -mask -master -passion -quick -raise -smooth -unless -wander -actually -broke -chair -deal -favorite -gift -note -number -sweat -box -chill -clothes -lady -mark -park -poor -sadness -tie -animal -belong -brush -consume -dawn -forest -innocent -pen -pride -stream -thick -clay -complete -count -draw -faith -press -silver -struggle -surface -taught -teach -wet -bless -chase -climb -enter -letter -melt -metal -movie -stretch -swing -vision -wife -beside -crash -forgot -guide -haunt -joke -knock -plant -pour -prove -reveal -steal -stuff -trip -wood -wrist -bother -bottom -crawl -crowd -fix -forgive -frown -grace -loose -lucky -party -release -surely -survive -teacher -gently -grip -speed -suicide -travel -treat -vein -written -cage -chain -conversation -date -enemy -however -interest -million -page -pink -proud -sway -themselves -winter -church -cruel -cup -demon -experience -freedom -pair -pop -purpose -respect -shoot -softly -state -strange -bar -birth -curl -dirt -excuse -lord -lovely -monster -order -pack -pants -pool -scene -seven -shame -slide -ugly -among -blade -blonde -closet -creek -deny -drug -eternity -gain -grade -handle -key -linger -pale -prepare -swallow -swim -tremble -wheel -won -cast -cigarette -claim -college -direction -dirty -gather -ghost -hundred -loss -lung -orange -present -swear -swirl -twice -wild -bitter -blanket -doctor -everywhere -flash -grown -knowledge -numb -pressure -radio -repeat -ruin -spend -unknown -buy -clock -devil -early -false -fantasy -pound -precious -refuse -sheet -teeth -welcome -add -ahead -block -bury -caress -content -depth -despite -distant -marry -purple -threw -whenever -bomb -dull -easily -grasp -hospital -innocence -normal -receive -reply -rhyme -shade -someday -sword -toe -visit -asleep -bought -center -consider -flat -hero -history -ink -insane -muscle -mystery -pocket -reflection -shove -silently -smart -soldier -spot -stress -train -type -view -whether -bus -energy -explain -holy -hunger -inch -magic -mix -noise -nowhere -prayer -presence -shock -snap -spider -study -thunder -trail -admit -agree -bag -bang -bound -butterfly -cute -exactly -explode -familiar -fold -further -pierce -reflect -scent -selfish -sharp -sink -spring -stumble -universe -weep -women -wonderful -action -ancient -attempt -avoid -birthday -branch -chocolate -core -depress -drunk -especially -focus -fruit -honest -match -palm -perfectly -pillow -pity -poison -roar -shift -slightly -thump -truck -tune -twenty -unable -wipe -wrote -coat -constant -dinner -drove -egg -eternal -flight -flood -frame -freak -gasp -glad -hollow -motion -peer -plastic -root -screen -season -sting -strike -team -unlike -victim -volume -warn -weird -attack -await -awake -built -charm -crave -despair -fought -grant -grief -horse -limit -message -ripple -sanity -scatter -serve -split -string -trick -annoy -blur -boat -brave -clearly -cling -connect -fist -forth -imagination -iron -jock -judge -lesson -milk -misery -nail -naked -ourselves -poet -possible -princess -sail -size -snake -society -stroke -torture -toss -trace -wise -bloom -bullet -cell -check -cost -darling -during -footstep -fragile -hallway -hardly -horizon -invisible -journey -midnight -mud -nod -pause -relax -shiver -sudden -value -youth -abuse -admire -blink -breast -bruise -constantly -couple -creep -curve -difference -dumb -emptiness -gotta -honor -plain -planet -recall -rub -ship -slam -soar -somebody -tightly -weather -adore -approach -bond -bread -burst -candle -coffee -cousin -crime -desert -flutter -frozen -grand -heel -hello -language -level -movement -pleasure -powerful -random -rhythm -settle -silly -slap -sort -spoken -steel -threaten -tumble -upset -aside -awkward -bee -blank -board -button -card -carefully -complain -crap -deeply -discover -drag -dread -effort -entire -fairy -giant -gotten -greet -illusion -jeans -leap -liquid -march -mend -nervous -nine -replace -rope -spine -stole -terror -accident -apple -balance -boom -childhood -collect -demand -depression -eventually -faint -glare -goal -group -honey -kitchen -laid -limb -machine -mere -mold -murder -nerve -painful -poetry -prince -rabbit -shelter -shore -shower -soothe -stair -steady -sunlight -tangle -tease -treasure -uncle -begun -bliss -canvas -cheer -claw -clutch -commit -crimson -crystal -delight -doll -existence -express -fog -football -gay -goose -guard -hatred -illuminate -mass -math -mourn -rich -rough -skip -stir -student -style -support -thorn -tough -yard -yearn -yesterday -advice -appreciate -autumn -bank -beam -bowl -capture -carve -collapse -confusion -creation -dove -feather -girlfriend -glory -government -harsh -hop -inner -loser -moonlight -neighbor -neither -peach -pig -praise -screw -shield -shimmer -sneak -stab -subject -throughout -thrown -tower -twirl -wow -army -arrive -bathroom -bump -cease -cookie -couch -courage -dim -guilt -howl -hum -husband -insult -led -lunch -mock -mostly -natural -nearly -needle -nerd -peaceful -perfection -pile -price -remove -roam -sanctuary -serious -shiny -shook -sob -stolen -tap -vain -void -warrior -wrinkle -affection -apologize -blossom -bounce -bridge -cheap -crumble -decision -descend -desperately -dig -dot -flip -frighten -heartbeat -huge -lazy -lick -odd -opinion -process -puzzle -quietly -retreat -score -sentence -separate -situation -skill -soak -square -stray -taint -task -tide -underneath -veil -whistle -anywhere -bedroom -bid -bloody -burden -careful -compare -concern -curtain -decay -defeat -describe -double -dreamer -driver -dwell -evening -flare -flicker -grandma -guitar -harm -horrible -hungry -indeed -lace -melody -monkey -nation -object -obviously -rainbow -salt -scratch -shown -shy -stage -stun -third -tickle -useless -weakness -worship -worthless -afternoon -beard -boyfriend -bubble -busy -certain -chin -concrete -desk -diamond -doom -drawn -due -felicity -freeze -frost -garden -glide -harmony -hopefully -hunt -jealous -lightning -mama -mercy -peel -physical -position -pulse -punch -quit -rant -respond -salty -sane -satisfy -savior -sheep -slept -social -sport -tuck -utter -valley -wolf -aim -alas -alter -arrow -awaken -beaten -belief -brand -ceiling -cheese -clue -confidence -connection -daily -disguise -eager -erase -essence -everytime -expression -fan -flag -flirt -foul -fur -giggle -glorious -ignorance -law -lifeless -measure -mighty -muse -north -opposite -paradise -patience -patient -pencil -petal -plate -ponder -possibly -practice -slice -spell -stock -strife -strip -suffocate -suit -tender -tool -trade -velvet -verse -waist -witch -aunt -bench -bold -cap -certainly -click -companion -creator -dart -delicate -determine -dish -dragon -drama -drum -dude -everybody -feast -forehead -former -fright -fully -gas -hook -hurl -invite -juice -manage -moral -possess -raw -rebel -royal -scale -scary -several -slight -stubborn -swell -talent -tea -terrible -thread -torment -trickle -usually -vast -violence -weave -acid -agony -ashamed -awe -belly -blend -blush -character -cheat -common -company -coward -creak -danger -deadly -defense -define -depend -desperate -destination -dew -duck -dusty -embarrass -engine -example -explore -foe -freely -frustrate -generation -glove -guilty -health -hurry -idiot -impossible -inhale -jaw -kingdom -mention -mist -moan -mumble -mutter -observe -ode -pathetic -pattern -pie -prefer -puff -rape -rare -revenge -rude -scrape -spiral -squeeze -strain -sunset -suspend -sympathy -thigh -throne -total -unseen -weapon -weary \ No newline at end of file diff --git a/ethcrypto/mnemonic_words.go b/ethcrypto/mnemonic_words.go new file mode 100644 index 000000000..72f0ad48f --- /dev/null +++ b/ethcrypto/mnemonic_words.go @@ -0,0 +1,1630 @@ +package ethcrypto + +var MnemonicWords []string = []string{ + "like", + "just", + "love", + "know", + "never", + "want", + "time", + "out", + "there", + "make", + "look", + "eye", + "down", + "only", + "think", + "heart", + "back", + "then", + "into", + "about", + "more", + "away", + "still", + "them", + "take", + "thing", + "even", + "through", + "long", + "always", + "world", + "too", + "friend", + "tell", + "try", + "hand", + "thought", + "over", + "here", + "other", + "need", + "smile", + "again", + "much", + "cry", + "been", + "night", + "ever", + "little", + "said", + "end", + "some", + "those", + "around", + "mind", + "people", + "girl", + "leave", + "dream", + "left", + "turn", + "myself", + "give", + "nothing", + "really", + "off", + "before", + "something", + "find", + "walk", + "wish", + "good", + "once", + "place", + "ask", + "stop", + "keep", + "watch", + "seem", + "everything", + "wait", + "got", + "yet", + "made", + "remember", + "start", + "alone", + "run", + "hope", + "maybe", + "believe", + "body", + "hate", + "after", + "close", + "talk", + "stand", + "own", + "each", + "hurt", + "help", + "home", + "god", + "soul", + "new", + "many", + "two", + "inside", + "should", + "true", + "first", + "fear", + "mean", + "better", + "play", + "another", + "gone", + "change", + "use", + "wonder", + "someone", + "hair", + "cold", + "open", + "best", + "any", + "behind", + "happen", + "water", + "dark", + "laugh", + "stay", + "forever", + "name", + "work", + "show", + "sky", + "break", + "came", + "deep", + "door", + "put", + "black", + "together", + "upon", + "happy", + "such", + "great", + "white", + "matter", + "fill", + "past", + "please", + "burn", + "cause", + "enough", + "touch", + "moment", + "soon", + "voice", + "scream", + "anything", + "stare", + "sound", + "red", + "everyone", + "hide", + "kiss", + "truth", + "death", + "beautiful", + "mine", + "blood", + "broken", + "very", + "pass", + "next", + "forget", + "tree", + "wrong", + "air", + "mother", + "understand", + "lip", + "hit", + "wall", + "memory", + "sleep", + "free", + "high", + "realize", + "school", + "might", + "skin", + "sweet", + "perfect", + "blue", + "kill", + "breath", + "dance", + "against", + "fly", + "between", + "grow", + "strong", + "under", + "listen", + "bring", + "sometimes", + "speak", + "pull", + "person", + "become", + "family", + "begin", + "ground", + "real", + "small", + "father", + "sure", + "feet", + "rest", + "young", + "finally", + "land", + "across", + "today", + "different", + "guy", + "line", + "fire", + "reason", + "reach", + "second", + "slowly", + "write", + "eat", + "smell", + "mouth", + "step", + "learn", + "three", + "floor", + "promise", + "breathe", + "darkness", + "push", + "earth", + "guess", + "save", + "song", + "above", + "along", + "both", + "color", + "house", + "almost", + "sorry", + "anymore", + "brother", + "okay", + "dear", + "game", + "fade", + "already", + "apart", + "warm", + "beauty", + "heard", + "notice", + "question", + "shine", + "began", + "piece", + "whole", + "shadow", + "secret", + "street", + "within", + "finger", + "point", + "morning", + "whisper", + "child", + "moon", + "green", + "story", + "glass", + "kid", + "silence", + "since", + "soft", + "yourself", + "empty", + "shall", + "angel", + "answer", + "baby", + "bright", + "dad", + "path", + "worry", + "hour", + "drop", + "follow", + "power", + "war", + "half", + "flow", + "heaven", + "act", + "chance", + "fact", + "least", + "tired", + "children", + "near", + "quite", + "afraid", + "rise", + "sea", + "taste", + "window", + "cover", + "nice", + "trust", + "lot", + "sad", + "cool", + "force", + "peace", + "return", + "blind", + "easy", + "ready", + "roll", + "rose", + "drive", + "held", + "music", + "beneath", + "hang", + "mom", + "paint", + "emotion", + "quiet", + "clear", + "cloud", + "few", + "pretty", + "bird", + "outside", + "paper", + "picture", + "front", + "rock", + "simple", + "anyone", + "meant", + "reality", + "road", + "sense", + "waste", + "bit", + "leaf", + "thank", + "happiness", + "meet", + "men", + "smoke", + "truly", + "decide", + "self", + "age", + "book", + "form", + "alive", + "carry", + "escape", + "damn", + "instead", + "able", + "ice", + "minute", + "throw", + "catch", + "leg", + "ring", + "course", + "goodbye", + "lead", + "poem", + "sick", + "corner", + "desire", + "known", + "problem", + "remind", + "shoulder", + "suppose", + "toward", + "wave", + "drink", + "jump", + "woman", + "pretend", + "sister", + "week", + "human", + "joy", + "crack", + "grey", + "pray", + "surprise", + "dry", + "knee", + "less", + "search", + "bleed", + "caught", + "clean", + "embrace", + "future", + "king", + "son", + "sorrow", + "chest", + "hug", + "remain", + "sat", + "worth", + "blow", + "daddy", + "final", + "parent", + "tight", + "also", + "create", + "lonely", + "safe", + "cross", + "dress", + "evil", + "silent", + "bone", + "fate", + "perhaps", + "anger", + "class", + "scar", + "snow", + "tiny", + "tonight", + "continue", + "control", + "dog", + "edge", + "mirror", + "month", + "suddenly", + "comfort", + "given", + "loud", + "quickly", + "gaze", + "plan", + "rush", + "stone", + "town", + "battle", + "ignore", + "spirit", + "stood", + "stupid", + "yours", + "brown", + "build", + "dust", + "hey", + "kept", + "pay", + "phone", + "twist", + "although", + "ball", + "beyond", + "hidden", + "nose", + "taken", + "fail", + "float", + "pure", + "somehow", + "wash", + "wrap", + "angry", + "cheek", + "creature", + "forgotten", + "heat", + "rip", + "single", + "space", + "special", + "weak", + "whatever", + "yell", + "anyway", + "blame", + "job", + "choose", + "country", + "curse", + "drift", + "echo", + "figure", + "grew", + "laughter", + "neck", + "suffer", + "worse", + "yeah", + "disappear", + "foot", + "forward", + "knife", + "mess", + "somewhere", + "stomach", + "storm", + "beg", + "idea", + "lift", + "offer", + "breeze", + "field", + "five", + "often", + "simply", + "stuck", + "win", + "allow", + "confuse", + "enjoy", + "except", + "flower", + "seek", + "strength", + "calm", + "grin", + "gun", + "heavy", + "hill", + "large", + "ocean", + "shoe", + "sigh", + "straight", + "summer", + "tongue", + "accept", + "crazy", + "everyday", + "exist", + "grass", + "mistake", + "sent", + "shut", + "surround", + "table", + "ache", + "brain", + "destroy", + "heal", + "nature", + "shout", + "sign", + "stain", + "choice", + "doubt", + "glance", + "glow", + "mountain", + "queen", + "stranger", + "throat", + "tomorrow", + "city", + "either", + "fish", + "flame", + "rather", + "shape", + "spin", + "spread", + "ash", + "distance", + "finish", + "image", + "imagine", + "important", + "nobody", + "shatter", + "warmth", + "became", + "feed", + "flesh", + "funny", + "lust", + "shirt", + "trouble", + "yellow", + "attention", + "bare", + "bite", + "money", + "protect", + "amaze", + "appear", + "born", + "choke", + "completely", + "daughter", + "fresh", + "friendship", + "gentle", + "probably", + "six", + "deserve", + "expect", + "grab", + "middle", + "nightmare", + "river", + "thousand", + "weight", + "worst", + "wound", + "barely", + "bottle", + "cream", + "regret", + "relationship", + "stick", + "test", + "crush", + "endless", + "fault", + "itself", + "rule", + "spill", + "art", + "circle", + "join", + "kick", + "mask", + "master", + "passion", + "quick", + "raise", + "smooth", + "unless", + "wander", + "actually", + "broke", + "chair", + "deal", + "favorite", + "gift", + "note", + "number", + "sweat", + "box", + "chill", + "clothes", + "lady", + "mark", + "park", + "poor", + "sadness", + "tie", + "animal", + "belong", + "brush", + "consume", + "dawn", + "forest", + "innocent", + "pen", + "pride", + "stream", + "thick", + "clay", + "complete", + "count", + "draw", + "faith", + "press", + "silver", + "struggle", + "surface", + "taught", + "teach", + "wet", + "bless", + "chase", + "climb", + "enter", + "letter", + "melt", + "metal", + "movie", + "stretch", + "swing", + "vision", + "wife", + "beside", + "crash", + "forgot", + "guide", + "haunt", + "joke", + "knock", + "plant", + "pour", + "prove", + "reveal", + "steal", + "stuff", + "trip", + "wood", + "wrist", + "bother", + "bottom", + "crawl", + "crowd", + "fix", + "forgive", + "frown", + "grace", + "loose", + "lucky", + "party", + "release", + "surely", + "survive", + "teacher", + "gently", + "grip", + "speed", + "suicide", + "travel", + "treat", + "vein", + "written", + "cage", + "chain", + "conversation", + "date", + "enemy", + "however", + "interest", + "million", + "page", + "pink", + "proud", + "sway", + "themselves", + "winter", + "church", + "cruel", + "cup", + "demon", + "experience", + "freedom", + "pair", + "pop", + "purpose", + "respect", + "shoot", + "softly", + "state", + "strange", + "bar", + "birth", + "curl", + "dirt", + "excuse", + "lord", + "lovely", + "monster", + "order", + "pack", + "pants", + "pool", + "scene", + "seven", + "shame", + "slide", + "ugly", + "among", + "blade", + "blonde", + "closet", + "creek", + "deny", + "drug", + "eternity", + "gain", + "grade", + "handle", + "key", + "linger", + "pale", + "prepare", + "swallow", + "swim", + "tremble", + "wheel", + "won", + "cast", + "cigarette", + "claim", + "college", + "direction", + "dirty", + "gather", + "ghost", + "hundred", + "loss", + "lung", + "orange", + "present", + "swear", + "swirl", + "twice", + "wild", + "bitter", + "blanket", + "doctor", + "everywhere", + "flash", + "grown", + "knowledge", + "numb", + "pressure", + "radio", + "repeat", + "ruin", + "spend", + "unknown", + "buy", + "clock", + "devil", + "early", + "false", + "fantasy", + "pound", + "precious", + "refuse", + "sheet", + "teeth", + "welcome", + "add", + "ahead", + "block", + "bury", + "caress", + "content", + "depth", + "despite", + "distant", + "marry", + "purple", + "threw", + "whenever", + "bomb", + "dull", + "easily", + "grasp", + "hospital", + "innocence", + "normal", + "receive", + "reply", + "rhyme", + "shade", + "someday", + "sword", + "toe", + "visit", + "asleep", + "bought", + "center", + "consider", + "flat", + "hero", + "history", + "ink", + "insane", + "muscle", + "mystery", + "pocket", + "reflection", + "shove", + "silently", + "smart", + "soldier", + "spot", + "stress", + "train", + "type", + "view", + "whether", + "bus", + "energy", + "explain", + "holy", + "hunger", + "inch", + "magic", + "mix", + "noise", + "nowhere", + "prayer", + "presence", + "shock", + "snap", + "spider", + "study", + "thunder", + "trail", + "admit", + "agree", + "bag", + "bang", + "bound", + "butterfly", + "cute", + "exactly", + "explode", + "familiar", + "fold", + "further", + "pierce", + "reflect", + "scent", + "selfish", + "sharp", + "sink", + "spring", + "stumble", + "universe", + "weep", + "women", + "wonderful", + "action", + "ancient", + "attempt", + "avoid", + "birthday", + "branch", + "chocolate", + "core", + "depress", + "drunk", + "especially", + "focus", + "fruit", + "honest", + "match", + "palm", + "perfectly", + "pillow", + "pity", + "poison", + "roar", + "shift", + "slightly", + "thump", + "truck", + "tune", + "twenty", + "unable", + "wipe", + "wrote", + "coat", + "constant", + "dinner", + "drove", + "egg", + "eternal", + "flight", + "flood", + "frame", + "freak", + "gasp", + "glad", + "hollow", + "motion", + "peer", + "plastic", + "root", + "screen", + "season", + "sting", + "strike", + "team", + "unlike", + "victim", + "volume", + "warn", + "weird", + "attack", + "await", + "awake", + "built", + "charm", + "crave", + "despair", + "fought", + "grant", + "grief", + "horse", + "limit", + "message", + "ripple", + "sanity", + "scatter", + "serve", + "split", + "string", + "trick", + "annoy", + "blur", + "boat", + "brave", + "clearly", + "cling", + "connect", + "fist", + "forth", + "imagination", + "iron", + "jock", + "judge", + "lesson", + "milk", + "misery", + "nail", + "naked", + "ourselves", + "poet", + "possible", + "princess", + "sail", + "size", + "snake", + "society", + "stroke", + "torture", + "toss", + "trace", + "wise", + "bloom", + "bullet", + "cell", + "check", + "cost", + "darling", + "during", + "footstep", + "fragile", + "hallway", + "hardly", + "horizon", + "invisible", + "journey", + "midnight", + "mud", + "nod", + "pause", + "relax", + "shiver", + "sudden", + "value", + "youth", + "abuse", + "admire", + "blink", + "breast", + "bruise", + "constantly", + "couple", + "creep", + "curve", + "difference", + "dumb", + "emptiness", + "gotta", + "honor", + "plain", + "planet", + "recall", + "rub", + "ship", + "slam", + "soar", + "somebody", + "tightly", + "weather", + "adore", + "approach", + "bond", + "bread", + "burst", + "candle", + "coffee", + "cousin", + "crime", + "desert", + "flutter", + "frozen", + "grand", + "heel", + "hello", + "language", + "level", + "movement", + "pleasure", + "powerful", + "random", + "rhythm", + "settle", + "silly", + "slap", + "sort", + "spoken", + "steel", + "threaten", + "tumble", + "upset", + "aside", + "awkward", + "bee", + "blank", + "board", + "button", + "card", + "carefully", + "complain", + "crap", + "deeply", + "discover", + "drag", + "dread", + "effort", + "entire", + "fairy", + "giant", + "gotten", + "greet", + "illusion", + "jeans", + "leap", + "liquid", + "march", + "mend", + "nervous", + "nine", + "replace", + "rope", + "spine", + "stole", + "terror", + "accident", + "apple", + "balance", + "boom", + "childhood", + "collect", + "demand", + "depression", + "eventually", + "faint", + "glare", + "goal", + "group", + "honey", + "kitchen", + "laid", + "limb", + "machine", + "mere", + "mold", + "murder", + "nerve", + "painful", + "poetry", + "prince", + "rabbit", + "shelter", + "shore", + "shower", + "soothe", + "stair", + "steady", + "sunlight", + "tangle", + "tease", + "treasure", + "uncle", + "begun", + "bliss", + "canvas", + "cheer", + "claw", + "clutch", + "commit", + "crimson", + "crystal", + "delight", + "doll", + "existence", + "express", + "fog", + "football", + "gay", + "goose", + "guard", + "hatred", + "illuminate", + "mass", + "math", + "mourn", + "rich", + "rough", + "skip", + "stir", + "student", + "style", + "support", + "thorn", + "tough", + "yard", + "yearn", + "yesterday", + "advice", + "appreciate", + "autumn", + "bank", + "beam", + "bowl", + "capture", + "carve", + "collapse", + "confusion", + "creation", + "dove", + "feather", + "girlfriend", + "glory", + "government", + "harsh", + "hop", + "inner", + "loser", + "moonlight", + "neighbor", + "neither", + "peach", + "pig", + "praise", + "screw", + "shield", + "shimmer", + "sneak", + "stab", + "subject", + "throughout", + "thrown", + "tower", + "twirl", + "wow", + "army", + "arrive", + "bathroom", + "bump", + "cease", + "cookie", + "couch", + "courage", + "dim", + "guilt", + "howl", + "hum", + "husband", + "insult", + "led", + "lunch", + "mock", + "mostly", + "natural", + "nearly", + "needle", + "nerd", + "peaceful", + "perfection", + "pile", + "price", + "remove", + "roam", + "sanctuary", + "serious", + "shiny", + "shook", + "sob", + "stolen", + "tap", + "vain", + "void", + "warrior", + "wrinkle", + "affection", + "apologize", + "blossom", + "bounce", + "bridge", + "cheap", + "crumble", + "decision", + "descend", + "desperately", + "dig", + "dot", + "flip", + "frighten", + "heartbeat", + "huge", + "lazy", + "lick", + "odd", + "opinion", + "process", + "puzzle", + "quietly", + "retreat", + "score", + "sentence", + "separate", + "situation", + "skill", + "soak", + "square", + "stray", + "taint", + "task", + "tide", + "underneath", + "veil", + "whistle", + "anywhere", + "bedroom", + "bid", + "bloody", + "burden", + "careful", + "compare", + "concern", + "curtain", + "decay", + "defeat", + "describe", + "double", + "dreamer", + "driver", + "dwell", + "evening", + "flare", + "flicker", + "grandma", + "guitar", + "harm", + "horrible", + "hungry", + "indeed", + "lace", + "melody", + "monkey", + "nation", + "object", + "obviously", + "rainbow", + "salt", + "scratch", + "shown", + "shy", + "stage", + "stun", + "third", + "tickle", + "useless", + "weakness", + "worship", + "worthless", + "afternoon", + "beard", + "boyfriend", + "bubble", + "busy", + "certain", + "chin", + "concrete", + "desk", + "diamond", + "doom", + "drawn", + "due", + "felicity", + "freeze", + "frost", + "garden", + "glide", + "harmony", + "hopefully", + "hunt", + "jealous", + "lightning", + "mama", + "mercy", + "peel", + "physical", + "position", + "pulse", + "punch", + "quit", + "rant", + "respond", + "salty", + "sane", + "satisfy", + "savior", + "sheep", + "slept", + "social", + "sport", + "tuck", + "utter", + "valley", + "wolf", + "aim", + "alas", + "alter", + "arrow", + "awaken", + "beaten", + "belief", + "brand", + "ceiling", + "cheese", + "clue", + "confidence", + "connection", + "daily", + "disguise", + "eager", + "erase", + "essence", + "everytime", + "expression", + "fan", + "flag", + "flirt", + "foul", + "fur", + "giggle", + "glorious", + "ignorance", + "law", + "lifeless", + "measure", + "mighty", + "muse", + "north", + "opposite", + "paradise", + "patience", + "patient", + "pencil", + "petal", + "plate", + "ponder", + "possibly", + "practice", + "slice", + "spell", + "stock", + "strife", + "strip", + "suffocate", + "suit", + "tender", + "tool", + "trade", + "velvet", + "verse", + "waist", + "witch", + "aunt", + "bench", + "bold", + "cap", + "certainly", + "click", + "companion", + "creator", + "dart", + "delicate", + "determine", + "dish", + "dragon", + "drama", + "drum", + "dude", + "everybody", + "feast", + "forehead", + "former", + "fright", + "fully", + "gas", + "hook", + "hurl", + "invite", + "juice", + "manage", + "moral", + "possess", + "raw", + "rebel", + "royal", + "scale", + "scary", + "several", + "slight", + "stubborn", + "swell", + "talent", + "tea", + "terrible", + "thread", + "torment", + "trickle", + "usually", + "vast", + "violence", + "weave", + "acid", + "agony", + "ashamed", + "awe", + "belly", + "blend", + "blush", + "character", + "cheat", + "common", + "company", + "coward", + "creak", + "danger", + "deadly", + "defense", + "define", + "depend", + "desperate", + "destination", + "dew", + "duck", + "dusty", + "embarrass", + "engine", + "example", + "explore", + "foe", + "freely", + "frustrate", + "generation", + "glove", + "guilty", + "health", + "hurry", + "idiot", + "impossible", + "inhale", + "jaw", + "kingdom", + "mention", + "mist", + "moan", + "mumble", + "mutter", + "observe", + "ode", + "pathetic", + "pattern", + "pie", + "prefer", + "puff", + "rape", + "rare", + "revenge", + "rude", + "scrape", + "spiral", + "squeeze", + "strain", + "sunset", + "suspend", + "sympathy", + "thigh", + "throne", + "total", + "unseen", + "weapon", + "weary", +} From fa881220aedb638f9ee35337b2ca1817c2a8482f Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 13 Aug 2014 10:52:50 +0200 Subject: [PATCH 42/64] Updated lookup method to include CNAME's as well as A records --- ethchain/bloom.go | 2 +- ethpub/pub.go | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ethchain/bloom.go b/ethchain/bloom.go index 320ce73fc..5317ca0b1 100644 --- a/ethchain/bloom.go +++ b/ethchain/bloom.go @@ -6,7 +6,7 @@ type BloomFilter struct { func NewBloomFilter(bin []byte) *BloomFilter { if bin == nil { - bin = make([]byte, 255) + bin = make([]byte, 256) } return &BloomFilter{ diff --git a/ethpub/pub.go b/ethpub/pub.go index ab2aae599..762c9a60f 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "math/big" + "strconv" "strings" "sync/atomic" @@ -74,8 +75,22 @@ func (self *PEthereum) LookupDomain(domain string) string { if len(domain) > 32 { domain = string(ethcrypto.Sha3Bin([]byte(domain))) } + data := world.Config().Get("DnsReg").StorageString(domain).Bytes() - return strings.Trim(world.Config().Get("DnsReg").StorageString(domain).Str(), "\x00") + // Left padded = A record, Right padded = CNAME + if data[0] == 0 { + data = bytes.TrimLeft(data, "\x00") + var ipSlice []string + for _, d := range data { + ipSlice = append(ipSlice, strconv.Itoa(int(d))) + } + + return strings.Join(ipSlice, ".") + } else { + data = bytes.TrimRight(data, "\x00") + + return string(data) + } } func (lib *PEthereum) GetBlock(hexHash string) *PBlock { From 0d733aa07197c8adbbaa92a12a4ad32e86676cc7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 14 Aug 2014 17:02:21 +0200 Subject: [PATCH 43/64] Removed validation check from GetMessages --- ethchain/state_manager.go | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a60b28b3f..d7860b2a2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -406,37 +406,9 @@ func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, defer state.Reset() - if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { - fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) - } + sm.ApplyDiff(state, parent, block) - receipts, err := sm.ApplyDiff(state, parent, block) - if err != nil { - return nil, err - } - - txSha := CreateTxSha(receipts) - if bytes.Compare(txSha, block.TxSha) != 0 { - return nil, fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha) - } - - // Block validation - if err = sm.ValidateBlock(block); err != nil { - statelogger.Errorln("Error validating block:", err) - return nil, err - } - - // I'm not sure, but I don't know if there should be thrown - // any errors at this time. - if err = sm.AccumelateRewards(state, block); err != nil { - statelogger.Errorln("Error accumulating reward", err) - return nil, err - } - - if !block.State().Cmp(state) { - err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) - return nil, err - } + sm.AccumelateRewards(state, block) return state.Manifest().Messages, nil } From 07cfb7b64ac7932a4ff8c2480452114b84b421a6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 14 Aug 2014 17:02:39 +0200 Subject: [PATCH 44/64] updated filter so it accepts multiple from and to --- ethchain/filter.go | 48 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/ethchain/filter.go b/ethchain/filter.go index c3b0a7f94..65c41c42d 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -14,7 +14,7 @@ type Filter struct { earliest []byte latest []byte skip int - from, to []byte + from, to [][]byte max int } @@ -53,14 +53,22 @@ func (self *Filter) SetLatestBlock(latest interface{}) { } } -func (self *Filter) SetFrom(addr []byte) { +func (self *Filter) SetFrom(addr [][]byte) { self.from = addr } -func (self *Filter) SetTo(addr []byte) { +func (self *Filter) AddFrom(addr []byte) { + self.from = append(self.from, addr) +} + +func (self *Filter) SetTo(addr [][]byte) { self.to = addr } +func (self *Filter) AddTo(addr []byte) { + self.from = append(self.to, addr) +} + func (self *Filter) SetMax(max int) { self.max = max } @@ -101,13 +109,22 @@ func (self *Filter) Find() []*ethstate.Message { break } + includes := func(addresses [][]byte, a []byte) (found bool) { + for _, addr := range addresses { + if bytes.Compare(addr, a) == 0 { + return true + } + } + + return + } // Filter the messages for interesting stuff for _, message := range msgs { - if len(self.to) > 0 && bytes.Compare(message.To, self.to) != 0 { + if len(self.to) > 0 && !includes(self.to, message.To) { continue } - if len(self.from) > 0 && bytes.Compare(message.From, self.from) != 0 { + if len(self.from) > 0 && !includes(self.from, message.From) { continue } @@ -130,17 +147,28 @@ func (self *Filter) bloomFilter(block *Block) bool { bloom := NewBloomFilter(bin) + var fromIncluded, toIncluded bool if len(self.from) > 0 { - if !bloom.Search(self.from) { - return false + for _, from := range self.from { + if bloom.Search(from) { + fromIncluded = true + break + } } + } else { + fromIncluded = true } if len(self.to) > 0 { - if !bloom.Search(self.to) { - return false + for _, to := range self.to { + if bloom.Search(to) { + toIncluded = true + break + } } + } else { + toIncluded = true } - return true + return fromIncluded && toIncluded } From 0fcc6065692f2692072cdf0d61fe1ada547fc235 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 00:24:37 +0200 Subject: [PATCH 45/64] Added new filter from map --- ethchain/filter.go | 89 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 21 deletions(-) diff --git a/ethchain/filter.go b/ethchain/filter.go index 65c41c42d..4f3160b90 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -24,6 +24,46 @@ func NewFilter(eth EthManager) *Filter { return &Filter{eth: eth} } +func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { + filter := NewFilter(eth) + + if object["earliest"] != nil { + earliest := object["earliest"] + if e, ok := earliest.(string); ok { + filter.SetEarliestBlock(ethutil.Hex2Bytes(e)) + } else { + filter.SetEarliestBlock(earliest) + } + } + + if object["latest"] != nil { + latest := object["latest"] + if l, ok := latest.(string); ok { + filter.SetLatestBlock(ethutil.Hex2Bytes(l)) + } else { + filter.SetLatestBlock(latest) + } + } + + if object["to"] != nil { + filter.AddTo(ethutil.Hex2Bytes(object["to"].(string))) + } + + if object["from"] != nil { + filter.AddFrom(ethutil.Hex2Bytes(object["from"].(string))) + } + + if object["max"] != nil { + filter.SetMax(object["max"].(int)) + } + + if object["skip"] != nil { + filter.SetSkip(object["skip"].(int)) + } + + return filter +} + // Set the earliest and latest block for filtering. // -1 = latest block (i.e., the current block) // hash = particular hash from-to @@ -109,27 +149,7 @@ func (self *Filter) Find() []*ethstate.Message { break } - includes := func(addresses [][]byte, a []byte) (found bool) { - for _, addr := range addresses { - if bytes.Compare(addr, a) == 0 { - return true - } - } - - return - } - // Filter the messages for interesting stuff - for _, message := range msgs { - if len(self.to) > 0 && !includes(self.to, message.To) { - continue - } - - if len(self.from) > 0 && !includes(self.from, message.From) { - continue - } - - messages = append(messages, message) - } + messages = append(messages, self.FilterMessages(msgs)...) } block = self.eth.BlockChain().GetBlock(block.PrevHash) @@ -138,6 +158,33 @@ func (self *Filter) Find() []*ethstate.Message { return messages } +func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message { + var messages []*ethstate.Message + includes := func(addresses [][]byte, a []byte) (found bool) { + for _, addr := range addresses { + if bytes.Compare(addr, a) == 0 { + return true + } + } + + return + } + // Filter the messages for interesting stuff + for _, message := range msgs { + if len(self.to) > 0 && !includes(self.to, message.To) { + continue + } + + if len(self.from) > 0 && !includes(self.from, message.From) { + continue + } + + messages = append(messages, message) + } + + return messages +} + func (self *Filter) bloomFilter(block *Block) bool { fk := append([]byte("bloom"), block.Hash()...) bin, err := self.eth.Db().Get(fk) From c7ee9844bd6f8ed2bb466f8adf21f437ecc83564 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 00:25:16 +0200 Subject: [PATCH 46/64] Removed old code --- ethchain/state_manager.go | 16 ++++++++++------ ethstate/manifest.go | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index d7860b2a2..1f47a2e0b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -380,14 +380,18 @@ func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { - for addr, value := range mappedObjects { - // Set the bloom filter's bin - bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr))) + sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages) - sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) + /* + for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { + for addr, value := range mappedObjects { + // Set the bloom filter's bin + bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr))) + + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) + } } - } + */ return bloomf } diff --git a/ethstate/manifest.go b/ethstate/manifest.go index b771127a6..88ce673b9 100644 --- a/ethstate/manifest.go +++ b/ethstate/manifest.go @@ -17,7 +17,7 @@ type Manifest struct { ObjectChanges map[string]*StateObject StorageChanges map[string]map[string]*big.Int - Messages []*Message + Messages Messages } func NewManifest() *Manifest { @@ -50,6 +50,7 @@ func (self *Manifest) AddMessage(msg *Message) *Message { return msg } +type Messages []*Message type Message struct { To, From []byte Input []byte From ace551030fbe9288d0d8660f9431867a42e98c88 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 01:08:23 +0200 Subject: [PATCH 47/64] Convert to hex --- ethpub/types.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ethpub/types.go b/ethpub/types.go index faf75bbe1..159f7d9a7 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -221,15 +221,16 @@ func (self *PStateObject) EachStorage(cb ethtrie.EachCallback) { } type KeyVal struct { - Key string - Value string + Key string `json:"key"` + Value string `json:"value"` } func (c *PStateObject) StateKeyVal(asJson bool) interface{} { var values []KeyVal if c.object != nil { c.object.EachStorage(func(name string, value *ethutil.Value) { - values = append(values, KeyVal{name, ethutil.Bytes2Hex(value.Bytes())}) + value.Decode() + values = append(values, KeyVal{ethutil.Bytes2Hex([]byte(name)), ethutil.Bytes2Hex(value.Bytes())}) }) } @@ -238,7 +239,7 @@ func (c *PStateObject) StateKeyVal(asJson bool) interface{} { if err != nil { return nil } - fmt.Println(string(valuesJson)) + return string(valuesJson) } From d701b232304149f5e9035213d1710ab71cc4a01d Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 13:05:13 +0200 Subject: [PATCH 48/64] Reworking the public js interface (pub) => (pipe) --- ethpipe/js_pipe.go | 168 +++++++++++++++++++++++++++++++++++++++++ ethpipe/js_types.go | 177 ++++++++++++++++++++++++++++++++++++++++++++ ethpipe/world.go | 4 + ethpub/pub.go | 6 -- 4 files changed, 349 insertions(+), 6 deletions(-) create mode 100644 ethpipe/js_pipe.go create mode 100644 ethpipe/js_types.go diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go new file mode 100644 index 000000000..a2d3fdf10 --- /dev/null +++ b/ethpipe/js_pipe.go @@ -0,0 +1,168 @@ +package ethpipe + +import ( + "encoding/json" + "sync/atomic" + + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethutil" +) + +type JSPipe struct { + *Pipe +} + +func NewJSPipe(eth ethchain.EthManager) *JSPipe { + return &JSPipe{New(eth)} +} + +func (self *JSPipe) GetBlockByHash(strHash string) *JSBlock { + hash := ethutil.Hex2Bytes(strHash) + block := self.obj.BlockChain().GetBlock(hash) + + return NewJSBlock(block) +} + +func (self *JSPipe) GetKey() *JSKey { + return NewJSKey(self.obj.KeyManager().KeyPair()) +} + +func (self *JSPipe) GetStateObject(addr string) *JSObject { + object := &Object{self.World().safeGet(ethutil.Hex2Bytes(addr))} + + return NewJSObject(object) +} + +func (self *JSPipe) GetPeerCount() int { + return self.obj.PeerCount() +} + +func (self *JSPipe) GetPeers() []JSPeer { + var peers []JSPeer + for peer := self.obj.Peers().Front(); peer != nil; peer = peer.Next() { + p := peer.Value.(ethchain.Peer) + // we only want connected peers + if atomic.LoadInt32(p.Connected()) != 0 { + peers = append(peers, *NewJSPeer(p)) + } + } + + return peers +} + +func (self *JSPipe) GetIsMining() bool { + return self.obj.IsMining() +} + +func (self *JSPipe) GetIsListening() bool { + return self.obj.IsListening() +} + +func (self *JSPipe) GetCoinBase() string { + return ethutil.Bytes2Hex(self.obj.KeyManager().Address()) +} + +func (self *JSPipe) GetStorage(addr, storageAddr string) string { + return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Storage(ethutil.Hex2Bytes(storageAddr)).Str() +} + +func (self *JSPipe) GetTxCountAt(address string) int { + return int(self.World().SafeGet(ethutil.Hex2Bytes(address)).Nonce) +} + +func (self *JSPipe) IsContract(address string) bool { + return len(self.World().SafeGet(ethutil.Hex2Bytes(address)).Code) > 0 +} + +func (self *JSPipe) SecretToAddress(key string) string { + pair, err := ethcrypto.NewKeyPairFromSec(ethutil.Hex2Bytes(key)) + if err != nil { + return "" + } + + return ethutil.Bytes2Hex(pair.Address()) +} + +type KeyVal struct { + Key string `json:"key"` + Value string `json:"value"` +} + +func (self *JSPipe) GetEachStorage(addr string) string { + var values []KeyVal + object := self.World().SafeGet(ethutil.Hex2Bytes(addr)) + object.EachStorage(func(name string, value *ethutil.Value) { + value.Decode() + values = append(values, KeyVal{ethutil.Bytes2Hex([]byte(name)), ethutil.Bytes2Hex(value.Bytes())}) + }) + + valuesJson, err := json.Marshal(values) + if err != nil { + return "" + } + + return string(valuesJson) +} + +func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (*JSReceipt, error) { + var hash []byte + var contractCreation bool + if len(toStr) == 0 { + contractCreation = true + } else { + // Check if an address is stored by this address + addr := self.World().Config().Get("NameReg").StorageString(toStr).Bytes() + if len(addr) > 0 { + hash = addr + } else { + hash = ethutil.Hex2Bytes(toStr) + } + } + + var keyPair *ethcrypto.KeyPair + var err error + if ethutil.IsHex(key) { + keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key[2:]))) + } else { + keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key))) + } + + if err != nil { + return nil, err + } + + var ( + value = ethutil.Big(valueStr) + gas = ethutil.Big(gasStr) + gasPrice = ethutil.Big(gasPriceStr) + data []byte + tx *ethchain.Transaction + ) + + if ethutil.IsHex(codeStr) { + data = ethutil.Hex2Bytes(codeStr[2:]) + } else { + data = ethutil.Hex2Bytes(codeStr) + } + + if contractCreation { + tx = ethchain.NewContractCreationTx(value, gas, gasPrice, data) + } else { + tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, data) + } + + acc := self.obj.StateManager().TransState().GetOrNewStateObject(keyPair.Address()) + tx.Nonce = acc.Nonce + acc.Nonce += 1 + self.obj.StateManager().TransState().UpdateStateObject(acc) + + tx.Sign(keyPair.PrivateKey) + self.obj.TxPool().QueueTransaction(tx) + + if contractCreation { + logger.Infof("Contract addr %x", tx.CreationAddress()) + } + + return NewJSReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil +} diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go new file mode 100644 index 000000000..e1743486b --- /dev/null +++ b/ethpipe/js_types.go @@ -0,0 +1,177 @@ +package ethpipe + +import ( + "encoding/json" + "strconv" + "strings" + + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethutil" +) + +// Block interface exposed to QML +type JSBlock struct { + ref *ethchain.Block + Number int `json:"number"` + Hash string `json:"hash"` + Transactions string `json:"transactions"` + Time int64 `json:"time"` + Coinbase string `json:"coinbase"` + Name string `json:"name"` + GasLimit string `json:"gasLimit"` + GasUsed string `json:"gasUsed"` +} + +// Creates a new QML Block from a chain block +func NewJSBlock(block *ethchain.Block) *JSBlock { + if block == nil { + return nil + } + + var ptxs []JSTransaction + for _, tx := range block.Transactions() { + ptxs = append(ptxs, *NewJSTx(tx)) + } + + txJson, err := json.Marshal(ptxs) + if err != nil { + return nil + } + + return &JSBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} +} + +func (self *JSBlock) ToString() string { + if self.ref != nil { + return self.ref.String() + } + + return "" +} + +func (self *JSBlock) GetTransaction(hash string) *JSTransaction { + tx := self.ref.GetTransaction(ethutil.Hex2Bytes(hash)) + if tx == nil { + return nil + } + + return NewJSTx(tx) +} + +type JSTransaction struct { + ref *ethchain.Transaction + + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + Hash string `json:"hash"` + Address string `json:"address"` + Sender string `json:"sender"` + RawData string `json:"rawData"` + Data string `json:"data"` + Contract bool `json:"isContract"` + CreatesContract bool `json:"createsContract"` + Confirmations int `json:"confirmations"` +} + +func NewJSTx(tx *ethchain.Transaction) *JSTransaction { + hash := ethutil.Bytes2Hex(tx.Hash()) + receiver := ethutil.Bytes2Hex(tx.Recipient) + if receiver == "0000000000000000000000000000000000000000" { + receiver = ethutil.Bytes2Hex(tx.CreationAddress()) + } + sender := ethutil.Bytes2Hex(tx.Sender()) + createsContract := tx.CreatesContract() + + var data string + if tx.CreatesContract() { + data = strings.Join(ethchain.Disassemble(tx.Data), "\n") + } else { + data = ethutil.Bytes2Hex(tx.Data) + } + + return &JSTransaction{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: ethutil.Bytes2Hex(tx.Data)} +} + +func (self *JSTransaction) ToString() string { + return self.ref.String() +} + +type JSKey struct { + Address string `json:"address"` + PrivateKey string `json:"privateKey"` + PublicKey string `json:"publicKey"` +} + +func NewJSKey(key *ethcrypto.KeyPair) *JSKey { + return &JSKey{ethutil.Bytes2Hex(key.Address()), ethutil.Bytes2Hex(key.PrivateKey), ethutil.Bytes2Hex(key.PublicKey)} +} + +type JSObject struct { + *Object +} + +func NewJSObject(object *Object) *JSObject { + return &JSObject{object} +} + +type PReceipt struct { + CreatedContract bool `json:"createdContract"` + Address string `json:"address"` + Hash string `json:"hash"` + Sender string `json:"sender"` +} + +func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt { + return &PReceipt{ + contractCreation, + ethutil.Bytes2Hex(creationAddress), + ethutil.Bytes2Hex(hash), + ethutil.Bytes2Hex(address), + } +} + +// Peer interface exposed to QML + +type JSPeer struct { + ref *ethchain.Peer + Inbound bool `json:"isInbound"` + LastSend int64 `json:"lastSend"` + LastPong int64 `json:"lastPong"` + Ip string `json:"ip"` + Port int `json:"port"` + Version string `json:"version"` + LastResponse string `json:"lastResponse"` + Latency string `json:"latency"` +} + +func NewJSPeer(peer ethchain.Peer) *JSPeer { + if peer == nil { + return nil + } + + var ip []string + for _, i := range peer.Host() { + ip = append(ip, strconv.Itoa(int(i))) + } + ipAddress := strings.Join(ip, ".") + + return &JSPeer{ref: &peer, Inbound: peer.Inbound(), LastSend: peer.LastSend().Unix(), LastPong: peer.LastPong(), Version: peer.Version(), Ip: ipAddress, Port: int(peer.Port()), Latency: peer.PingTime()} +} + +type JSReceipt struct { + CreatedContract bool `json:"createdContract"` + Address string `json:"address"` + Hash string `json:"hash"` + Sender string `json:"sender"` +} + +func NewJSReciept(contractCreation bool, creationAddress, hash, address []byte) *JSReceipt { + return &JSReceipt{ + contractCreation, + ethutil.Bytes2Hex(creationAddress), + ethutil.Bytes2Hex(hash), + ethutil.Bytes2Hex(address), + } +} diff --git a/ethpipe/world.go b/ethpipe/world.go index 72e116d09..4666362f9 100644 --- a/ethpipe/world.go +++ b/ethpipe/world.go @@ -30,6 +30,10 @@ func (self *World) Get(addr []byte) *Object { return &Object{self.State().GetStateObject(addr)} } +func (self *World) SafeGet(addr []byte) *Object { + return &Object{self.safeGet(addr)} +} + func (self *World) safeGet(addr []byte) *ethstate.StateObject { object := self.State().GetStateObject(addr) if object == nil { diff --git a/ethpub/pub.go b/ethpub/pub.go index 762c9a60f..64c08c2f1 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -52,12 +52,6 @@ type PEthereum struct { keyManager *ethcrypto.KeyManager } -func NewPEthereum(manager ethchain.EthManager) *PEthereum { - logger.Warnln("DEPRECATED: ethpub.New should be used in favour of ethpub.NewPEthereum") - - return New(manager) -} - func New(manager ethchain.EthManager) *PEthereum { return &PEthereum{ manager, From 7d95e8624a3bdca4a68b2a7ff6ed133264088cc1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 16:19:10 +0200 Subject: [PATCH 49/64] Added message to closure && added change addresses --- ethchain/filter.go | 101 ++++++++++++++++++++++++++++++++--- ethchain/state_manager.go | 14 +++-- ethchain/state_transition.go | 8 +-- ethpipe/pipe.go | 2 +- ethstate/manifest.go | 30 +++-------- ethstate/state.go | 2 - ethvm/closure.go | 11 ++-- ethvm/vm.go | 7 ++- 8 files changed, 125 insertions(+), 50 deletions(-) diff --git a/ethchain/filter.go b/ethchain/filter.go index 4f3160b90..c4c403cf7 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -6,8 +6,13 @@ import ( "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" + "gopkg.in/qml.v1" ) +type data struct { + id, address []byte +} + // Filtering interface type Filter struct { eth EthManager @@ -16,6 +21,8 @@ type Filter struct { skip int from, to [][]byte max int + + altered []data } // Create a new filter which uses a bloom filter on blocks to figure out whether a particular block @@ -61,9 +68,19 @@ func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { filter.SetSkip(object["skip"].(int)) } + if object["altered"] != nil { + filter.altered = makeAltered(object["altered"]) + } + + fmt.Println("ALTERED", filter.altered) + return filter } +func (self *Filter) AddAltered(id, address []byte) { + self.altered = append(self.altered, data{id, address}) +} + // Set the earliest and latest block for filtering. // -1 = latest block (i.e., the current block) // hash = particular hash from-to @@ -158,17 +175,19 @@ func (self *Filter) Find() []*ethstate.Message { return messages } +func includes(addresses [][]byte, a []byte) (found bool) { + for _, addr := range addresses { + if bytes.Compare(addr, a) == 0 { + return true + } + } + + return +} + func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message { var messages []*ethstate.Message - includes := func(addresses [][]byte, a []byte) (found bool) { - for _, addr := range addresses { - if bytes.Compare(addr, a) == 0 { - return true - } - } - return - } // Filter the messages for interesting stuff for _, message := range msgs { if len(self.to) > 0 && !includes(self.to, message.To) { @@ -179,6 +198,28 @@ func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message continue } + var match bool + if len(self.altered) == 0 { + match = true + } + + for _, item := range self.altered { + if len(item.id) > 0 && bytes.Compare(message.To, item.id) != 0 { + continue + } + + if len(item.address) > 0 && !includes(message.ChangedAddresses, item.address) { + continue + } + + match = true + break + } + + if !match { + continue + } + messages = append(messages, message) } @@ -219,3 +260,47 @@ func (self *Filter) bloomFilter(block *Block) bool { return fromIncluded && toIncluded } + +// Conversion methodn +func mapToData(m map[string]interface{}) (d data) { + if str, ok := m["id"].(string); ok { + d.id = ethutil.Hex2Bytes(str) + } + + if str, ok := m["at"].(string); ok { + d.address = ethutil.Hex2Bytes(str) + } + + return +} + +// data can come in in the following formats: +// ["aabbccdd", {id: "ccddee", at: "11223344"}], "aabbcc", {id: "ccddee", at: "1122"} +func makeAltered(v interface{}) (d []data) { + if str, ok := v.(string); ok { + d = append(d, data{ethutil.Hex2Bytes(str), nil}) + } else if obj, ok := v.(map[string]interface{}); ok { + d = append(d, mapToData(obj)) + } else if slice, ok := v.([]interface{}); ok { + for _, item := range slice { + d = append(d, makeAltered(item)...) + } + } else if qList, ok := v.(*qml.List); ok { + var s []interface{} + qList.Convert(&s) + + fmt.Println(s) + + d = makeAltered(s) + } else if qMap, ok := v.(*qml.Map); ok { + var m map[string]interface{} + qMap.Convert(&m) + fmt.Println(m) + + d = makeAltered(m) + } else { + panic(fmt.Sprintf("makeAltered err (unknown conversion): %T\n", v)) + } + + return +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1f47a2e0b..08bd22d29 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -373,11 +373,17 @@ func (sm *StateManager) Stop() { func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { bloomf := NewBloomFilter(nil) - for addr, stateObject := range state.Manifest().ObjectChanges { - // Set the bloom filter's bin - bloomf.Set([]byte(addr)) + /* + for addr, stateObject := range state.Manifest().ObjectChanges { + // Set the bloom filter's bin + bloomf.Set([]byte(addr)) - sm.Ethereum.Reactor().Post("object:"+addr, stateObject) + sm.Ethereum.Reactor().Post("object:"+addr, stateObject) + } + */ + for _, msg := range state.Manifest().Messages { + bloomf.Set(msg.To) + bloomf.Set(msg.From) } sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 489ff2b6a..f8452cdb3 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -225,7 +225,7 @@ func (self *StateTransition) TransitionState() (err error) { // script section for the state object. self.data = nil - code, err := self.Eval(receiver.Init(), receiver, "init") + code, err := self.Eval(msg, receiver.Init(), receiver, "init") if err != nil { self.state.Set(snapshot) @@ -236,7 +236,7 @@ func (self *StateTransition) TransitionState() (err error) { msg.Output = code } else { if len(receiver.Code) > 0 { - ret, err := self.Eval(receiver.Code, receiver, "code") + ret, err := self.Eval(msg, receiver.Code, receiver, "code") if err != nil { self.state.Set(snapshot) @@ -263,12 +263,12 @@ func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObjec return nil } -func (self *StateTransition) Eval(script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) { +func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) { var ( transactor = self.Sender() state = self.state env = NewEnv(state, self.tx, self.block) - callerClosure = ethvm.NewClosure(transactor, context, script, self.gas, self.gasPrice) + callerClosure = ethvm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) ) vm := ethvm.New(env) diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index a9da66ab8..8a81734cd 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -61,7 +61,7 @@ func (self *Pipe) ExecuteObject(object *Object, data []byte, value, gas, price * vm := ethvm.New(NewEnv(self.Vm.State, block, value.BigInt(), initiator.Address())) - closure := ethvm.NewClosure(initiator, stateObject, object.Code, gas.BigInt(), price.BigInt()) + closure := ethvm.NewClosure(ðstate.Message{}, initiator, stateObject, object.Code, gas.BigInt(), price.BigInt()) ret, _, err := closure.Call(vm, data) return ret, err diff --git a/ethstate/manifest.go b/ethstate/manifest.go index 88ce673b9..604f77b89 100644 --- a/ethstate/manifest.go +++ b/ethstate/manifest.go @@ -10,38 +10,18 @@ import ( // The object manifest is used to keep changes to the state so we can keep track of the changes // that occurred during a state transitioning phase. type Manifest struct { - // XXX These will be handy in the future. Not important for now. - objectAddresses map[string]bool - storageAddresses map[string]map[string]bool - - ObjectChanges map[string]*StateObject - StorageChanges map[string]map[string]*big.Int - Messages Messages } func NewManifest() *Manifest { - m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} + m := &Manifest{} m.Reset() return m } func (m *Manifest) Reset() { - m.ObjectChanges = make(map[string]*StateObject) - m.StorageChanges = make(map[string]map[string]*big.Int) -} - -func (m *Manifest) AddObjectChange(stateObject *StateObject) { - m.ObjectChanges[string(stateObject.Address())] = stateObject -} - -func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { - if m.StorageChanges[string(stateObject.Address())] == nil { - m.StorageChanges[string(stateObject.Address())] = make(map[string]*big.Int) - } - - m.StorageChanges[string(stateObject.Address())][string(storageAddr)] = storage + m.Messages = nil } func (self *Manifest) AddMessage(msg *Message) *Message { @@ -61,6 +41,12 @@ type Message struct { Coinbase []byte Block []byte Number *big.Int + + ChangedAddresses [][]byte +} + +func (self *Message) AddStorageChange(addr []byte) { + self.ChangedAddresses = append(self.ChangedAddresses, addr) } func (self *Message) String() string { diff --git a/ethstate/state.go b/ethstate/state.go index 19210916e..cf060e795 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -60,8 +60,6 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Code), stateObject.Code) self.Trie.Update(string(addr), string(stateObject.RlpEncode())) - - self.manifest.AddObjectChange(stateObject) } // Delete the given state object and delete it from the state trie diff --git a/ethvm/closure.go b/ethvm/closure.go index f9be952d4..54bfd05f4 100644 --- a/ethvm/closure.go +++ b/ethvm/closure.go @@ -18,9 +18,10 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { - caller ClosureRef - object *ethstate.StateObject - Code []byte + caller ClosureRef + object *ethstate.StateObject + Code []byte + message *ethstate.Message Gas, UsedGas, Price *big.Int @@ -28,8 +29,8 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure { - c := &Closure{caller: caller, object: object, Code: code, Args: nil} +func NewClosure(msg *ethstate.Message, caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure { + c := &Closure{message: msg, caller: caller, object: object, Code: code, Args: nil} // Gas should be a pointer so it can safely be reduced through the run // This pointer will be off the state transition diff --git a/ethvm/vm.go b/ethvm/vm.go index a0d4db591..789697865 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -645,8 +645,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { val, loc := stack.Popn() closure.SetStorage(loc, ethutil.NewValue(val)) - // Add the change to manifest - self.env.State().Manifest().AddStorageChange(closure.Object(), loc.Bytes(), val) + closure.message.AddStorageChange(loc.Bytes()) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: @@ -719,7 +718,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { closure.UseGas(closure.Gas) // Create the closure - c := NewClosure(closure, contract, initCode, gas, closure.Price) + c := NewClosure(msg, closure, contract, initCode, gas, closure.Price) // Call the closure and set the return value as // main script. contract.Code, _, err = c.Call(self, nil) @@ -783,7 +782,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stateObject.AddAmount(value) // Create a new callable closure - c := NewClosure(closure, stateObject, stateObject.Code, gas, closure.Price) + c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price) // Executer the closure and get the return value (if any) ret, _, err := c.Call(self, args) if err != nil { From 4bd6003b7fea3d6291f2ebde8b9f9264f1749985 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 16 Aug 2014 01:38:02 +0200 Subject: [PATCH 50/64] removed pub completely in favour of pipe --- ethpub/pub.go | 296 --------------------------------------------- ethpub/types.go | 273 ----------------------------------------- ethrpc/packages.go | 36 +++--- ethrpc/server.go | 13 +- 4 files changed, 26 insertions(+), 592 deletions(-) delete mode 100644 ethpub/pub.go delete mode 100644 ethpub/types.go diff --git a/ethpub/pub.go b/ethpub/pub.go deleted file mode 100644 index 64c08c2f1..000000000 --- a/ethpub/pub.go +++ /dev/null @@ -1,296 +0,0 @@ -package ethpub - -import ( - "bytes" - "encoding/json" - "math/big" - "strconv" - "strings" - "sync/atomic" - - "github.com/ethereum/eth-go/ethchain" - "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethpipe" - "github.com/ethereum/eth-go/ethstate" - "github.com/ethereum/eth-go/ethutil" -) - -var logger = ethlog.NewLogger("PUB") - -// TODO this has to move elsewhere -var cnfCtr = ethutil.Hex2Bytes("661005d2720d855f1d9976f88bb10c1a3398c77f") - -type helper struct { - sm *ethchain.StateManager -} - -func EthereumConfig(stateManager *ethchain.StateManager) helper { - return helper{stateManager} -} -func (self helper) obj() *ethstate.StateObject { - return self.sm.CurrentState().GetStateObject(cnfCtr) -} - -func (self helper) NameReg() *ethstate.StateObject { - if self.obj() != nil { - addr := self.obj().GetStorage(big.NewInt(0)) - if len(addr.Bytes()) > 0 { - return self.sm.CurrentState().GetStateObject(addr.Bytes()) - } - } - - return nil -} - -// TODO Re-write / refactor -type PEthereum struct { - manager ethchain.EthManager - stateManager *ethchain.StateManager - blockChain *ethchain.BlockChain - txPool *ethchain.TxPool - keyManager *ethcrypto.KeyManager -} - -func New(manager ethchain.EthManager) *PEthereum { - return &PEthereum{ - manager, - manager.StateManager(), - manager.BlockChain(), - manager.TxPool(), - manager.KeyManager(), - } -} - -func (self *PEthereum) LookupDomain(domain string) string { - pipe := ethpipe.New(self.manager) - world := pipe.World() - - if len(domain) > 32 { - domain = string(ethcrypto.Sha3Bin([]byte(domain))) - } - data := world.Config().Get("DnsReg").StorageString(domain).Bytes() - - // Left padded = A record, Right padded = CNAME - if data[0] == 0 { - data = bytes.TrimLeft(data, "\x00") - var ipSlice []string - for _, d := range data { - ipSlice = append(ipSlice, strconv.Itoa(int(d))) - } - - return strings.Join(ipSlice, ".") - } else { - data = bytes.TrimRight(data, "\x00") - - return string(data) - } -} - -func (lib *PEthereum) GetBlock(hexHash string) *PBlock { - hash := ethutil.Hex2Bytes(hexHash) - block := lib.blockChain.GetBlock(hash) - - return NewPBlock(block) -} - -func (lib *PEthereum) GetKey() *PKey { - return NewPKey(lib.keyManager.KeyPair()) -} - -func (lib *PEthereum) GetStateObject(address string) *PStateObject { - stateObject := lib.stateManager.CurrentState().GetStateObject(ethutil.Hex2Bytes(address)) - if stateObject != nil { - return NewPStateObject(stateObject) - } - - // See GetStorage for explanation on "nil" - return NewPStateObject(nil) -} - -func (lib *PEthereum) GetPeerCount() int { - return lib.manager.PeerCount() -} - -func (lib *PEthereum) GetPeers() []PPeer { - var peers []PPeer - for peer := lib.manager.Peers().Front(); peer != nil; peer = peer.Next() { - p := peer.Value.(ethchain.Peer) - // we only want connected peers - if atomic.LoadInt32(p.Connected()) != 0 { - peers = append(peers, *NewPPeer(p)) - } - } - - return peers -} - -func (lib *PEthereum) GetIsMining() bool { - return lib.manager.IsMining() -} - -func (lib *PEthereum) GetIsListening() bool { - return lib.manager.IsListening() -} - -func (lib *PEthereum) GetCoinBase() string { - return ethutil.Bytes2Hex(lib.keyManager.Address()) -} - -func (lib *PEthereum) GetTransactionsFor(address string, asJson bool) interface{} { - sBlk := lib.manager.BlockChain().LastBlockHash - blk := lib.manager.BlockChain().GetBlock(sBlk) - addr := []byte(ethutil.Hex2Bytes(address)) - - var txs []*PTx - - for ; blk != nil; blk = lib.manager.BlockChain().GetBlock(sBlk) { - sBlk = blk.PrevHash - - // Loop through all transactions to see if we missed any while being offline - for _, tx := range blk.Transactions() { - if bytes.Compare(tx.Sender(), addr) == 0 || bytes.Compare(tx.Recipient, addr) == 0 { - ptx := NewPTx(tx) - //TODO: somehow move this to NewPTx - ptx.Confirmations = int(lib.manager.BlockChain().LastBlockNumber - blk.BlockInfo().Number) - txs = append(txs, ptx) - } - } - } - if asJson { - txJson, err := json.Marshal(txs) - if err != nil { - return nil - } - return string(txJson) - } - return txs -} - -func (lib *PEthereum) GetStorage(address, storageAddress string) string { - return lib.GetStateObject(address).GetStorage(storageAddress) -} - -func (lib *PEthereum) GetTxCountAt(address string) int { - return lib.GetStateObject(address).Nonce() -} - -func (lib *PEthereum) IsContract(address string) bool { - return lib.GetStateObject(address).IsContract() -} - -func (lib *PEthereum) SecretToAddress(key string) string { - pair, err := ethcrypto.NewKeyPairFromSec(ethutil.Hex2Bytes(key)) - if err != nil { - return "" - } - - return ethutil.Bytes2Hex(pair.Address()) -} - -func FindAddressInNameReg(stateManager *ethchain.StateManager, name string) []byte { - nameReg := EthereumConfig(stateManager).NameReg() - if nameReg != nil { - addr := ethutil.RightPadBytes([]byte(name), 32) - - reg := nameReg.GetStorage(ethutil.BigD(addr)) - - return reg.Bytes() - } - - return nil -} - -func FindNameInNameReg(stateManager *ethchain.StateManager, addr []byte) string { - nameReg := EthereumConfig(stateManager).NameReg() - if nameReg != nil { - addr = ethutil.LeftPadBytes(addr, 32) - - reg := nameReg.GetStorage(ethutil.BigD(addr)) - - return strings.TrimRight(reg.Str(), "\x00") - } - - return "" -} - -func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) { - return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr) -} - -func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, script string) (*PReceipt, error) { - return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, script) -} - -func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { - var hash []byte - var contractCreation bool - if len(recipient) == 0 { - contractCreation = true - } else { - // Check if an address is stored by this address - addr := FindAddressInNameReg(lib.stateManager, recipient) - if len(addr) > 0 { - hash = addr - } else { - hash = ethutil.Hex2Bytes(recipient) - } - } - - var keyPair *ethcrypto.KeyPair - var err error - if ethutil.IsHex(key) { - keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key[2:]))) - } else { - keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key))) - } - - if err != nil { - return nil, err - } - - value := ethutil.Big(valueStr) - gas := ethutil.Big(gasStr) - gasPrice := ethutil.Big(gasPriceStr) - var tx *ethchain.Transaction - // Compile and assemble the given data - if contractCreation { - var script []byte - var err error - if ethutil.IsHex(scriptStr) { - script = ethutil.Hex2Bytes(scriptStr[2:]) - } else { - script, err = ethutil.Compile(scriptStr, false) - if err != nil { - return nil, err - } - } - - tx = ethchain.NewContractCreationTx(value, gas, gasPrice, script) - } else { - data := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) { - slice := strings.Split(s, "\n") - for _, dataItem := range slice { - d := ethutil.FormatData(dataItem) - ret = append(ret, d...) - } - return - }) - - tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, data) - } - - acc := lib.stateManager.TransState().GetOrNewStateObject(keyPair.Address()) - tx.Nonce = acc.Nonce - acc.Nonce += 1 - lib.stateManager.TransState().UpdateStateObject(acc) - - tx.Sign(keyPair.PrivateKey) - lib.txPool.QueueTransaction(tx) - - if contractCreation { - logger.Infof("Contract addr %x", tx.CreationAddress()) - } - - return NewPReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil -} diff --git a/ethpub/types.go b/ethpub/types.go deleted file mode 100644 index 159f7d9a7..000000000 --- a/ethpub/types.go +++ /dev/null @@ -1,273 +0,0 @@ -package ethpub - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/ethereum/eth-go/ethchain" - "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethstate" - "github.com/ethereum/eth-go/ethtrie" - "github.com/ethereum/eth-go/ethutil" -) - -// Peer interface exposed to QML - -type PPeer struct { - ref *ethchain.Peer - Inbound bool `json:"isInbound"` - LastSend int64 `json:"lastSend"` - LastPong int64 `json:"lastPong"` - Ip string `json:"ip"` - Port int `json:"port"` - Version string `json:"version"` - LastResponse string `json:"lastResponse"` - Latency string `json:"latency"` -} - -func NewPPeer(peer ethchain.Peer) *PPeer { - if peer == nil { - return nil - } - - // TODO: There must be something build in to do this? - var ip []string - for _, i := range peer.Host() { - ip = append(ip, fmt.Sprintf("%d", i)) - } - ipAddress := strings.Join(ip, ".") - - return &PPeer{ref: &peer, Inbound: peer.Inbound(), LastSend: peer.LastSend().Unix(), LastPong: peer.LastPong(), Version: peer.Version(), Ip: ipAddress, Port: int(peer.Port()), Latency: peer.PingTime()} -} - -// Block interface exposed to QML -type PBlock struct { - ref *ethchain.Block - Number int `json:"number"` - Hash string `json:"hash"` - Transactions string `json:"transactions"` - Time int64 `json:"time"` - Coinbase string `json:"coinbase"` - Name string `json:"name"` - GasLimit string `json:"gasLimit"` - GasUsed string `json:"gasUsed"` -} - -// Creates a new QML Block from a chain block -func NewPBlock(block *ethchain.Block) *PBlock { - if block == nil { - return nil - } - - var ptxs []PTx - for _, tx := range block.Transactions() { - ptxs = append(ptxs, *NewPTx(tx)) - } - - txJson, err := json.Marshal(ptxs) - if err != nil { - return nil - } - - return &PBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} -} - -func (self *PBlock) ToString() string { - if self.ref != nil { - return self.ref.String() - } - - return "" -} - -func (self *PBlock) GetTransaction(hash string) *PTx { - tx := self.ref.GetTransaction(ethutil.Hex2Bytes(hash)) - if tx == nil { - return nil - } - - return NewPTx(tx) -} - -type PTx struct { - ref *ethchain.Transaction - - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - Hash string `json:"hash"` - Address string `json:"address"` - Sender string `json:"sender"` - RawData string `json:"rawData"` - Data string `json:"data"` - Contract bool `json:"isContract"` - CreatesContract bool `json:"createsContract"` - Confirmations int `json:"confirmations"` -} - -func NewPTx(tx *ethchain.Transaction) *PTx { - hash := ethutil.Bytes2Hex(tx.Hash()) - receiver := ethutil.Bytes2Hex(tx.Recipient) - if receiver == "0000000000000000000000000000000000000000" { - receiver = ethutil.Bytes2Hex(tx.CreationAddress()) - } - sender := ethutil.Bytes2Hex(tx.Sender()) - createsContract := tx.CreatesContract() - - var data string - if tx.CreatesContract() { - data = strings.Join(ethchain.Disassemble(tx.Data), "\n") - } else { - data = ethutil.Bytes2Hex(tx.Data) - } - - return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: ethutil.Bytes2Hex(tx.Data)} -} - -func (self *PTx) ToString() string { - return self.ref.String() -} - -type PKey struct { - Address string `json:"address"` - PrivateKey string `json:"privateKey"` - PublicKey string `json:"publicKey"` -} - -func NewPKey(key *ethcrypto.KeyPair) *PKey { - return &PKey{ethutil.Bytes2Hex(key.Address()), ethutil.Bytes2Hex(key.PrivateKey), ethutil.Bytes2Hex(key.PublicKey)} -} - -type PReceipt struct { - CreatedContract bool `json:"createdContract"` - Address string `json:"address"` - Hash string `json:"hash"` - Sender string `json:"sender"` -} - -func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt { - return &PReceipt{ - contractCreation, - ethutil.Bytes2Hex(creationAddress), - ethutil.Bytes2Hex(hash), - ethutil.Bytes2Hex(address), - } -} - -type PStateObject struct { - object *ethstate.StateObject -} - -func NewPStateObject(object *ethstate.StateObject) *PStateObject { - return &PStateObject{object: object} -} - -func (c *PStateObject) GetStorage(address string) string { - // Because somehow, even if you return nil to QML it - // still has some magical object so we can't rely on - // undefined or null at the QML side - if c.object != nil { - val := c.object.GetStorage(ethutil.Big("0x" + address)) - - return val.BigInt().String() - } - - return "" -} - -func (c *PStateObject) Balance() string { - if c.object != nil { - return c.object.Balance.String() - } - - return "" -} - -func (c *PStateObject) Address() string { - if c.object != nil { - return ethutil.Bytes2Hex(c.object.Address()) - } - - return "" -} - -func (c *PStateObject) Nonce() int { - if c.object != nil { - return int(c.object.Nonce) - } - - return 0 -} - -func (c *PStateObject) Root() string { - if c.object != nil { - return ethutil.Bytes2Hex(ethutil.NewValue(c.object.State.Root()).Bytes()) - } - - return "" -} - -func (c *PStateObject) IsContract() bool { - if c.object != nil { - return len(c.object.Code) > 0 - } - - return false -} - -func (self *PStateObject) EachStorage(cb ethtrie.EachCallback) { - self.object.EachStorage(cb) -} - -type KeyVal struct { - Key string `json:"key"` - Value string `json:"value"` -} - -func (c *PStateObject) StateKeyVal(asJson bool) interface{} { - var values []KeyVal - if c.object != nil { - c.object.EachStorage(func(name string, value *ethutil.Value) { - value.Decode() - values = append(values, KeyVal{ethutil.Bytes2Hex([]byte(name)), ethutil.Bytes2Hex(value.Bytes())}) - }) - } - - if asJson { - valuesJson, err := json.Marshal(values) - if err != nil { - return nil - } - - return string(valuesJson) - } - - return values -} - -func (c *PStateObject) Script() string { - if c.object != nil { - return strings.Join(ethchain.Disassemble(c.object.Code), " ") - } - - return "" -} - -func (c *PStateObject) HexScript() string { - if c.object != nil { - return ethutil.Bytes2Hex(c.object.Code) - } - - return "" -} - -type PStorageState struct { - StateAddress string - Address string - Value string -} - -func NewPStorageState(storageObject *ethstate.StorageState) *PStorageState { - return &PStorageState{ethutil.Bytes2Hex(storageObject.StateAddress), ethutil.Bytes2Hex(storageObject.Address), storageObject.Value.String()} -} diff --git a/ethrpc/packages.go b/ethrpc/packages.go index d307d0314..bd7528415 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -6,12 +6,12 @@ import ( "math/big" "strings" - "github.com/ethereum/eth-go/ethpub" + "github.com/ethereum/eth-go/ethpipe" "github.com/ethereum/eth-go/ethutil" ) type EthereumApi struct { - ethp *ethpub.PEthereum + pipe *ethpipe.JSPipe } type JsonArgs interface { @@ -73,8 +73,8 @@ func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *string) error { if err != nil { return err } - // Do something - block := p.ethp.GetBlock(args.Hash) + + block := p.pipe.GetBlockByHash(args.Hash) *reply = NewSuccessRes(block) return nil } @@ -129,7 +129,7 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *string) error { if err != nil { return err } - result, _ := p.ethp.Transact(p.ethp.GetKey().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.pipe.Transact(p.pipe.GetKey().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) *reply = NewSuccessRes(result) return nil } @@ -139,13 +139,14 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error { if err != nil { return err } - result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Body) + + result, _ := p.pipe.Transact(p.pipe.GetKey().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body) *reply = NewSuccessRes(result) return nil } func (p *EthereumApi) GetKey(args interface{}, reply *string) error { - *reply = NewSuccessRes(p.ethp.GetKey()) + *reply = NewSuccessRes(p.pipe.GetKey()) return nil } @@ -175,7 +176,8 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { if err != nil { return err } - state := p.ethp.GetStateObject(args.Address) + + state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address)) var hx string if strings.Index(args.Key, "0x") == 0 { @@ -186,8 +188,8 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { hx = ethutil.Bytes2Hex(i.Bytes()) } logger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx) - value := state.GetStorage(hx) - *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) + value := state.Storage(ethutil.Hex2Bytes(hx)) + *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()}) return nil } @@ -210,7 +212,7 @@ type GetPeerCountRes struct { } func (p *EthereumApi) GetPeerCount(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetPeerCountRes{PeerCount: p.ethp.GetPeerCount()}) + *reply = NewSuccessRes(GetPeerCountRes{PeerCount: p.pipe.GetPeerCount()}) return nil } @@ -219,7 +221,7 @@ type GetListeningRes struct { } func (p *EthereumApi) GetIsListening(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetListeningRes{IsListening: p.ethp.GetIsListening()}) + *reply = NewSuccessRes(GetListeningRes{IsListening: p.pipe.GetIsListening()}) return nil } @@ -228,7 +230,7 @@ type GetCoinbaseRes struct { } func (p *EthereumApi) GetCoinbase(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetCoinbaseRes{Coinbase: p.ethp.GetCoinBase()}) + *reply = NewSuccessRes(GetCoinbaseRes{Coinbase: p.pipe.GetCoinBase()}) return nil } @@ -237,7 +239,7 @@ type GetMiningRes struct { } func (p *EthereumApi) GetIsMining(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetMiningRes{IsMining: p.ethp.GetIsMining()}) + *reply = NewSuccessRes(GetMiningRes{IsMining: p.pipe.GetIsMining()}) return nil } @@ -246,7 +248,7 @@ func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *string) error { if err != nil { return err } - state := p.ethp.GetTxCountAt(args.Address) + state := p.pipe.GetTxCountAt(args.Address) *reply = NewSuccessRes(GetTxCountRes{Nonce: state}) return nil } @@ -272,8 +274,8 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *string) error { if err != nil { return err } - state := p.ethp.GetStateObject(args.Address) - *reply = NewSuccessRes(BalanceRes{Balance: state.Balance(), Address: args.Address}) + state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address)) + *reply = NewSuccessRes(BalanceRes{Balance: state.Balance.String(), Address: args.Address}) return nil } diff --git a/ethrpc/server.go b/ethrpc/server.go index d9d6f695b..4abe29aa9 100644 --- a/ethrpc/server.go +++ b/ethrpc/server.go @@ -2,11 +2,12 @@ package ethrpc import ( "fmt" - "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethpub" "net" "net/rpc" "net/rpc/jsonrpc" + + "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethpipe" ) var logger = ethlog.NewLogger("JSON") @@ -14,7 +15,7 @@ var logger = ethlog.NewLogger("JSON") type JsonRpcServer struct { quit chan bool listener net.Listener - ethp *ethpub.PEthereum + pipe *ethpipe.JSPipe } func (s *JsonRpcServer) exitHandler() { @@ -37,7 +38,7 @@ func (s *JsonRpcServer) Stop() { func (s *JsonRpcServer) Start() { logger.Infoln("Starting JSON-RPC server") go s.exitHandler() - rpc.Register(&EthereumApi{ethp: s.ethp}) + rpc.Register(&EthereumApi{pipe: s.pipe}) rpc.HandleHTTP() for { @@ -51,7 +52,7 @@ func (s *JsonRpcServer) Start() { } } -func NewJsonRpcServer(ethp *ethpub.PEthereum, port int) (*JsonRpcServer, error) { +func NewJsonRpcServer(pipe *ethpipe.JSPipe, port int) (*JsonRpcServer, error) { sport := fmt.Sprintf(":%d", port) l, err := net.Listen("tcp", sport) if err != nil { @@ -61,6 +62,6 @@ func NewJsonRpcServer(ethp *ethpub.PEthereum, port int) (*JsonRpcServer, error) return &JsonRpcServer{ listener: l, quit: make(chan bool), - ethp: ethp, + pipe: pipe, }, nil } From d79387c27e5bbbbed1d02cb9c57cbb7c5bd9fc33 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 17 Aug 2014 12:41:52 +0200 Subject: [PATCH 51/64] Mutan compile --- ethpipe/js_pipe.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index a2d3fdf10..2f1f90462 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -166,3 +166,12 @@ func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr return NewJSReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil } + +func (self *JSPipe) CompileMutan(code string) string { + data, err := self.Pipe.CompileMutan(code) + if err != nil { + return err.Error() + } + + return ethutil.Bytes2Hex(data) +} From 4008ff32c903e6894f5fb4fb69c795641641d192 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 17 Aug 2014 12:42:02 +0200 Subject: [PATCH 52/64] Mutan compile --- ethpipe/pipe.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index 8a81734cd..800a71139 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -148,3 +148,12 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price return tx.Hash(), nil } + +func (self *Pipe) CompileMutan(code string) ([]byte, error) { + data, err := ethutil.Compile(code, false) + if err != nil { + return nil, err + } + + return data, nil +} From 793e666f36e512bceb0d92d0a8dfe1d7c508c0e2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 17 Aug 2014 12:42:32 +0200 Subject: [PATCH 53/64] Dump bytes instead of strings --- ethstate/dump.go | 4 ++-- ethutil/common.go | 35 ++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/ethstate/dump.go b/ethstate/dump.go index 2406dfc49..be60a05fc 100644 --- a/ethstate/dump.go +++ b/ethstate/dump.go @@ -19,7 +19,7 @@ type World struct { Accounts map[string]Account `json:"accounts"` } -func (self *State) Dump() string { +func (self *State) Dump() []byte { world := World{ Root: ethutil.Bytes2Hex(self.Trie.Root.([]byte)), Accounts: make(map[string]Account), @@ -43,5 +43,5 @@ func (self *State) Dump() string { fmt.Println("dump err", err) } - return string(json) + return json } diff --git a/ethutil/common.go b/ethutil/common.go index cbd94e7ad..8532d80f2 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -34,26 +34,43 @@ var ( // Currency to string // Returns a string representing a human readable format func CurrencyToString(num *big.Int) string { + var ( + fin *big.Int = num + denom string = "Wei" + ) + switch { case num.Cmp(Douglas) >= 0: - return fmt.Sprintf("%v Douglas", new(big.Int).Div(num, Douglas)) + fin = new(big.Int).Div(num, Douglas) + denom = "Douglas" case num.Cmp(Einstein) >= 0: - return fmt.Sprintf("%v Einstein", new(big.Int).Div(num, Einstein)) + fin = new(big.Int).Div(num, Einstein) + denom = "Einstein" case num.Cmp(Ether) >= 0: - return fmt.Sprintf("%v Ether", new(big.Int).Div(num, Ether)) + fin = new(big.Int).Div(num, Ether) + denom = "Ether" case num.Cmp(Finney) >= 0: - return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) + fin = new(big.Int).Div(num, Finney) + denom = "Finney" case num.Cmp(Szabo) >= 0: - return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) + fin = new(big.Int).Div(num, Szabo) + denom = "Szabo" case num.Cmp(Shannon) >= 0: - return fmt.Sprintf("%v Shannon", new(big.Int).Div(num, Shannon)) + fin = new(big.Int).Div(num, Shannon) + denom = "Shannon" case num.Cmp(Babbage) >= 0: - return fmt.Sprintf("%v Babbage", new(big.Int).Div(num, Babbage)) + fin = new(big.Int).Div(num, Babbage) + denom = "Babbage" case num.Cmp(Ada) >= 0: - return fmt.Sprintf("%v Ada", new(big.Int).Div(num, Ada)) + fin = new(big.Int).Div(num, Ada) + denom = "Ada" } - return fmt.Sprintf("%v Wei", num) + if len(fin.String()) > 5 { + return fmt.Sprintf("%sE%d %s", fin.String()[0:5], len(fin.String())-5, denom) + } + + return fmt.Sprintf("%v %s", fin, denom) } // Common big integers often used From b0ae61c6521003d7861d89944e1d426e939535bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 18 Aug 2014 10:17:45 +0200 Subject: [PATCH 54/64] Removed the "Get" part --- ethchain/state_transition.go | 1 + ethpipe/js_pipe.go | 49 ++++++++++++++++++++++++++++-------- ethpipe/js_types.go | 31 +++++++++++++++++++++++ ethrpc/packages.go | 18 ++++++------- ethstate/manifest.go | 3 ++- ethvm/vm.go | 2 ++ 6 files changed, 83 insertions(+), 21 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index f8452cdb3..9fbc160a5 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -216,6 +216,7 @@ func (self *StateTransition) TransitionState() (err error) { Input: self.tx.Data, Origin: sender.Address(), Block: self.block.Hash(), Timestamp: self.block.Time, Coinbase: self.block.Coinbase, Number: self.block.Number, + Value: self.value, }) // Process the init code and create 'valid' contract diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index 2f1f90462..a2b1a4551 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -17,28 +17,28 @@ func NewJSPipe(eth ethchain.EthManager) *JSPipe { return &JSPipe{New(eth)} } -func (self *JSPipe) GetBlockByHash(strHash string) *JSBlock { +func (self *JSPipe) BlockByHash(strHash string) *JSBlock { hash := ethutil.Hex2Bytes(strHash) block := self.obj.BlockChain().GetBlock(hash) return NewJSBlock(block) } -func (self *JSPipe) GetKey() *JSKey { +func (self *JSPipe) Key() *JSKey { return NewJSKey(self.obj.KeyManager().KeyPair()) } -func (self *JSPipe) GetStateObject(addr string) *JSObject { +func (self *JSPipe) StateObject(addr string) *JSObject { object := &Object{self.World().safeGet(ethutil.Hex2Bytes(addr))} return NewJSObject(object) } -func (self *JSPipe) GetPeerCount() int { +func (self *JSPipe) PeerCount() int { return self.obj.PeerCount() } -func (self *JSPipe) GetPeers() []JSPeer { +func (self *JSPipe) Peers() []JSPeer { var peers []JSPeer for peer := self.obj.Peers().Front(); peer != nil; peer = peer.Next() { p := peer.Value.(ethchain.Peer) @@ -51,23 +51,33 @@ func (self *JSPipe) GetPeers() []JSPeer { return peers } -func (self *JSPipe) GetIsMining() bool { +func (self *JSPipe) IsMining() bool { return self.obj.IsMining() } -func (self *JSPipe) GetIsListening() bool { +func (self *JSPipe) IsListening() bool { return self.obj.IsListening() } -func (self *JSPipe) GetCoinBase() string { +func (self *JSPipe) CoinBase() string { return ethutil.Bytes2Hex(self.obj.KeyManager().Address()) } -func (self *JSPipe) GetStorage(addr, storageAddr string) string { +func (self *JSPipe) BalanceAt(addr string) string { + return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Balance.String() +} + +func (self *JSPipe) NumberToHuman(balance string) string { + b := ethutil.Big(balance) + + return ethutil.CurrencyToString(b) +} + +func (self *JSPipe) StorageAt(addr, storageAddr string) string { return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Storage(ethutil.Hex2Bytes(storageAddr)).Str() } -func (self *JSPipe) GetTxCountAt(address string) int { +func (self *JSPipe) TxCountAt(address string) int { return int(self.World().SafeGet(ethutil.Hex2Bytes(address)).Nonce) } @@ -89,7 +99,7 @@ type KeyVal struct { Value string `json:"value"` } -func (self *JSPipe) GetEachStorage(addr string) string { +func (self *JSPipe) EachStorage(addr string) string { var values []KeyVal object := self.World().SafeGet(ethutil.Hex2Bytes(addr)) object.EachStorage(func(name string, value *ethutil.Value) { @@ -175,3 +185,20 @@ func (self *JSPipe) CompileMutan(code string) string { return ethutil.Bytes2Hex(data) } + +func (self *JSPipe) Messages(object map[string]interface{}) string { + filter := ethchain.NewFilterFromMap(object, self.obj) + + messages := filter.Find() + var msgs []JSMessage + for _, m := range messages { + msgs = append(msgs, NewJSMessage(m)) + } + + b, err := json.Marshal(msgs) + if err != nil { + return "{\"error\":" + err.Error() + "}" + } + + return string(b) +} diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go index e1743486b..0fb3a3876 100644 --- a/ethpipe/js_types.go +++ b/ethpipe/js_types.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" ) @@ -175,3 +176,33 @@ func NewJSReciept(contractCreation bool, creationAddress, hash, address []byte) ethutil.Bytes2Hex(address), } } + +type JSMessage struct { + To string `json:"to"` + From string `json:"from"` + Input string `json:"input"` + Output string `json:"output"` + Path int32 `json:"path"` + Origin string `json:"origin"` + Timestamp int32 `json:"timestamp"` + Coinbase string `json:"coinbase"` + Block string `json:"block"` + Number int32 `json:"number"` + Value string `json:"value"` +} + +func NewJSMessage(message *ethstate.Message) JSMessage { + return JSMessage{ + To: ethutil.Bytes2Hex(message.To), + From: ethutil.Bytes2Hex(message.From), + Input: ethutil.Bytes2Hex(message.Input), + Output: ethutil.Bytes2Hex(message.Output), + Path: int32(message.Path), + Origin: ethutil.Bytes2Hex(message.Origin), + Timestamp: int32(message.Timestamp), + Coinbase: ethutil.Bytes2Hex(message.Origin), + Block: ethutil.Bytes2Hex(message.Block), + Number: int32(message.Number.Int64()), + Value: message.Value.String(), + } +} diff --git a/ethrpc/packages.go b/ethrpc/packages.go index bd7528415..f2e57fa49 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -74,7 +74,7 @@ func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *string) error { return err } - block := p.pipe.GetBlockByHash(args.Hash) + block := p.pipe.BlockByHash(args.Hash) *reply = NewSuccessRes(block) return nil } @@ -129,7 +129,7 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *string) error { if err != nil { return err } - result, _ := p.pipe.Transact(p.pipe.GetKey().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) *reply = NewSuccessRes(result) return nil } @@ -140,13 +140,13 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error { return err } - result, _ := p.pipe.Transact(p.pipe.GetKey().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body) *reply = NewSuccessRes(result) return nil } func (p *EthereumApi) GetKey(args interface{}, reply *string) error { - *reply = NewSuccessRes(p.pipe.GetKey()) + *reply = NewSuccessRes(p.pipe.Key()) return nil } @@ -212,7 +212,7 @@ type GetPeerCountRes struct { } func (p *EthereumApi) GetPeerCount(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetPeerCountRes{PeerCount: p.pipe.GetPeerCount()}) + *reply = NewSuccessRes(GetPeerCountRes{PeerCount: p.pipe.PeerCount()}) return nil } @@ -221,7 +221,7 @@ type GetListeningRes struct { } func (p *EthereumApi) GetIsListening(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetListeningRes{IsListening: p.pipe.GetIsListening()}) + *reply = NewSuccessRes(GetListeningRes{IsListening: p.pipe.IsListening()}) return nil } @@ -230,7 +230,7 @@ type GetCoinbaseRes struct { } func (p *EthereumApi) GetCoinbase(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetCoinbaseRes{Coinbase: p.pipe.GetCoinBase()}) + *reply = NewSuccessRes(GetCoinbaseRes{Coinbase: p.pipe.CoinBase()}) return nil } @@ -239,7 +239,7 @@ type GetMiningRes struct { } func (p *EthereumApi) GetIsMining(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetMiningRes{IsMining: p.pipe.GetIsMining()}) + *reply = NewSuccessRes(GetMiningRes{IsMining: p.pipe.IsMining()}) return nil } @@ -248,7 +248,7 @@ func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *string) error { if err != nil { return err } - state := p.pipe.GetTxCountAt(args.Address) + state := p.pipe.TxCountAt(args.Address) *reply = NewSuccessRes(GetTxCountRes{Nonce: state}) return nil } diff --git a/ethstate/manifest.go b/ethstate/manifest.go index 604f77b89..945de22ab 100644 --- a/ethstate/manifest.go +++ b/ethstate/manifest.go @@ -41,6 +41,7 @@ type Message struct { Coinbase []byte Block []byte Number *big.Int + Value *big.Int ChangedAddresses [][]byte } @@ -50,5 +51,5 @@ func (self *Message) AddStorageChange(addr []byte) { } func (self *Message) String() string { - return fmt.Sprintf("Message{to: %x from: %x input: %x output: %x origin: %x coinbase: %x block: %x number: %v timestamp: %d path: %d", self.To, self.From, self.Input, self.Output, self.Origin, self.Coinbase, self.Block, self.Number, self.Timestamp, self.Path) + return fmt.Sprintf("Message{to: %x from: %x input: %x output: %x origin: %x coinbase: %x block: %x number: %v timestamp: %d path: %d value: %v", self.To, self.From, self.Input, self.Output, self.Origin, self.Coinbase, self.Block, self.Number, self.Timestamp, self.Path, self.Value) } diff --git a/ethvm/vm.go b/ethvm/vm.go index 789697865..ddad0d366 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -700,6 +700,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { To: addr, From: closure.Address(), Origin: self.env.Origin(), Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + Value: value, }) // Create a new contract @@ -765,6 +766,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { Input: args, Origin: self.env.Origin(), Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + Value: value, }) if closure.object.Balance.Cmp(value) < 0 { From b97ea0e447c24c0a85f63a7714a2eb221a7faccd Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 20 Aug 2014 09:59:09 +0200 Subject: [PATCH 55/64] Added JSFilter type --- ethpipe/js_pipe.go | 88 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index a2b1a4551..0d0928fc3 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -2,10 +2,13 @@ package ethpipe import ( "encoding/json" + "fmt" "sync/atomic" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethreact" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" ) @@ -74,7 +77,8 @@ func (self *JSPipe) NumberToHuman(balance string) string { } func (self *JSPipe) StorageAt(addr, storageAddr string) string { - return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Storage(ethutil.Hex2Bytes(storageAddr)).Str() + storage := self.World().SafeGet(ethutil.Hex2Bytes(addr)).Storage(ethutil.Hex2Bytes(storageAddr)) + return storage.BigInt().String() } func (self *JSPipe) TxCountAt(address string) int { @@ -186,10 +190,45 @@ func (self *JSPipe) CompileMutan(code string) string { return ethutil.Bytes2Hex(data) } -func (self *JSPipe) Messages(object map[string]interface{}) string { - filter := ethchain.NewFilterFromMap(object, self.obj) +func (self *JSPipe) Watch(object map[string]interface{}) *JSFilter { + return NewJSFilterFromMap(object, self.Pipe.obj) + /*} else if str, ok := object.(string); ok { + println("str") + return NewJSFilterFromString(str, self.Pipe.obj) + */ +} - messages := filter.Find() +func (self *JSPipe) Messages(object map[string]interface{}) string { + filter := self.Watch(object) + + defer filter.Uninstall() + + return filter.Messages() + +} + +type JSFilter struct { + eth ethchain.EthManager + *ethchain.Filter + quit chan bool + + BlockCallback func(*ethchain.Block) + MessageCallback func(ethstate.Messages) +} + +func NewJSFilterFromMap(object map[string]interface{}, eth ethchain.EthManager) *JSFilter { + filter := &JSFilter{eth, ethchain.NewFilterFromMap(object, eth), make(chan bool), nil, nil} + + go filter.mainLoop() + + return filter +} + +func NewJSFilterFromString(str string, eth ethchain.EthManager) *JSFilter { + return nil +} + +func (self *JSFilter) MessagesToJson(messages ethstate.Messages) string { var msgs []JSMessage for _, m := range messages { msgs = append(msgs, NewJSMessage(m)) @@ -202,3 +241,44 @@ func (self *JSPipe) Messages(object map[string]interface{}) string { return string(b) } + +func (self *JSFilter) Messages() string { + return self.MessagesToJson(self.Find()) +} + +func (self *JSFilter) mainLoop() { + blockChan := make(chan ethreact.Event, 1) + messageChan := make(chan ethreact.Event, 1) + // Subscribe to events + reactor := self.eth.Reactor() + reactor.Subscribe("newBlock", blockChan) + reactor.Subscribe("messages", messageChan) +out: + for { + select { + case <-self.quit: + break out + case block := <-blockChan: + if block, ok := block.Resource.(*ethchain.Block); ok { + if self.BlockCallback != nil { + self.BlockCallback(block) + } + } + case msg := <-messageChan: + if messages, ok := msg.Resource.(ethstate.Messages); ok { + if self.MessageCallback != nil { + msgs := self.FilterMessages(messages) + self.MessageCallback(msgs) + } + } + } + } +} + +func (self *JSFilter) Changed(object interface{}) { + fmt.Printf("%T\n", object) +} + +func (self *JSFilter) Uninstall() { + self.quit <- true +} From 55a2f35a648ef70cdcc88bd751265e30831b54e5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 20 Aug 2014 13:05:26 +0200 Subject: [PATCH 56/64] JS Filter --- ethchain/filter.go | 4 +--- ethpipe/js_pipe.go | 35 ++++++++++++++++++++++++++++++----- ethutil/bytes.go | 22 ++++++++++++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/ethchain/filter.go b/ethchain/filter.go index c4c403cf7..5ed9af977 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -72,8 +72,6 @@ func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { filter.altered = makeAltered(object["altered"]) } - fmt.Println("ALTERED", filter.altered) - return filter } @@ -123,7 +121,7 @@ func (self *Filter) SetTo(addr [][]byte) { } func (self *Filter) AddTo(addr []byte) { - self.from = append(self.to, addr) + self.to = append(self.to, addr) } func (self *Filter) SetMax(max int) { diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index 0d0928fc3..4b0d6a849 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -1,6 +1,7 @@ package ethpipe import ( + "bytes" "encoding/json" "fmt" "sync/atomic" @@ -119,6 +120,28 @@ func (self *JSPipe) EachStorage(addr string) string { return string(valuesJson) } +func (self *JSPipe) ToAscii(str string) string { + padded := ethutil.RightPadBytes([]byte(str), 32) + + return "0x" + ethutil.Bytes2Hex(padded) +} + +func (self *JSPipe) FromAscii(str string) string { + if ethutil.IsHex(str) { + str = str[2:] + } + + return string(bytes.Trim(ethutil.Hex2Bytes(str), "\x00")) +} + +func (self *JSPipe) FromNumber(str string) string { + if ethutil.IsHex(str) { + str = str[2:] + } + + return ethutil.BigD(ethutil.Hex2Bytes(str)).String() +} + func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (*JSReceipt, error) { var hash []byte var contractCreation bool @@ -200,8 +223,7 @@ func (self *JSPipe) Watch(object map[string]interface{}) *JSFilter { func (self *JSPipe) Messages(object map[string]interface{}) string { filter := self.Watch(object) - - defer filter.Uninstall() + filter.Uninstall() return filter.Messages() @@ -247,8 +269,8 @@ func (self *JSFilter) Messages() string { } func (self *JSFilter) mainLoop() { - blockChan := make(chan ethreact.Event, 1) - messageChan := make(chan ethreact.Event, 1) + blockChan := make(chan ethreact.Event, 5) + messageChan := make(chan ethreact.Event, 5) // Subscribe to events reactor := self.eth.Reactor() reactor.Subscribe("newBlock", blockChan) @@ -267,8 +289,11 @@ out: case msg := <-messageChan: if messages, ok := msg.Resource.(ethstate.Messages); ok { if self.MessageCallback != nil { + println("messages!") msgs := self.FilterMessages(messages) - self.MessageCallback(msgs) + if len(msgs) > 0 { + self.MessageCallback(msgs) + } } } } diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 49fc229d3..63c1606c2 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -173,6 +173,28 @@ func LeftPadBytes(slice []byte, l int) []byte { return padded } +func LeftPadString(str string, l int) string { + if l < len(str) { + return str + } + + zeros := Bytes2Hex(make([]byte, (l-len(str))/2)) + + return zeros + str + +} + +func RightPadString(str string, l int) string { + if l < len(str) { + return str + } + + zeros := Bytes2Hex(make([]byte, (l-len(str))/2)) + + return str + zeros + +} + func Address(slice []byte) (addr []byte) { if len(slice) < 20 { addr = LeftPadBytes(slice, 20) From 89c442cadbf995f09259b6a30a6d51989bd3d777 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 20 Aug 2014 13:36:54 +0200 Subject: [PATCH 57/64] Added block by number --- ethpipe/js_pipe.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index 4b0d6a849..51de4ddbe 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -28,6 +28,14 @@ func (self *JSPipe) BlockByHash(strHash string) *JSBlock { return NewJSBlock(block) } +func (self *JSPipe) GetBlockByNumber(num int32) *JSBlock { + if num == -1 { + return NewJSBlock(self.obj.BlockChain().CurrentBlock) + } + + return NewJSBlock(self.obj.BlockChain().GetBlockByNumber(uint64(num))) +} + func (self *JSPipe) Key() *JSKey { return NewJSKey(self.obj.KeyManager().KeyPair()) } From 79c64f6bca4fcfb257496be22c64f4b2faed7050 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 20 Aug 2014 16:40:19 +0200 Subject: [PATCH 58/64] Added block by hash or number --- ethpipe/js_pipe.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index 51de4ddbe..8f08a7c5f 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -28,7 +28,7 @@ func (self *JSPipe) BlockByHash(strHash string) *JSBlock { return NewJSBlock(block) } -func (self *JSPipe) GetBlockByNumber(num int32) *JSBlock { +func (self *JSPipe) BlockByNumber(num int32) *JSBlock { if num == -1 { return NewJSBlock(self.obj.BlockChain().CurrentBlock) } @@ -36,6 +36,18 @@ func (self *JSPipe) GetBlockByNumber(num int32) *JSBlock { return NewJSBlock(self.obj.BlockChain().GetBlockByNumber(uint64(num))) } +func (self *JSPipe) Block(v interface{}) *JSBlock { + if n, ok := v.(int32); ok { + return self.BlockByNumber(n) + } else if str, ok := v.(string); ok { + return self.BlockByHash(str) + } else if f, ok := v.(float64); ok { // Don't ask ... + return self.BlockByNumber(int32(f)) + } + + return nil +} + func (self *JSPipe) Key() *JSKey { return NewJSKey(self.obj.KeyManager().KeyPair()) } From eaa2e8900d1036e09b002c4e20fc6e4f9cd031bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 14:47:58 +0200 Subject: [PATCH 59/64] PoC 6 networking code. * Added block pool for gathering blocks from the network (chunks) * Re wrote syncing --- block_pool.go | 116 ++++++++++++++++ ethchain/block_chain.go | 20 +++ ethchain/genesis.go | 6 +- ethereum.go | 3 + ethutil/bytes.go | 8 ++ ethwire/messaging.go | 52 +++++--- peer.go | 288 ++++++++++++++++------------------------ 7 files changed, 296 insertions(+), 197 deletions(-) create mode 100644 block_pool.go diff --git a/block_pool.go b/block_pool.go new file mode 100644 index 000000000..3225bdff2 --- /dev/null +++ b/block_pool.go @@ -0,0 +1,116 @@ +package eth + +import ( + "math" + "math/big" + "sync" + + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethutil" +) + +type block struct { + peer *Peer + block *ethchain.Block +} + +type BlockPool struct { + mut sync.Mutex + + eth *Ethereum + + hashPool [][]byte + pool map[string]*block + + td *big.Int +} + +func NewBlockPool(eth *Ethereum) *BlockPool { + return &BlockPool{ + eth: eth, + pool: make(map[string]*block), + td: ethutil.Big0, + } +} + +func (self *BlockPool) HasLatestHash() bool { + return self.pool[string(self.eth.BlockChain().CurrentBlock.Hash())] != nil +} + +func (self *BlockPool) HasCommonHash(hash []byte) bool { + return self.eth.BlockChain().GetBlock(hash) != nil +} + +func (self *BlockPool) AddHash(hash []byte) { + if self.pool[string(hash)] == nil { + self.pool[string(hash)] = &block{nil, nil} + + self.hashPool = append([][]byte{hash}, self.hashPool...) + } +} + +func (self *BlockPool) SetBlock(b *ethchain.Block) { + hash := string(b.Hash()) + + if self.pool[string(hash)] == nil { + self.pool[hash] = &block{nil, nil} + } + + self.pool[hash].block = b +} + +func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) bool { + self.mut.Lock() + defer self.mut.Unlock() + + if self.IsLinked() { + for i, hash := range self.hashPool { + block := self.pool[string(hash)].block + if block != nil { + f(block) + + delete(self.pool, string(hash)) + } else { + self.hashPool = self.hashPool[i:] + + return false + } + } + + return true + } + + return false +} + +func (self *BlockPool) IsLinked() bool { + if len(self.hashPool) == 0 { + return false + } + + block := self.pool[string(self.hashPool[0])].block + if block != nil { + return self.eth.BlockChain().HasBlock(block.PrevHash) + } + + return false +} + +func (self *BlockPool) Take(amount int, peer *Peer) (hashes [][]byte) { + self.mut.Lock() + defer self.mut.Unlock() + + num := int(math.Min(float64(amount), float64(len(self.pool)))) + j := 0 + for i := 0; i < len(self.hashPool) && j < num; i++ { + hash := string(self.hashPool[i]) + if self.pool[hash].peer == nil || self.pool[hash].peer == peer { + self.pool[hash].peer = peer + + hashes = append(hashes, self.hashPool[i]) + j++ + } + } + + return +} diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 611735707..3445bbb87 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -208,6 +208,26 @@ func (bc *BlockChain) GenesisBlock() *Block { return bc.genesisBlock } +func (self *BlockChain) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) { + block := self.GetBlock(hash) + if block == nil { + return + } + + // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list) + for i := uint64(0); i < max; i++ { + chain = append(chain, block.Hash()) + + if block.Number.Cmp(ethutil.Big0) <= 0 { + break + } + + block = self.GetBlock(block.PrevHash) + } + + return +} + // Get chain return blocks from hash up to max in RLP format func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { var chain []interface{} diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 54a3bc766..0ce53a6ee 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -1,9 +1,10 @@ package ethchain import ( + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" - "math/big" ) /* @@ -26,7 +27,8 @@ var GenesisHeader = []interface{}{ // tx sha "", // Difficulty - ethutil.BigPow(2, 22), + //ethutil.BigPow(2, 22), + big.NewInt(4096), // Number ethutil.Big0, // Block minimum gas price diff --git a/ethereum.go b/ethereum.go index c1c4c2f2f..1e1891589 100644 --- a/ethereum.go +++ b/ethereum.go @@ -54,6 +54,8 @@ type Ethereum struct { txPool *ethchain.TxPool // The canonical chain blockChain *ethchain.BlockChain + // The block pool + blockPool *BlockPool // Peers (NYI) peers *list.List // Nonce @@ -116,6 +118,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager } ethereum.reactor = ethreact.New() + ethereum.blockPool = NewBlockPool(ethereum) ethereum.txPool = ethchain.NewTxPool(ethereum) ethereum.blockChain = ethchain.NewBlockChain(ethereum) ethereum.stateManager = ethchain.NewStateManager(ethereum) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 63c1606c2..e38f89454 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -208,3 +208,11 @@ func Address(slice []byte) (addr []byte) { return } + +func ByteSliceToInterface(slice [][]byte) (ret []interface{}) { + for _, i := range slice { + ret = append(ret, i) + } + + return +} diff --git a/ethwire/messaging.go b/ethwire/messaging.go index d114a1c9d..7ac0188a1 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -27,33 +27,41 @@ const ( // Values are given explicitly instead of by iota because these values are // defined by the wire protocol spec; it is easier for humans to ensure // correctness when values are explicit. - MsgHandshakeTy = 0x00 - MsgDiscTy = 0x01 - MsgPingTy = 0x02 - MsgPongTy = 0x03 - MsgGetPeersTy = 0x10 - MsgPeersTy = 0x11 - MsgTxTy = 0x12 - MsgBlockTy = 0x13 - MsgGetChainTy = 0x14 - MsgNotInChainTy = 0x15 - MsgGetTxsTy = 0x16 + MsgHandshakeTy = 0x00 + MsgDiscTy = 0x01 + MsgPingTy = 0x02 + MsgPongTy = 0x03 + MsgGetPeersTy = 0x10 + MsgPeersTy = 0x11 + MsgTxTy = 0x12 + MsgGetChainTy = 0x14 + MsgNotInChainTy = 0x15 + MsgGetTxsTy = 0x16 + MsgGetBlockHashesTy = 0x17 + MsgBlockHashesTy = 0x18 + MsgGetBlocksTy = 0x19 + MsgBlockTy = 0x13 + + MsgOldBlockTy = 0xbb MsgTalkTy = 0xff ) var msgTypeToString = map[MsgType]string{ - MsgHandshakeTy: "Handshake", - MsgDiscTy: "Disconnect", - MsgPingTy: "Ping", - MsgPongTy: "Pong", - MsgGetPeersTy: "Get peers", - MsgPeersTy: "Peers", - MsgTxTy: "Transactions", - MsgBlockTy: "Blocks", - MsgGetChainTy: "Get chain", - MsgGetTxsTy: "Get Txs", - MsgNotInChainTy: "Not in chain", + MsgHandshakeTy: "Handshake", + MsgDiscTy: "Disconnect", + MsgPingTy: "Ping", + MsgPongTy: "Pong", + MsgGetPeersTy: "Get peers", + MsgPeersTy: "Peers", + MsgTxTy: "Transactions", + MsgBlockTy: "Blocks", + MsgGetChainTy: "Get chain", + MsgGetTxsTy: "Get Txs", + MsgNotInChainTy: "Not in chain", + MsgGetBlockHashesTy: "Get block hashes", + MsgBlockHashesTy: "Block hashes", + MsgGetBlocksTy: "Get blocks", } func (mt MsgType) String() string { diff --git a/peer.go b/peer.go index 4cbe8b652..4e6fc55d4 100644 --- a/peer.go +++ b/peer.go @@ -4,6 +4,8 @@ import ( "bytes" "container/list" "fmt" + "math" + "math/big" "net" "strconv" "strings" @@ -22,7 +24,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 26 + ProtocolVersion = 27 // Interval for ping/pong message pingPongTimer = 2 * time.Second ) @@ -125,9 +127,13 @@ type Peer struct { lastPong int64 lastBlockReceived time.Time - host []byte - port uint16 - caps Caps + host []byte + port uint16 + caps Caps + td *big.Int + bestHash []byte + lastReceivedHash []byte + requestedHashes [][]byte // This peer's public key pubkey []byte @@ -345,7 +351,6 @@ func (p *Peer) HandleInbound() { for _, msg := range msgs { peerlogger.DebugDetailf("(%v) => %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) - nextMsg: switch msg.Type { case ethwire.MsgHandshakeTy: // Version message @@ -354,6 +359,7 @@ func (p *Peer) HandleInbound() { if p.caps.IsCap(CapPeerDiscTy) { p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, "")) } + case ethwire.MsgDiscTy: p.Stop() peerlogger.Infoln("Disconnect peer: ", DiscReason(msg.Data.Get(0).Uint())) @@ -366,117 +372,6 @@ func (p *Peer) HandleInbound() { // active. p.lastPong = time.Now().Unix() p.pingTime = time.Since(p.pingStartTime) - case ethwire.MsgBlockTy: - // Get all blocks and process them - //var block, lastBlock *ethchain.Block - //var err error - - var ( - block, lastBlock *ethchain.Block - blockChain = p.ethereum.BlockChain() - err error - ) - - // Make sure we are actually receiving anything - if msg.Data.Len()-1 > 1 && p.diverted { - // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find - // common ground to start syncing from - lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) - if p.lastRequestedBlock != nil && bytes.Compare(lastBlock.Hash(), p.lastRequestedBlock.Hash()) == 0 { - p.catchingUp = false - continue - } - p.lastRequestedBlock = lastBlock - peerlogger.Infof("Last block: %x. Checking if we have it locally.\n", lastBlock.Hash()) - for i := msg.Data.Len() - 1; i >= 0; i-- { - block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) - // Do we have this block on our chain? If so we can continue - if !blockChain.HasBlock(block.Hash()) { - // We don't have this block, but we do have a block with the same prevHash, diversion time! - if blockChain.HasBlockWithPrevHash(block.PrevHash) { - p.diverted = false - if !blockChain.FindCanonicalChainFromMsg(msg, block.PrevHash) { - p.SyncWithPeerToLastKnown() - break nextMsg - } - break - } - } - } - if !blockChain.HasBlock(lastBlock.Hash()) { - // If we can't find a common ancenstor we need to request more blocks. - // FIXME: At one point this won't scale anymore since we are not asking for an offset - // we just keep increasing the amount of blocks. - p.blocksRequested = p.blocksRequested * 2 - - peerlogger.Infof("No common ancestor found, requesting %d more blocks.\n", p.blocksRequested) - p.FindCommonParentBlock() - break nextMsg - } - - p.catchingUp = false - } - - for i := msg.Data.Len() - 1; i >= 0; i-- { - block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) - - err = p.ethereum.StateManager().Process(block, false) - if err != nil { - if ethutil.Config.Debug { - peerlogger.Infof("Block %x failed\n", block.Hash()) - peerlogger.Infof("%v\n", err) - peerlogger.Debugln(block) - } - break - } else { - lastBlock = block - } - - p.lastBlockReceived = time.Now() - } - - if msg.Data.Len() <= 1 { - // Set catching up to false if - // the peer has nothing left to give - p.catchingUp = false - } - - 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 unknown\n", b.Hash()) - p.catchingUp = false - - p.CatchupWithPeer(b.PrevHash) - - peerlogger.Infoln(b) - - /* - peerlogger.Infoln("Attempting to catch. Parent known") - p.catchingUp = false - p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) - */ - } else if ethchain.IsValidationErr(err) { - fmt.Println("Err:", err) - p.catchingUp = false - } - } else { - // If we're catching up, try to catch up further. - if p.catchingUp && msg.Data.Len() > 1 { - if lastBlock != nil { - blockInfo := lastBlock.BlockInfo() - peerlogger.DebugDetailf("Synced chain to #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) - } - - p.catchingUp = false - - hash := p.ethereum.BlockChain().CurrentBlock.Hash() - p.CatchupWithPeer(hash) - } - } - case ethwire.MsgTxTy: // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and @@ -501,58 +396,6 @@ func (p *Peer) HandleInbound() { // Connect to the list of peers p.ethereum.ProcessPeerList(peers) - case ethwire.MsgGetChainTy: - var parent *ethchain.Block - // Length minus one since the very last element in the array is a count - l := msg.Data.Len() - 1 - // Ignore empty get chains - if l == 0 { - break - } - - // Amount of parents in the canonical chain - //amountOfBlocks := msg.Data.Get(l).AsUint() - amountOfBlocks := uint64(100) - - // Check each SHA block hash from the message and determine whether - // the SHA is in the database - for i := 0; i < l; i++ { - if data := msg.Data.Get(i).Bytes(); p.ethereum.StateManager().BlockChain().HasBlock(data) { - parent = p.ethereum.BlockChain().GetBlock(data) - break - } - } - - // If a parent is found send back a reply - if parent != nil { - peerlogger.DebugDetailf("Found canonical block, returning chain from: %x ", parent.Hash()) - chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) - if len(chain) > 0 { - //peerlogger.Debugf("Returning %d blocks: %x ", len(chain), parent.Hash()) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) - } else { - p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, []interface{}{})) - } - - } else { - //peerlogger.Debugf("Could not find a similar block") - // If no blocks are found we send back a reply with msg not in chain - // and the last hash from get chain - if l > 0 { - lastHash := msg.Data.Get(l - 1) - //log.Printf("Sending not in chain with hash %x\n", lastHash.AsRaw()) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) - } - } - case ethwire.MsgNotInChainTy: - peerlogger.DebugDetailf("Not in chain: %x\n", msg.Data.Get(0).Bytes()) - if p.diverted == true { - // If were already looking for a common parent and we get here again we need to go deeper - p.blocksRequested = p.blocksRequested * 2 - } - p.diverted = true - p.catchingUp = false - p.FindCommonParentBlock() case ethwire.MsgGetTxsTy: // Get the current transactions of the pool txs := p.ethereum.TxPool().CurrentTransactions() @@ -564,15 +407,103 @@ func (p *Peer) HandleInbound() { // Broadcast it back to the peer p.QueueMessage(ethwire.NewMessage(ethwire.MsgTxTy, txsInterface)) - // Unofficial but fun nonetheless - case ethwire.MsgTalkTy: - peerlogger.Infoln("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str()) + case ethwire.MsgGetBlockHashesTy: + if msg.Data.Len() < 2 { + peerlogger.Debugln("err: argument length invalid ", msg.Data.Len()) + } + + hash := msg.Data.Get(0).Bytes() + amount := msg.Data.Get(1).Uint() + + hashes := p.ethereum.BlockChain().GetChainHashesFromHash(hash, amount) + + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockHashesTy, ethutil.ByteSliceToInterface(hashes))) + + case ethwire.MsgGetBlocksTy: + // Limit to max 300 blocks + max := int(math.Min(float64(msg.Data.Len()), 300.0)) + var blocks []interface{} + + for i := 0; i < max; i++ { + hash := msg.Data.Get(i).Bytes() + block := p.ethereum.BlockChain().GetBlock(hash) + if block != nil { + blocks = append(blocks, block.Value().Raw()) + } + } + + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, blocks)) + + case ethwire.MsgBlockHashesTy: + blockPool := p.ethereum.blockPool + + foundCommonHash := false + + it := msg.Data.NewIterator() + for it.Next() { + hash := it.Value().Bytes() + + if blockPool.HasCommonHash(hash) { + foundCommonHash = true + + break + } + + blockPool.AddHash(hash) + + p.lastReceivedHash = hash + } + + if foundCommonHash { + p.FetchBlocks() + } else { + p.FetchHashes() + } + case ethwire.MsgBlockTy: + blockPool := p.ethereum.blockPool + + it := msg.Data.NewIterator() + + for it.Next() { + block := ethchain.NewBlockFromRlpValue(it.Value()) + blockPool.SetBlock(block) + } + + linked := blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { + p.ethereum.StateManager().Process(block, false) + }) + + if !linked { + p.FetchBlocks() + } } } } + p.Stop() } +func (self *Peer) FetchBlocks() { + blockPool := self.ethereum.blockPool + + hashes := blockPool.Take(100, self) + if len(hashes) > 0 { + self.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlocksTy, ethutil.ByteSliceToInterface(hashes))) + } +} + +func (self *Peer) FetchHashes() { + blockPool := self.ethereum.blockPool + + if self.td.Cmp(blockPool.td) >= 0 { + peerlogger.Debugf("Requesting hashes from %x\n", self.lastReceivedHash) + + if !blockPool.HasLatestHash() { + self.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlockHashesTy, []interface{}{self.lastReceivedHash, uint32(200)})) + } + } +} + // General update method func (self *Peer) update() { serviceTimer := time.NewTicker(5 * time.Second) @@ -643,6 +574,7 @@ func (p *Peer) pushHandshake() error { pubkey := p.ethereum.KeyManager().PublicKey() msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ uint32(ProtocolVersion), uint32(0), []byte(p.version), byte(p.caps), p.port, pubkey[1:], + p.ethereum.BlockChain().TD.Uint64(), p.ethereum.BlockChain().CurrentBlock.Hash(), }) p.QueueMessage(msg) @@ -728,10 +660,15 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.SetVersion(c.Get(2).Str()) } + // Get the td and last hash + p.td = c.Get(6).BigInt() + p.bestHash = c.Get(7).Bytes() + p.lastReceivedHash = p.bestHash + p.ethereum.PushPeer(p) p.ethereum.reactor.Post("peerList", p.ethereum.Peers()) - ethlogger.Infof("Added peer (%s) %d / %d\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers) + ethlogger.Infof("Added peer (%s) %d / %d (TD = %v ~ %x)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, p.td, p.bestHash) /* // Catch up with the connected peer @@ -740,7 +677,12 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { time.Sleep(10 * time.Second) } */ - p.SyncWithPeerToLastKnown() + //p.SyncWithPeerToLastKnown() + + if p.td.Cmp(p.ethereum.BlockChain().TD) > 0 { + p.ethereum.blockPool.AddHash(p.lastReceivedHash) + p.FetchHashes() + } peerlogger.Debugln(p) } From c44f4f32fe9d72634574b909655d159ec153ea7d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 14:52:21 +0200 Subject: [PATCH 60/64] Re-enabled catching up flag --- peer.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/peer.go b/peer.go index 4e6fc55d4..d841b2ad3 100644 --- a/peer.go +++ b/peer.go @@ -435,6 +435,8 @@ func (p *Peer) HandleInbound() { p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, blocks)) case ethwire.MsgBlockHashesTy: + p.catchingUp = true + blockPool := p.ethereum.blockPool foundCommonHash := false @@ -452,6 +454,8 @@ func (p *Peer) HandleInbound() { blockPool.AddHash(hash) p.lastReceivedHash = hash + + p.lastBlockReceived = time.Now() } if foundCommonHash { @@ -459,14 +463,20 @@ func (p *Peer) HandleInbound() { } else { p.FetchHashes() } + case ethwire.MsgBlockTy: + p.catchingUp = true + blockPool := p.ethereum.blockPool it := msg.Data.NewIterator() for it.Next() { block := ethchain.NewBlockFromRlpValue(it.Value()) + blockPool.SetBlock(block) + + p.lastBlockReceived = time.Now() } linked := blockPool.CheckLinkAndProcess(func(block *ethchain.Block) { From b368549fd5d54ca5c73f424273a9d3896ad456a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 15:12:13 +0200 Subject: [PATCH 61/64] Always return something valid --- ethpipe/js_pipe.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go index 8f08a7c5f..b32e94a10 100644 --- a/ethpipe/js_pipe.go +++ b/ethpipe/js_pipe.go @@ -276,6 +276,11 @@ func (self *JSFilter) MessagesToJson(messages ethstate.Messages) string { msgs = append(msgs, NewJSMessage(m)) } + // Return an empty array instead of "null" + if len(msgs) == 0 { + return "[]" + } + b, err := json.Marshal(msgs) if err != nil { return "{\"error\":" + err.Error() + "}" From d90ae4d45bb19b1b4f807b0c3b79a0236c6635ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 15:24:19 +0200 Subject: [PATCH 62/64] Prot 0.6.3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b0f6e07f..17e74892e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 0.6.0". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 0.6.3". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. From 15ef3388c177c59b93c96e9f0663c907d2ad1829 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 15:27:01 +0200 Subject: [PATCH 63/64] Doc --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 17e74892e..3ed340612 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,11 @@ individual package for more information. 3. [ethwire](https://github.com/ethereum/eth-go/tree/master/ethwire) 4. [ethdb](https://github.com/ethereum/eth-go/tree/master/ethdb) 5. [ethutil](https://github.com/ethereum/eth-go/tree/master/ethutil) + 6. [ethpipe](https://github.com/ethereum/eth-go/tree/master/ethpipe) + 7. [ethvm](https://github.com/ethereum/eth-go/tree/master/ethvm) + 8. [ethtrie](https://github.com/ethereum/eth-go/tree/master/ethtrie) + 9. [ethreact](https://github.com/ethereum/eth-go/tree/master/ethreact) + 10. [ethlog](https://github.com/ethereum/eth-go/tree/master/ethlog) The [eth](https://github.com/ethereum/eth-go) is the top-level package of the Ethereum protocol. It functions as the Ethereum bootstrapping and @@ -45,7 +50,7 @@ Contribution If you'd like to contribute to Eth please fork, fix, commit and send a pull request. Commits who do not comply with the coding standards -are ignored. If you send pull requests make absolute sure that you +are ignored (use gofmt!). If you send pull requests make absolute sure that you commit on the `develop` branch and that you do not merge to master. Commits that are directly based on master are simply ignored. From c173e9f4ab463cf3a44d35215bc29d846d6f6b02 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 15:43:14 +0200 Subject: [PATCH 64/64] MIT -> LGPL --- LICENSE | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/LICENSE b/LICENSE index b77f7909a..30f629158 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,16 @@ -The MIT License (MIT) +Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. -Copyright (c) 2013 Jeffrey Wilcke +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301 USA