Ver código fonte

PoC 7 updates

* Bloom
* Block restructure
* Receipts
obscuren 11 anos atrás
pai
commit
fb4113dab4

+ 75 - 69
ethchain/block.go

@@ -96,9 +96,10 @@ type Block struct {
 	// Block Nonce for verification
 	Nonce ethutil.Bytes
 	// List of transactions and/or contracts
-	transactions []*Transaction
-	receipts     []*Receipt
-	TxSha        []byte
+	transactions      Transactions
+	receipts          Receipts
+	TxSha, ReceiptSha []byte
+	LogsBloom         []byte
 }
 
 func NewBlockFromBytes(raw []byte) *Block {
@@ -151,7 +152,7 @@ func (block *Block) Hash() ethutil.Bytes {
 func (block *Block) HashNoNonce() []byte {
 	return ethcrypto.Sha3(ethutil.Encode([]interface{}{block.PrevHash,
 		block.UncleSha, block.Coinbase, block.state.Trie.Root,
-		block.TxSha, block.Difficulty, block.Number, block.MinGasPrice,
+		block.ReceiptSha, block.Difficulty, block.Number, block.MinGasPrice,
 		block.GasLimit, block.GasUsed, block.Time, block.Extra}))
 }
 
@@ -191,9 +192,9 @@ func (block *Block) BlockInfo() BlockInfo {
 }
 
 func (self *Block) GetTransaction(hash []byte) *Transaction {
-	for _, receipt := range self.receipts {
-		if bytes.Compare(receipt.Tx.Hash(), hash) == 0 {
-			return receipt.Tx
+	for _, tx := range self.transactions {
+		if bytes.Compare(tx.Hash(), hash) == 0 {
+			return tx
 		}
 	}
 
@@ -236,10 +237,7 @@ func (block *Block) rlpUncles() interface{} {
 func (block *Block) SetUncles(uncles []*Block) {
 	block.Uncles = uncles
 
-	// Sha of the concatenated uncles
-	if len(uncles) > 0 {
-		block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles()))
-	}
+	block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles()))
 }
 
 func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) {
@@ -249,32 +247,20 @@ func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) {
 
 func (block *Block) setTransactions(txs []*Transaction) {
 	block.transactions = txs
-}
-
-func CreateTxSha(receipts Receipts) (sha []byte) {
-	trie := ethtrie.New(ethutil.Config.Db, "")
-	for i, receipt := range receipts {
-		trie.Update(string(ethutil.NewValue(i).Encode()), string(ethutil.NewValue(receipt.RlpData()).Encode()))
-	}
 
-	switch trie.Root.(type) {
-	case string:
-		sha = []byte(trie.Root.(string))
-	case []byte:
-		sha = trie.Root.([]byte)
-	default:
-		panic(fmt.Sprintf("invalid root type %T", trie.Root))
-	}
+	block.LogsBloom = CreateBloom(txs)
+}
 
-	return sha
+func (self *Block) SetTransactionHash(transactions Transactions) {
+	self.TxSha = DeriveSha(transactions)
 }
 
-func (self *Block) SetTxHash(receipts Receipts) {
-	self.TxSha = CreateTxSha(receipts)
+func (self *Block) SetReceiptHash(receipts Receipts) {
+	self.ReceiptSha = DeriveSha(receipts)
 }
 
 func (block *Block) Value() *ethutil.Value {
-	return ethutil.NewValue([]interface{}{block.header(), block.rlpReceipts(), block.rlpUncles()})
+	return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()})
 }
 
 func (block *Block) RlpEncode() []byte {
@@ -289,33 +275,20 @@ func (block *Block) RlpDecode(data []byte) {
 }
 
 func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
-	header := decoder.Get(0)
-
-	block.PrevHash = header.Get(0).Bytes()
-	block.UncleSha = header.Get(1).Bytes()
-	block.Coinbase = header.Get(2).Bytes()
-	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()
-	//fmt.Printf("#%v : %x\n", block.Number, block.Coinbase)
-	block.MinGasPrice = header.Get(7).BigInt()
-	block.GasLimit = header.Get(8).BigInt()
-	block.GasUsed = header.Get(9).BigInt()
-	block.Time = int64(header.Get(10).BigInt().Uint64())
-	block.Extra = header.Get(11).Str()
-	block.Nonce = header.Get(12).Bytes()
+	block.setHeader(decoder.Get(0))
 
 	// Tx list might be empty if this is an uncle. Uncles only have their
 	// header set.
 	if decoder.Get(1).IsNil() == false { // Yes explicitness
-		receipts := decoder.Get(1)
-		block.transactions = make([]*Transaction, receipts.Len())
-		block.receipts = make([]*Receipt, receipts.Len())
-		for i := 0; i < receipts.Len(); i++ {
-			receipt := NewRecieptFromValue(receipts.Get(i))
-			block.transactions[i] = receipt.Tx
-			block.receipts[i] = receipt
+		//receipts := decoder.Get(1)
+		//block.receipts = make([]*Receipt, receipts.Len())
+		it := decoder.Get(1).NewIterator()
+		block.transactions = make(Transactions, it.Len())
+		for it.Next() {
+			block.transactions[it.Idx()] = NewTransactionFromValue(it.Value())
+			//receipt := NewRecieptFromValue(receipts.Get(i))
+			//block.transactions[i] = receipt.Tx
+			//block.receipts[i] = receipt
 		}
 
 	}
@@ -330,22 +303,27 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
 
 }
 
+func (self *Block) setHeader(header *ethutil.Value) {
+	self.PrevHash = header.Get(0).Bytes()
+	self.UncleSha = header.Get(1).Bytes()
+	self.Coinbase = header.Get(2).Bytes()
+	self.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val))
+	self.TxSha = header.Get(4).Bytes()
+	self.ReceiptSha = header.Get(5).Bytes()
+	self.LogsBloom = header.Get(6).Bytes()
+	self.Difficulty = header.Get(7).BigInt()
+	self.Number = header.Get(8).BigInt()
+	self.MinGasPrice = header.Get(9).BigInt()
+	self.GasLimit = header.Get(10).BigInt()
+	self.GasUsed = header.Get(11).BigInt()
+	self.Time = int64(header.Get(12).BigInt().Uint64())
+	self.Extra = header.Get(13).Str()
+	self.Nonce = header.Get(14).Bytes()
+}
+
 func NewUncleBlockFromValue(header *ethutil.Value) *Block {
 	block := &Block{}
-
-	block.PrevHash = header.Get(0).Bytes()
-	block.UncleSha = header.Get(1).Bytes()
-	block.Coinbase = header.Get(2).Bytes()
-	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()
-	block.MinGasPrice = header.Get(7).BigInt()
-	block.GasLimit = header.Get(8).BigInt()
-	block.GasUsed = header.Get(9).BigInt()
-	block.Time = int64(header.Get(10).BigInt().Uint64())
-	block.Extra = header.Get(11).Str()
-	block.Nonce = header.Get(12).Bytes()
+	block.setHeader(header)
 
 	return block
 }
