Commit 0af0f0d8 authored by obscuren's avatar obscuren

Merge branch 'release/0.6.3'

parents d761af84 c173e9f4
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
......@@ -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.
......@@ -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.
......
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
}
......@@ -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()
......
......@@ -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")...))
......
......@@ -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)
......
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
}
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")
}
}
......@@ -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
......
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
}
package ethchain
import "testing"
func TestFilter(t *testing.T) {
filter := NewFilter()
}
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
......
......@@ -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
}
......@@ -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
}
......
......@@ -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 {
......
......@@ -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())
}
......
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 }
......@@ -2,40 +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) {
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))
}
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 {
......@@ -48,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]
......@@ -56,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
......
This diff is collapsed.
This diff is collapsed.
......@@ -3,24 +3,27 @@ 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"
"net/http"
"strconv"
"strings"
"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/ethreact"
"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"
const (
seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt"
seedNodeAddress = "54.76.56.74:30303"
)
var ethlogger = ethlog.NewLogger("SERV")
......@@ -41,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
......@@ -51,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
......@@ -73,7 +78,7 @@ type Ethereum struct {
listening bool
reactor *ethutil.ReactorEngine
reactor *ethreact.ReactorEngine
RpcServer *ethrpc.JsonRpcServer
......@@ -111,8 +116,9 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager
clientIdentity: clientIdentity,
isUpToDate: true,
}
ethereum.reactor = ethutil.NewReactorEngine()
ethereum.reactor = ethreact.New()
ethereum.blockPool = NewBlockPool(ethereum)
ethereum.txPool = ethchain.NewTxPool(ethereum)
ethereum.blockChain = ethchain.NewBlockChain(ethereum)
ethereum.stateManager = ethchain.NewStateManager(ethereum)
......@@ -123,7 +129,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
}
......@@ -146,6 +152,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
......@@ -355,6 +364,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 {
......@@ -420,22 +430,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) {
......@@ -466,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)
......
......@@ -39,7 +39,9 @@ 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 mutex = sync.Mutex{}
type LogLevel uint8
......@@ -52,34 +54,55 @@ const (
DebugDetailLevel
)
func dispatch(msg *logMessage) {
for _, logSystem := range logSystems {
if logSystem.GetLogLevel() >= msg.LogLevel {
msg.send(logSystem)
}
}
}
// log messages are dispatched to log writers
func start() {
out:
for {
select {
case status := <-quit:
status <- nil
return
case msg := <-logMessages:
for _, logSystem := range logSystems {
if logSystem.GetLogLevel() >= msg.LogLevel {
msg.send(logSystem)
}
}
case <-quit:
break out
dispatch(msg)
default:
drained <- true // this blocks until a message is sent to the queue
}
}
}
// waits until log messages are drained (dispatched to log writers)
func Flush() {
quit <- true
func send(msg *logMessage) {
logMessages <- msg
select {
case <-drained:
default:
}
}
done:
for {
func Reset() {
mutex.Lock()
defer mutex.Unlock()
if logSystems != nil {
status := make(chan error)
quit <- status
select {
case <-logMessages:
case <-drained:
default:
break done
}
<-status
}
}
// waits until log messages are drained (dispatched to log writers)
func Flush() {
if logSystems != nil {
<-drained
}
}
......@@ -97,7 +120,8 @@ func AddLogSystem(logSystem LogSystem) {
defer mutex.Unlock()
if logSystems == nil {
logMessages = make(chan *logMessage, 10)
quit = make(chan bool, 1)
quit = make(chan chan error, 1)
drained = make(chan bool, 1)
go start()
}
logSystems = append(logSystems, logSystem)
......@@ -106,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)
}
}
......
......@@ -28,8 +28,19 @@ func (t *TestLogSystem) GetLogLevel() LogLevel {
return t.level
}
func quote(s string) string {
return fmt.Sprintf("'%s'", s)
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) {
......@@ -41,10 +52,11 @@ func TestLoggerPrintln(t *testing.T) {
logger.Infoln("info")
logger.Debugln("debug")
Flush()
Reset()
output := testLogSystem.Output
fmt.Println(quote(output))
if output != "[TEST] error\n[TEST] warn\n" {
t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", quote(testLogSystem.Output))
t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", output)
}
}
......@@ -57,10 +69,10 @@ func TestLoggerPrintf(t *testing.T) {
logger.Infof("info")
logger.Debugf("debug")
Flush()
Reset()
output := testLogSystem.Output
fmt.Println(quote(output))
if output != "[TEST] error to { 2}\n[TEST] warn" {
t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", quote(testLogSystem.Output))
t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", output)
}
}
......@@ -73,13 +85,14 @@ func TestMultipleLogSystems(t *testing.T) {
logger.Errorln("error")
logger.Warnln("warn")
Flush()
Reset()
output0 := testLogSystem0.Output
output1 := testLogSystem1.Output
if output0 != "[TEST] error\n" {
t.Error("Expected logger 0 output '[TEST] error\\n', got ", quote(testLogSystem0.Output))
t.Error("Expected logger 0 output '[TEST] error\\n', got ", output0)
}
if output1 != "[TEST] error\n[TEST] warn\n" {
t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", quote(testLogSystem1.Output))
t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", output1)
}
}
......@@ -94,9 +107,8 @@ func TestFileLogSystem(t *testing.T) {
Flush()
contents, _ := ioutil.ReadFile(filename)
output := string(contents)
fmt.Println(quote(output))
if output != "[TEST] error to test.log\n[TEST] warn\n" {
t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", quote(output))
t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", output)
} else {
os.Remove(filename)
}
......
This diff is collapsed.
package ethpipe
import "github.com/ethereum/eth-go/ethutil"
var cnfCtr = ethutil.Hex2Bytes("661005d2720d855f1d9976f88bb10c1a3398c77f")
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}
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)
}
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
}
This diff is collapsed.
This diff is collapsed.
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))
}
This diff is collapsed.
This diff is collapsed.
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) BlockHash() []byte { return self.block.Hash() }
func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) State() *ethstate.State { return self.state }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment