aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-08-21 21:46:26 +0800
committerobscuren <geffobscura@gmail.com>2014-08-21 21:46:26 +0800
commit0af0f0d890120e007ce42f072e1ee179a62115d3 (patch)
tree5ae9ecafbb729d1636fadfcfa49fd9100959560c /ethchain
parentd761af84c83ae8d9d723e6766abb7950ff59cdf3 (diff)
parentc173e9f4ab463cf3a44d35215bc29d846d6f6b02 (diff)
downloadgo-tangerine-0af0f0d890120e007ce42f072e1ee179a62115d3.tar
go-tangerine-0af0f0d890120e007ce42f072e1ee179a62115d3.tar.gz
go-tangerine-0af0f0d890120e007ce42f072e1ee179a62115d3.tar.bz2
go-tangerine-0af0f0d890120e007ce42f072e1ee179a62115d3.tar.lz
go-tangerine-0af0f0d890120e007ce42f072e1ee179a62115d3.tar.xz
go-tangerine-0af0f0d890120e007ce42f072e1ee179a62115d3.tar.zst
go-tangerine-0af0f0d890120e007ce42f072e1ee179a62115d3.zip
Merge branch 'release/0.6.3'
Diffstat (limited to 'ethchain')
-rw-r--r--ethchain/block.go83
-rw-r--r--ethchain/block_chain.go55
-rw-r--r--ethchain/block_chain_test.go23
-rw-r--r--ethchain/bloom.go47
-rw-r--r--ethchain/bloom_test.go20
-rw-r--r--ethchain/dagger.go5
-rw-r--r--ethchain/filter.go304
-rw-r--r--ethchain/filter_test.go7
-rw-r--r--ethchain/genesis.go6
-rw-r--r--ethchain/state_manager.go72
-rw-r--r--ethchain/state_transition.go36
-rw-r--r--ethchain/transaction.go5
-rw-r--r--ethchain/transaction_pool.go79
-rw-r--r--ethchain/vm_env.go4
14 files changed, 552 insertions, 194 deletions
diff --git a/ethchain/block.go b/ethchain/block.go
index 437525e35..5765abd51 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)
@@ -105,7 +100,7 @@ func CreateBlock(root interface{},
}
block.SetUncles([]*Block{})
- block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, root))
+ block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, root))
return block
}
@@ -130,40 +125,15 @@ 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)
}
- 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)
@@ -172,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 {
@@ -252,26 +209,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()))
}
@@ -313,7 +254,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.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()
@@ -355,7 +296,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.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/block_chain.go b/ethchain/block_chain.go
index 1a2662787..3445bbb87 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")
@@ -131,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))
@@ -144,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))
@@ -158,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
}
}
@@ -207,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{}
@@ -280,7 +301,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)
}
}
@@ -289,7 +310,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()
@@ -300,9 +320,8 @@ 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()
+ 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)
@@ -338,6 +357,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/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/bloom.go b/ethchain/bloom.go
new file mode 100644
index 000000000..5317ca0b1
--- /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, 256)
+ }
+
+ 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/dagger.go b/ethchain/dagger.go
index dccd2ff5b..917b3d722 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
GetHashrate() int64
}
@@ -28,7 +29,7 @@ func (pow *EasyPow) GetHashrate() int64 {
return pow.HashRate
}
-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/filter.go b/ethchain/filter.go
new file mode 100644
index 000000000..5ed9af977
--- /dev/null
+++ b/ethchain/filter.go
@@ -0,0 +1,304 @@
+package ethchain
+
+import (
+ "bytes"
+ "fmt"
+
+ "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
+ earliest []byte
+ latest []byte
+ 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
+// is interesting or not.
+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))
+ }
+
+ if object["altered"] != nil {
+ filter.altered = makeAltered(object["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
+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) 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.to = append(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
+ }
+
+ messages = append(messages, self.FilterMessages(msgs)...)
+ }
+
+ block = self.eth.BlockChain().GetBlock(block.PrevHash)
+ }
+
+ 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
+
+ // 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
+ }
+
+ 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)
+ }
+
+ 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)
+
+ var fromIncluded, toIncluded bool
+ if len(self.from) > 0 {
+ for _, from := range self.from {
+ if bloom.Search(from) {
+ fromIncluded = true
+ break
+ }
+ }
+ } else {
+ fromIncluded = true
+ }
+
+ if len(self.to) > 0 {
+ for _, to := range self.to {
+ if bloom.Search(to) {
+ toIncluded = true
+ break
+ }
+ }
+ } else {
+ toIncluded = true
+ }
+
+ 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/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/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/ethchain/state_manager.go b/ethchain/state_manager.go
index 9408cf331..08bd22d29 100644
--- a/ethchain/state_manager.go
+++ b/ethchain/state_manager.go
@@ -4,14 +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")
@@ -36,13 +38,14 @@ 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
Peers() *list.List
KeyManager() *ethcrypto.KeyManager
ClientIdentity() ethwire.ClientIdentity
+ Db() ethutil.Database
}
type StateManager struct {
@@ -233,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 {
@@ -361,14 +369,56 @@ func (sm *StateManager) Stop() {
sm.bc.Stop()
}
-func (sm *StateManager) notifyChanges(state *ethstate.State) {
- for addr, stateObject := range state.Manifest().ObjectChanges {
- sm.Ethereum.Reactor().Post("object:"+addr, stateObject)
+// 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 _, msg := range state.Manifest().Messages {
+ bloomf.Set(msg.To)
+ bloomf.Set(msg.From)
}
- for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges {
- for addr, value := range mappedObjects {
- sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &ethstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value})
+ sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages)
+
+ /*
+ 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, &ethstate.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()
+
+ sm.ApplyDiff(state, parent, block)
+
+ sm.AccumelateRewards(state, block)
+
+ return state.Manifest().Messages, nil
}
diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go
index 266328ce8..9fbc160a5 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
@@ -210,6 +211,14 @@ func (self *StateTransition) TransitionState() (err error) {
snapshot = self.state.Copy()
}
+ msg := self.state.Manifest().AddMessage(&ethstate.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,
+ Value: self.value,
+ })
+
// Process the init code and create 'valid' contract
if IsContractAddr(self.receiver) {
// Evaluate the initialization script
@@ -217,7 +226,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)
@@ -225,14 +234,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(msg, receiver.Code, receiver, "code")
if err != nil {
self.state.Set(snapshot)
return fmt.Errorf("Error during code execution %v", err)
}
+
+ msg.Output = ret
}
}
@@ -240,8 +252,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
@@ -252,12 +264,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)
@@ -277,7 +289,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.New(ethtrie.New(ethutil.Config.Db, ""))
return contract
}
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 {
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/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 }