@@ -376,8 +354,12 @@ func (block *Block) header() []interface{} {
 		block.Coinbase,
 		// root state
 		block.state.Trie.Root,
-		// Sha of tx
+		// tx root
 		block.TxSha,
+		// Sha of tx
+		block.ReceiptSha,
+		// Bloom
+		block.LogsBloom,
 		// Current block Difficulty
 		block.Difficulty,
 		// The block number
@@ -404,7 +386,9 @@ func (block *Block) String() string {
 	UncleSha:   %x
 	Coinbase:   %x
 	Root:       %x
-	TxSha:      %x
+	TxSha       %x
+	ReceiptSha: %x
+	Bloom:      %x
 	Difficulty: %v
 	Number:     %v
 	MinGas:     %v
@@ -422,6 +406,8 @@ func (block *Block) String() string {
 		block.Coinbase,
 		block.state.Trie.Root,
 		block.TxSha,
+		block.ReceiptSha,
+		block.LogsBloom,
 		block.Difficulty,
 		block.Number,
 		block.MinGasPrice,
@@ -437,3 +423,23 @@ func (block *Block) String() string {
 func (self *Block) Size() ethutil.StorageSize {
 	return ethutil.StorageSize(len(self.RlpEncode()))
 }
+
+/*
+func DeriveReceiptHash(receipts Receipts) (sha []byte) {
+	trie := ethtrie.New(ethutil.Config.Db, "")
+	for i, receipt := range receipts {
+		trie.Update(string(ethutil.NewValue(i).Encode()), string(ethutil.NewValue(receipt.RlpData()).Encode()))
+	}
+
+	switch trie.Root.(type) {
+	case string:
+		sha = []byte(trie.Root.(string))
+	case []byte:
+		sha = trie.Root.([]byte)
+	default:
+		panic(fmt.Sprintf("invalid root type %T", trie.Root))
+	}
+
+	return sha
+}
+*/

+ 19 - 12
ethchain/bloom9.go

@@ -1,37 +1,44 @@
 package ethchain
 
-import "github.com/ethereum/go-ethereum/vm"
+import (
+	"math/big"
 
-func CreateBloom(txs Transactions) uint64 {
-	var bin uint64
+	"github.com/ethereum/go-ethereum/vm"
+)
+
+func CreateBloom(txs Transactions) []byte {
+	bin := new(big.Int)
 	for _, tx := range txs {
-		bin |= logsBloom(tx.logs)
+		bin.Or(bin, LogsBloom(tx.logs))
 	}
 
-	return bin
+	return bin.Bytes()
 }
 
-func logsBloom(logs []vm.Log) uint64 {
-	var bin uint64
+func LogsBloom(logs []vm.Log) *big.Int {
+	bin := new(big.Int)
 	for _, log := range logs {
 		data := [][]byte{log.Address}
 		for _, topic := range log.Topics {
-			data = append(data, topic.Bytes())
+			data = append(data, topic)
 		}
 		data = append(data, log.Data)
 
 		for _, b := range data {
-			bin |= bloom9(b)
+			bin.Or(bin, bloom9(b))
 		}
 	}
 
 	return bin
 }
 
-func bloom9(b []byte) uint64 {
-	var r uint64
+func bloom9(b []byte) *big.Int {
+	r := new(big.Int)
 	for _, i := range []int{0, 2, 4} {
-		r |= 1 << (uint64(b[i+1]) + 256*(uint64(b[i])&1))
+		t := big.NewInt(1)
+
+		//r |= 1 << (uint64(b[i+1]) + 256*(uint64(b[i])&1))
+		r.Or(r, t.Rsh(t, uint(b[i+1])+256*(uint(b[i])&1)))
 	}
 
 	return r

+ 2 - 2
ethchain/chain_manager.go

@@ -87,8 +87,8 @@ func (bc *ChainManager) Reset() {
 	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))
+	//fk := append([]byte("bloom"), bc.genesisBlock.Hash()...)
+	//bc.Ethereum.Db().Put(fk, make([]byte, 255))
 	bc.CurrentBlock = bc.genesisBlock
 
 	bc.SetTotalDifficulty(ethutil.Big("0"))

+ 8 - 8
ethchain/filter.go

@@ -2,7 +2,6 @@ package ethchain
 
 import (
 	"bytes"
-	"fmt"
 	"math"
 
 	"github.com/ethereum/go-ethereum/ethstate"
@@ -171,13 +170,14 @@ func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message
 }
 
 func (self *Filter) bloomFilter(block *Block) bool {
-	fk := append([]byte("bloom"), block.Hash()...)
-	bin, err := self.eth.Db().Get(fk)
-	if err != nil {
-		fmt.Println(err)
-	}
-
-	bloom := NewBloomFilter(bin)
+	//fk := append([]byte("bloom"), block.Hash()...)
+	//bin, err := self.eth.Db().Get(fk)
+	//if err != nil {
+	//	fmt.Println(err)
+	//}
+
+	// TODO update to the new bloom filter
+	bloom := NewBloomFilter(nil)
 
 	var fromIncluded, toIncluded bool
 	if len(self.from) > 0 {

+ 8 - 3
ethchain/genesis.go

@@ -13,19 +13,24 @@ import (
 
 var ZeroHash256 = make([]byte, 32)
 var ZeroHash160 = make([]byte, 20)
+var ZeroHash512 = make([]byte, 64)
 var EmptyShaList = ethcrypto.Sha3(ethutil.Encode([]interface{}{}))
 
 var GenesisHeader = []interface{}{
 	// Previous hash (none)
 	ZeroHash256,
 	// Empty uncles
-	"",
+	EmptyShaList,
 	// Coinbase
 	ZeroHash160,
 	// Root state
-	"",
+	EmptyShaList,
 	// tx sha
-	"",
+	EmptyShaList,
+	// receipt list
+	EmptyShaList,
+	// bloom
+	ZeroHash512,
 	// Difficulty
 	//ethutil.BigPow(2, 22),
 	big.NewInt(131072),

+ 17 - 9
ethchain/state_manager.go

@@ -173,8 +173,9 @@ done:
 		state.Update()
 
 		txGas.Sub(txGas, st.gas)
-		accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
-		receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative}
+		cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
+		//receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative}
+		receipt := &Receipt{ethutil.CopyBytes(state.Root().([]byte)), cumulative, LogsBloom(tx.logs).Bytes(), tx.logs}
 
 		if i < len(block.Receipts()) {
 			original := block.Receipts()[i]
@@ -183,7 +184,7 @@ done:
 					os.Exit(1)
 				}
 
-				err := fmt.Errorf("#%d receipt failed (r) %v ~ %x  <=>  (c) %v ~ %x (%x...)", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()[0:4])
+				err := fmt.Errorf("#%d receipt failed (r) %v ~ %x  <=>  (c) %v ~ %x (%x...)", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], tx.Hash()[0:4])
 
 				return nil, nil, nil, nil, err
 			}
@@ -235,14 +236,19 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
 		fmt.Printf("## %x %x ##\n", block.Hash(), block.Number)
 	}
 
+	txSha := DeriveSha(block.transactions)
+	if bytes.Compare(txSha, block.TxSha) != 0 {
+		return fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.ReceiptSha, txSha)
+	}
+
 	receipts, err := sm.ApplyDiff(state, parent, block)
 	if err != nil {
 		return err
 	}
 
-	txSha := CreateTxSha(receipts)
-	if bytes.Compare(txSha, block.TxSha) != 0 {
-		return fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha)
+	receiptSha := DeriveSha(receipts)
+	if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
+		return fmt.Errorf("Error validating receipt sha. Received %x, got %x", block.ReceiptSha, receiptSha)
 	}
 
 	// Block validation
@@ -271,13 +277,15 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
 		// Add the block to the chain
 		sm.bc.Add(block)
 
+		// TODO at this point we should also insert LOGS in to a database
+
 		sm.transState = state.Copy()
 
 		// Create a bloom bin for this block
-		filter := sm.createBloomFilter(state)
+		//filter := sm.createBloomFilter(state)
 		// Persist the data
-		fk := append([]byte("bloom"), block.Hash()...)
-		sm.eth.Db().Put(fk, filter.Bin())
+		//fk := append([]byte("bloom"), block.Hash()...)
+		//sm.eth.Db().Put(fk, filter.Bin())
 
 		statelogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4])
 		if dontReact == false {

+ 2 - 8
ethchain/state_transition.go

@@ -5,7 +5,6 @@ import (
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/ethstate"
-	"github.com/ethereum/go-ethereum/ethtrie"
 	"github.com/ethereum/go-ethereum/ethutil"
 	"github.com/ethereum/go-ethereum/vm"
 )
@@ -231,11 +230,9 @@ func (self *StateTransition) TransitionState() (err error) {
 
 			msg.Output = ret
 		} else {
-			// Add default LOG
-			// PUSH1 1 CALLER ADD LOG1
+			// Add default LOG. Default = big(sender.addr) + 1
 			addr := ethutil.BigD(sender.Address())
-			addr.Add(addr, ethutil.Big1)
-			tx.addLog(vm.Log{sender.Address(), []*big.Int{addr}, nil})
+			tx.addLog(vm.Log{sender.Address(), [][]byte{addr.Add(addr, ethutil.Big1).Bytes()}, nil})
 		}
 	}
 
@@ -250,9 +247,7 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context
 		callerClosure = vm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice)
 	)
 
-	//vm := vm.New(env, vm.Type(ethutil.Config.VmType))
 	evm := vm.New(env, vm.DebugVmTy)
-
 	ret, _, err = callerClosure.Call(evm, self.tx.Data)
 
 	return
@@ -264,7 +259,6 @@ func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject
 
 	contract := state.GetOrNewStateObject(addr)
 	contract.InitCode = tx.Data
-	contract.State = ethstate.New(ethtrie.New(ethutil.Config.Db, ""))
 
 	return contract
 }

+ 33 - 19
ethchain/transaction.go

@@ -113,7 +113,8 @@ func (tx *Transaction) PublicKey() []byte {
 	sig := append(r, s...)
 	sig = append(sig, tx.v-27)
 
-	pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
+	pubkey := ethcrypto.Ecrecover(append(hash, sig...))
+	//pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
 
 	return pubkey
 }
@@ -208,11 +209,11 @@ func (tx *Transaction) String() string {
 }
 
 type Receipt struct {
-	Tx                *Transaction
 	PostState         []byte
 	CumulativeGasUsed *big.Int
+	Bloom             []byte
+	Logs              vm.Logs
 }
-type Receipts []*Receipt
 
 func NewRecieptFromValue(val *ethutil.Value) *Receipt {
 	r := &Receipt{}
@@ -222,25 +223,22 @@ func NewRecieptFromValue(val *ethutil.Value) *Receipt {
 }
 
 func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) {
-	self.Tx = NewTransactionFromValue(decoder.Get(0))
-	self.PostState = decoder.Get(1).Bytes()
-	self.CumulativeGasUsed = decoder.Get(2).BigInt()
+	self.PostState = decoder.Get(0).Bytes()
+	self.CumulativeGasUsed = decoder.Get(1).BigInt()
+	self.Bloom = decoder.Get(2).Bytes()
+
+	it := decoder.Get(3).NewIterator()
+	for it.Next() {
+		self.Logs = append(self.Logs, vm.NewLogFromValue(it.Value()))
+	}
 }
 
 func (self *Receipt) RlpData() interface{} {
-	return []interface{}{self.Tx.RlpData(), self.PostState, self.CumulativeGasUsed}
+	return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.Logs.RlpData()}
 }
 
-func (self *Receipt) String() string {
-	return fmt.Sprintf(`
-	R
-	Tx:[                 %v]
-	PostState:           0x%x
-	CumulativeGasUsed:   %v
-	`,
-		self.Tx,
-		self.PostState,
-		self.CumulativeGasUsed)
+func (self *Receipt) RlpEncode() []byte {
+	return ethutil.Encode(self.RlpData())
 }
 
 func (self *Receipt) Cmp(other *Receipt) bool {
@@ -251,11 +249,27 @@ func (self *Receipt) Cmp(other *Receipt) bool {
 	return true
 }
 
+type Receipts []*Receipt
+
+func (self Receipts) Len() int            { return len(self) }
+func (self Receipts) GetRlp(i int) []byte { return ethutil.Rlp(self[i]) }
+
 // Transaction slice type for basic sorting
 type Transactions []*Transaction
 
-func (s Transactions) Len() int      { return len(s) }
-func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (self Transactions) RlpData() interface{} {
+	// Marshal the transactions of this block
+	enc := make([]interface{}, len(self))
+	for i, tx := range self {
+		// Cast it to a string (safe)
+		enc[i] = tx.RlpData()
+	}
+
+	return enc
+}
+func (s Transactions) Len() int            { return len(s) }
+func (s Transactions) Swap(i, j int)       { s[i], s[j] = s[j], s[i] }
+func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) }
 
 type TxByNonce struct{ Transactions }
 

+ 1 - 1
ethminer/miner.go

@@ -187,7 +187,7 @@ func (self *Miner) mineNewBlock() {
 	}
 	self.ethereum.TxPool().RemoveSet(erroneous)
 	self.txs = append(txs, unhandledTxs...)
-	self.block.SetTxHash(receipts)
+	self.block.SetReceiptHash(receipts)
 
 	// Set the transactions to the block so the new SHA3 can be calculated
 	self.block.SetReceipts(receipts, txs)

+ 11 - 0
ethtrie/trie.go

@@ -219,6 +219,17 @@ func (t *Trie) Delete(key string) {
 	}
 }
 
+func (self *Trie) GetRoot() []byte {
+	switch self.Root.(type) {
+	case string:
+		return []byte(self.Root.(string))
+	case []byte:
+		return self.Root.([]byte)
+	default:
+		panic(fmt.Sprintf("invalid root type %T", self.Root))
+	}
+}
+
 // Simple compare function which creates a rlp value out of the evaluated objects
 func (t *Trie) Cmp(trie *Trie) bool {
 	return ethutil.NewValue(t.Root).Cmp(ethutil.NewValue(trie.Root))

+ 6 - 0
ethutil/rlp.go

@@ -15,6 +15,10 @@ type RlpEncodeDecode interface {
 	RlpValue() []interface{}
 }
 
+type RlpEncodable interface {
+	RlpData() interface{}
+}
+
 func Rlp(encoder RlpEncode) []byte {
 	return encoder.RlpEncode()
 }
@@ -100,6 +104,8 @@ func Encode(object interface{}) []byte {
 		switch t := object.(type) {
 		case *Value:
 			buff.Write(Encode(t.Raw()))
+		case RlpEncodable:
+			buff.Write(Encode(t.RlpData()))
 		// Code dup :-/
 		case int:
 			buff.Write(Encode(big.NewInt(int64(t))))

+ 4 - 0
ethutil/value.go

@@ -377,6 +377,10 @@ func (val *Value) NewIterator() *ValueIterator {
 	return &ValueIterator{value: val}
 }
 
+func (it *ValueIterator) Len() int {
+	return it.value.Len()
+}
+
 func (it *ValueIterator) Next() bool {
 	if it.idx >= it.value.Len() {
 		return false

+ 31 - 2
vm/log.go

@@ -1,9 +1,38 @@
 package vm
 
-import "math/big"
+import "github.com/ethereum/go-ethereum/ethutil"
 
 type Log struct {
 	Address []byte
-	Topics  []*big.Int
+	Topics  [][]byte
 	Data    []byte
 }
+
+func NewLogFromValue(decoder *ethutil.Value) Log {
+	log := Log{
+		Address: decoder.Get(0).Bytes(),
+		Data:    decoder.Get(2).Bytes(),
+	}
+
+	it := decoder.Get(1).NewIterator()
+	for it.Next() {
+		log.Topics = append(log.Topics, it.Value().Bytes())
+	}
+
+	return log
+}
+
+func (self Log) RlpData() interface{} {
+	return []interface{}{self.Address, ethutil.ByteSliceToInterface(self.Topics), self.Data}
+}
+
+type Logs []Log
+
+func (self Logs) RlpData() interface{} {
+	data := make([]interface{}, len(self))
+	for i, log := range self {
+		data[i] = log.RlpData()
+	}
+
+	return data
+}

+ 2 - 2
vm/vm_debug.go

@@ -704,11 +704,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) {
 			self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes())
 		case LOG0, LOG1, LOG2, LOG3, LOG4:
 			n := int(op - LOG0)
-			topics := make([]*big.Int, n)
+			topics := make([][]byte, n)
 			mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64()
 			data := mem.Geti(mStart, mSize)
 			for i := 0; i < n; i++ {
-				topics[i] = stack.Pop()
+				topics[i] = stack.Pop().Bytes()
 			}
 			self.env.AddLog(Log{closure.Address(), topics, data})
 		case MLOAD: