Commit 839bd73f authored by obscuren's avatar obscuren

Merge branch 'release/0.3.0'

parents 30ee32a7 3f7ec1a8
The MIT License (MIT)
Copyright (c) 2013 Geff Obscura
Copyright (c) 2013 Jeffrey Wilcke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type Address struct {
Amount *big.Int
Nonce uint64
}
func NewAddress(amount *big.Int) *Address {
return &Address{Amount: amount, Nonce: 0}
}
func NewAddressFromData(data []byte) *Address {
address := &Address{}
address.RlpDecode(data)
return address
}
func (a *Address) AddFee(fee *big.Int) {
a.Amount.Add(a.Amount, fee)
}
func (a *Address) RlpEncode() []byte {
return ethutil.Encode([]interface{}{a.Amount, a.Nonce})
}
func (a *Address) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
a.Amount = decoder.Get(0).BigInt()
a.Nonce = decoder.Get(1).Uint()
}
type AddrStateStore struct {
states map[string]*AddressState
}
func NewAddrStateStore() *AddrStateStore {
return &AddrStateStore{states: make(map[string]*AddressState)}
}
func (s *AddrStateStore) Add(addr []byte, account *Address) *AddressState {
state := &AddressState{Nonce: account.Nonce, Account: account}
s.states[string(addr)] = state
return state
}
func (s *AddrStateStore) Get(addr []byte) *AddressState {
return s.states[string(addr)]
}
type AddressState struct {
Nonce uint64
Account *Address
}
package ethchain
import (
"testing"
)
func TestAddressState(t *testing.T) {
}
......@@ -46,6 +46,8 @@ type Block struct {
// List of transactions and/or contracts
transactions []*Transaction
TxSha []byte
contractStates map[string]*ethutil.Trie
}
// New block takes a raw encoded string
......@@ -79,14 +81,15 @@ func CreateBlock(root interface{},
block := &Block{
// Slice of transactions to include in this block
transactions: txes,
PrevHash: prevHash,
Coinbase: base,
Difficulty: Difficulty,
Nonce: Nonce,
Time: time.Now().Unix(),
Extra: extra,
UncleSha: EmptyShaList,
transactions: txes,
PrevHash: prevHash,
Coinbase: base,
Difficulty: Difficulty,
Nonce: Nonce,
Time: time.Now().Unix(),
Extra: extra,
UncleSha: EmptyShaList,
contractStates: make(map[string]*ethutil.Trie),
}
block.SetTransactions(txes)
block.SetUncles([]*Block{})
......@@ -128,14 +131,26 @@ func (block *Block) GetContract(addr []byte) *Contract {
return nil
}
value := ethutil.NewValueFromBytes([]byte(data))
if value.Len() == 2 {
return nil
}
contract := &Contract{}
contract.RlpDecode([]byte(data))
cachedState := block.contractStates[string(addr)]
if cachedState != nil {
contract.state = cachedState
} else {
block.contractStates[string(addr)] = contract.state
}
return contract
}
func (block *Block) UpdateContract(addr []byte, contract *Contract) {
// Make sure the state is synced
contract.State().Sync()
//contract.State().Sync()
block.state.Update(string(addr), string(contract.RlpEncode()))
}
......@@ -190,18 +205,29 @@ func (block *Block) BlockInfo() BlockInfo {
return bi
}
// Sync the block's state and contract respectively
func (block *Block) Sync() {
// Sync all contracts currently in cache
for _, val := range block.contractStates {
val.Sync()
}
// Sync the block state itself
block.state.Sync()
}
func (block *Block) Undo() {
// Sync all contracts currently in cache
for _, val := range block.contractStates {
val.Undo()
}
// Sync the block state itself
block.state.Undo()
}
func (block *Block) MakeContract(tx *Transaction) {
// Create contract if there's no recipient
if tx.IsContract() {
addr := tx.Hash()
value := tx.Value
contract := NewContract(value, []byte(""))
block.state.Update(string(addr), string(contract.RlpEncode()))
for i, val := range tx.Data {
contract.state.Update(string(ethutil.NumberToBytes(uint64(i), 32)), val)
}
block.UpdateContract(addr, contract)
contract := MakeContract(tx, NewState(block.state))
if contract != nil {
block.contractStates[string(tx.Hash()[12:])] = contract.state
}
}
......@@ -288,6 +314,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
block.Time = int64(header.Get(6).BigInt().Uint64())
block.Extra = header.Get(7).Str()
block.Nonce = header.Get(8).Bytes()
block.contractStates = make(map[string]*ethutil.Trie)
// Tx list might be empty if this is an uncle. Uncles only have their
// header set.
......@@ -298,12 +325,6 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
tx := NewTransactionFromValue(txes.Get(i))
block.transactions[i] = tx
/*
if ethutil.Config.Debug {
ethutil.Config.Db.Put(tx.Hash(), ethutil.Encode(tx))
}
*/
}
}
......@@ -335,7 +356,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
}
func (block *Block) String() string {
return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce)
return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
}
//////////// UNEXPORTED /////////////////
......
......@@ -104,7 +104,6 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} {
currentHash = block.PrevHash
chain = append(chain, block.Value().Val)
//chain = append([]interface{}{block.RlpValue().Value}, chain...)
num--
}
......@@ -112,6 +111,24 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} {
return chain
}
func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block {
genHash := bc.genesisBlock.Hash()
block := bc.GetBlock(hash)
var blocks []*Block
for i := 0; i < amount && block != nil; block = bc.GetBlock(block.PrevHash) {
blocks = append([]*Block{block}, blocks...)
if bytes.Compare(genHash, block.Hash()) == 0 {
break
}
i++
}
return blocks
}
func (bc *BlockChain) setLastBlock() {
data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
if len(data) != 0 {
......@@ -141,11 +158,16 @@ func (bc *BlockChain) Add(block *Block) {
bc.CurrentBlock = block
bc.LastBlockHash = block.Hash()
ethutil.Config.Db.Put(block.Hash(), block.RlpEncode())
encodedBlock := block.RlpEncode()
ethutil.Config.Db.Put(block.Hash(), encodedBlock)
ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
}
func (bc *BlockChain) GetBlock(hash []byte) *Block {
data, _ := ethutil.Config.Db.Get(hash)
if len(data) == 0 {
return nil
}
return NewBlockFromData(data)
}
......@@ -177,8 +199,6 @@ func (bc *BlockChain) writeBlockInfo(block *Block) {
func (bc *BlockChain) Stop() {
if bc.CurrentBlock != nil {
ethutil.Config.Db.Put([]byte("LastBlock"), bc.CurrentBlock.RlpEncode())
log.Println("[CHAIN] Stopped")
}
}
This diff is collapsed.
package ethchain
/*
import (
_ "fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
func TestVm(t *testing.T) {
InitFees()
db, _ := NewMemDatabase()
Db = db
ctrct := NewTransaction("", 200000000, []string{
"PUSH", "1a2f2e",
"PUSH", "hallo",
"POP", // POP hallo
"PUSH", "3",
"LOAD", // Load hallo back on the stack
"PUSH", "1",
"PUSH", "2",
"ADD",
"PUSH", "2",
"PUSH", "1",
"SUB",
"PUSH", "100000000000000000000000",
"PUSH", "10000000000000",
"SDIV",
"PUSH", "105",
"PUSH", "200",
"MOD",
"PUSH", "100000000000000000000000",
"PUSH", "10000000000000",
"SMOD",
"PUSH", "5",
"PUSH", "10",
"LT",
"PUSH", "5",
"PUSH", "5",
"LE",
"PUSH", "50",
"PUSH", "5",
"GT",
"PUSH", "5",
"PUSH", "5",
"GE",
"PUSH", "10",
"PUSH", "10",
"NOT",
"MYADDRESS",
"TXSENDER",
"STOP",
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
ethutil.Config.Db = db
bm := NewBlockManager(nil)
block := bm.bc.genesisBlock
script := Compile([]string{
"PUSH",
"1",
"PUSH",
"2",
})
tx := NewTransaction("1e8a42ea8cce13", 100, []string{})
block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx})
db.Put(block.Hash(), block.RlpEncode())
tx := NewTransaction(ContractAddr, big.NewInt(200000000), script)
addr := tx.Hash()[12:]
bm.ApplyTransactions(block, []*Transaction{tx})
bm := NewBlockManager()
bm.ProcessBlock(block)
tx2 := NewTransaction(addr, big.NewInt(1e17), nil)
tx2.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
bm.ApplyTransactions(block, []*Transaction{tx2})
}
*/
......@@ -30,37 +30,42 @@ func (c *Contract) RlpDecode(data []byte) {
c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())
}
func (c *Contract) State() *ethutil.Trie {
return c.state
}
type Address struct {
Amount *big.Int
Nonce uint64
func (c *Contract) Addr(addr []byte) *ethutil.Value {
return ethutil.NewValueFromBytes([]byte(c.state.Get(string(addr))))
}
func NewAddress(amount *big.Int) *Address {
return &Address{Amount: amount, Nonce: 0}
func (c *Contract) SetAddr(addr []byte, value interface{}) {
c.state.Update(string(addr), string(ethutil.NewValue(value).Encode()))
}
func NewAddressFromData(data []byte) *Address {
address := &Address{}
address.RlpDecode(data)
return address
func (c *Contract) State() *ethutil.Trie {
return c.state
}
func (a *Address) AddFee(fee *big.Int) {
a.Amount.Add(a.Amount, fee)
}
func (c *Contract) GetMem(num int) *ethutil.Value {
nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256)
func (a *Address) RlpEncode() []byte {
return ethutil.Encode([]interface{}{a.Amount, a.Nonce})
return c.Addr(nb)
}
func (a *Address) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
a.Amount = decoder.Get(0).BigInt()
a.Nonce = decoder.Get(1).Uint()
func MakeContract(tx *Transaction, state *State) *Contract {
// Create contract if there's no recipient
if tx.IsContract() {
addr := tx.Hash()[12:]
value := tx.Value
contract := NewContract(value, []byte(""))
state.trie.Update(string(addr), string(contract.RlpEncode()))
for i, val := range tx.Data {
if len(val) > 0 {
bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256)
contract.state.Update(string(bytNum), string(ethutil.Encode(val)))
}
}
state.trie.Update(string(addr), string(contract.RlpEncode()))
return contract
}
return nil
}
......@@ -4,22 +4,32 @@ import (
"math/big"
)
var StepFee *big.Int = new(big.Int)
var TxFeeRat *big.Int = big.NewInt(100000000000000)
var TxFee *big.Int = big.NewInt(100)
var ContractFee *big.Int = new(big.Int)
var MemFee *big.Int = new(big.Int)
var DataFee *big.Int = new(big.Int)
var CryptoFee *big.Int = new(big.Int)
var ExtroFee *big.Int = new(big.Int)
var StepFee *big.Int = big.NewInt(1)
var StoreFee *big.Int = big.NewInt(5)
var DataFee *big.Int = big.NewInt(20)
var ExtroFee *big.Int = big.NewInt(40)
var CryptoFee *big.Int = big.NewInt(20)
var ContractFee *big.Int = big.NewInt(100)
var BlockReward *big.Int = big.NewInt(1.5e+18)
var UncleReward *big.Int = big.NewInt(1.125e+18)
var UncleInclusionReward *big.Int = big.NewInt(1.875e+17)
var BlockReward *big.Int = big.NewInt(1500000000000000000)
var Period1Reward *big.Int = new(big.Int)
var Period2Reward *big.Int = new(big.Int)
var Period3Reward *big.Int = new(big.Int)
var Period4Reward *big.Int = new(big.Int)
func InitFees() {
StepFee.Mul(StepFee, TxFeeRat)
StoreFee.Mul(StoreFee, TxFeeRat)
DataFee.Mul(DataFee, TxFeeRat)
ExtroFee.Mul(ExtroFee, TxFeeRat)
CryptoFee.Mul(CryptoFee, TxFeeRat)
ContractFee.Mul(ContractFee, TxFeeRat)
/*
// Base for 2**64
b60 := new(big.Int)
......
......@@ -13,7 +13,7 @@ var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20)
var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{}))
var GenisisHeader = []interface{}{
var GenesisHeader = []interface{}{
// Previous hash (none)
//"",
ZeroHash256,
......@@ -36,4 +36,4 @@ var GenisisHeader = []interface{}{
ethutil.Sha3Bin(big.NewInt(42).Bytes()),
}
var Genesis = []interface{}{GenisisHeader, []interface{}{}, []interface{}{}}
var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}}
......@@ -9,57 +9,57 @@ type OpCode int
// Op codes
const (
oSTOP OpCode = iota
oADD
oMUL
oSUB
oDIV
oSDIV
oMOD
oSMOD
oEXP
oNEG
oLT
oLE
oGT
oGE
oEQ
oNOT
oMYADDRESS
oTXSENDER
oTXVALUE
oTXFEE
oTXDATAN
oTXDATA
oBLK_PREVHASH
oBLK_COINBASE
oBLK_TIMESTAMP
oBLK_NUMBER
oBLK_DIFFICULTY
oBASEFEE
oSHA256 OpCode = 32
oRIPEMD160 OpCode = 33
oECMUL OpCode = 34
oECADD OpCode = 35
oECSIGN OpCode = 36
oECRECOVER OpCode = 37
oECVALID OpCode = 38
oSHA3 OpCode = 39
oPUSH OpCode = 48
oPOP OpCode = 49
oDUP OpCode = 50
oSWAP OpCode = 51
oMLOAD OpCode = 52
oMSTORE OpCode = 53
oSLOAD OpCode = 54
oSSTORE OpCode = 55
oJMP OpCode = 56
oJMPI OpCode = 57
oIND OpCode = 58
oEXTRO OpCode = 59
oBALANCE OpCode = 60
oMKTX OpCode = 61
oSUICIDE OpCode = 62
oSTOP = 0x00
oADD = 0x01
oMUL = 0x02
oSUB = 0x03
oDIV = 0x04
oSDIV = 0x05
oMOD = 0x06
oSMOD = 0x07
oEXP = 0x08
oNEG = 0x09
oLT = 0x0a
oLE = 0x0b
oGT = 0x0c
oGE = 0x0d
oEQ = 0x0e
oNOT = 0x0f
oMYADDRESS = 0x10
oTXSENDER = 0x11
oTXVALUE = 0x12
oTXDATAN = 0x13
oTXDATA = 0x14
oBLK_PREVHASH = 0x15
oBLK_COINBASE = 0x16
oBLK_TIMESTAMP = 0x17
oBLK_NUMBER = 0x18
oBLK_DIFFICULTY = 0x19
oBLK_NONCE = 0x1a
oBASEFEE = 0x1b
oSHA256 = 0x20
oRIPEMD160 = 0x21
oECMUL = 0x22
oECADD = 0x23
oECSIGN = 0x24
oECRECOVER = 0x25
oECVALID = 0x26
oSHA3 = 0x27
oPUSH = 0x30
oPOP = 0x31
oDUP = 0x32
oSWAP = 0x33
oMLOAD = 0x34
oMSTORE = 0x35
oSLOAD = 0x36
oSSTORE = 0x37
oJMP = 0x38
oJMPI = 0x39
oIND = 0x3a
oEXTRO = 0x3b
oBALANCE = 0x3c
oMKTX = 0x3d
oSUICIDE = 0x3f
)
// Since the opcodes aren't all in order we can't use a regular slice
......@@ -83,7 +83,6 @@ var opCodeToString = map[OpCode]string{
oMYADDRESS: "MYADDRESS",
oTXSENDER: "TXSENDER",
oTXVALUE: "TXVALUE",
oTXFEE: "TXFEE",
oTXDATAN: "TXDATAN",
oTXDATA: "TXDATA",
oBLK_PREVHASH: "BLK_PREVHASH",
......@@ -159,9 +158,33 @@ func (st *Stack) Popn() (*big.Int, *big.Int) {
return ints[0], ints[1]
}
func (st *Stack) Peek() *big.Int {
s := len(st.data)
str := st.data[s-1]
return str
}
func (st *Stack) Peekn() (*big.Int, *big.Int) {
s := len(st.data)
ints := st.data[s-2:]
return ints[0], ints[1]
}
func (st *Stack) Push(d *big.Int) {
st.data = append(st.data, d)
}
func (st *Stack) Print() {
fmt.Println(st.data)
fmt.Println("### STACK ###")
if len(st.data) > 0 {
for i, val := range st.data {
fmt.Printf("%-3d %v\n", i, val)
}
} else {
fmt.Println("-- empty --")
}
fmt.Println("#############")
}
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type State struct {
trie *ethutil.Trie
}
func NewState(trie *ethutil.Trie) *State {
return &State{trie: trie}
}
func (s *State) GetContract(addr []byte) *Contract {
data := s.trie.Get(string(addr))
if data == "" {
return nil
}
contract := &Contract{}
contract.RlpDecode([]byte(data))
return contract
}
func (s *State) UpdateContract(addr []byte, contract *Contract) {
s.trie.Update(string(addr), string(contract.RlpEncode()))
}
func Compile(code []string) (script []string) {
script = make([]string, len(code))
for i, val := range code {
instr, _ := ethutil.CompileInstr(val)
script[i] = string(instr)
}
return
}
func (s *State) GetAccount(addr []byte) (account *Address) {
data := s.trie.Get(string(addr))
if data == "" {
account = NewAddress(big.NewInt(0))
} else {
account = NewAddressFromData([]byte(data))
}
return
}
func (s *State) UpdateAccount(addr []byte, account *Address) {
s.trie.Update(string(addr), string(account.RlpEncode()))
}
package ethchain
import (
"bytes"
"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}
type Transaction struct {
Nonce uint64
Recipient []byte
......@@ -21,20 +24,17 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction {
tx.Nonce = 0
// Serialize the data
tx.Data = make([]string, len(data))
for i, val := range data {
instr, err := ethutil.CompileInstr(val)
if err != nil {
//fmt.Printf("compile error:%d %v\n", i+1, err)
}
tx.Data[i] = instr
}
tx.Data = data
return &tx
}
// XXX Deprecated
func NewTransactionFromData(data []byte) *Transaction {
return NewTransactionFromBytes(data)
}
func NewTransactionFromBytes(data []byte) *Transaction {
tx := &Transaction{}
tx.RlpDecode(data)
......@@ -65,7 +65,7 @@ func (tx *Transaction) Hash() []byte {
}
func (tx *Transaction) IsContract() bool {
return len(tx.Recipient) == 0
return bytes.Compare(tx.Recipient, ContractAddr) == 0
}
func (tx *Transaction) Signature(key []byte) []byte {
......
......@@ -17,6 +17,17 @@ const (
)
type TxPoolHook chan *Transaction
type TxMsgTy byte
const (
TxPre = iota
TxPost
)
type TxMsg struct {
Tx *Transaction
Type TxMsgTy
}
func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction {
for e := pool.Front(); e != nil; e = e.Next() {
......@@ -34,6 +45,10 @@ type PublicSpeaker interface {
Broadcast(msgType ethwire.MsgType, data []interface{})
}
type TxProcessor interface {
ProcessTransaction(tx *Transaction)
}
// The tx pool a thread safe transaction pool handler. In order to
// guarantee a non blocking pool we use a queue channel which can be
// independently read without needing access to the actual pool. If the
......@@ -54,7 +69,9 @@ type TxPool struct {
BlockManager *BlockManager
Hook TxPoolHook
SecondaryProcessor TxProcessor
subscribers []chan TxMsg
}
func NewTxPool() *TxPool {
......@@ -80,8 +97,6 @@ func (pool *TxPool) addTransaction(tx *Transaction) {
// Process transaction validates the Tx and processes funds from the
// sender to the recipient.
func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) {
log.Printf("[TXPL] Processing Tx %x\n", tx.Hash())
defer func() {
if r := recover(); r != nil {
log.Println(r)
......@@ -106,17 +121,30 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error
}
}
// Subtract the amount from the senders account
sender.Amount.Sub(sender.Amount, totAmount)
sender.Nonce += 1
// Get the receiver
receiver := block.GetAddr(tx.Recipient)
// Add the amount to receivers account which should conclude this transaction
receiver.Amount.Add(receiver.Amount, tx.Value)
sender.Nonce += 1
// Send Tx to self
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
// Subtract the fee
sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat))
} else {
// Subtract the amount from the senders account
sender.Amount.Sub(sender.Amount, totAmount)
// Add the amount to receivers account which should conclude this transaction
receiver.Amount.Add(receiver.Amount, tx.Value)
block.UpdateAddr(tx.Recipient, receiver)
}
block.UpdateAddr(tx.Sender(), sender)
block.UpdateAddr(tx.Recipient, receiver)
log.Printf("[TXPL] Processed Tx %x\n", tx.Hash())
// Notify the subscribers
pool.notifySubscribers(TxPost, tx)
return
}
......@@ -131,7 +159,8 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
}
// Get the sender
sender := block.GetAddr(tx.Sender())
accountState := pool.BlockManager.GetAddrState(tx.Sender())
sender := accountState.Account
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
// Make sure there's enough in the sender's account. Having insufficient
......@@ -171,9 +200,8 @@ out:
// doesn't matter since this is a goroutine
pool.addTransaction(tx)
if pool.Hook != nil {
pool.Hook <- tx
}
// Notify the subscribers
pool.notifySubscribers(TxPre, tx)
}
case <-pool.quit:
break out
......@@ -217,3 +245,14 @@ func (pool *TxPool) Stop() {
pool.Flush()
}
func (pool *TxPool) Subscribe(channel chan TxMsg) {
pool.subscribers = append(pool.subscribers, channel)
}
func (pool *TxPool) notifySubscribers(ty TxMsgTy, tx *Transaction) {
msg := TxMsg{Type: ty, Tx: tx}
for _, subscriber := range pool.subscribers {
subscriber <- msg
}
}
......@@ -2,8 +2,6 @@ package ethchain
import (
"encoding/hex"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
......@@ -42,13 +40,15 @@ func TestAddressRetrieval2(t *testing.T) {
tx.Sign(key)
//data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7")
//tx := NewTransactionFromData(data)
fmt.Println(tx.RlpValue())
/*
fmt.Println(tx.RlpValue())
fmt.Printf("rlp %x\n", tx.RlpEncode())
fmt.Printf("sha rlp %x\n", tx.Hash())
fmt.Printf("rlp %x\n", tx.RlpEncode())
fmt.Printf("sha rlp %x\n", tx.Hash())
//tx.Sign(key)
//tx.Sign(key)
fmt.Printf("hex tx key %x\n", tx.PublicKey())
fmt.Printf("seder %x\n", tx.Sender())
fmt.Printf("hex tx key %x\n", tx.PublicKey())
fmt.Printf("seder %x\n", tx.Sender())
*/
}
This diff is collapsed.
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
func TestRun(t *testing.T) {
InitFees()
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script := Compile([]string{
"TXSENDER",
"SUICIDE",
})
tx := NewTransaction(ContractAddr, big.NewInt(1e17), script)
fmt.Printf("contract addr %x\n", tx.Hash()[12:])
contract := MakeContract(tx, state)
vm := &Vm{}
vm.Process(contract, state, RuntimeVars{
address: tx.Hash()[12:],
blockNumber: 1,
sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"),
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
txValue: tx.Value,
txData: tx.Data,
})
}
func TestRun1(t *testing.T) {
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script := Compile([]string{
"PUSH", "0",
"PUSH", "0",
"TXSENDER",
"PUSH", "10000000",
"MKTX",
})
fmt.Println(ethutil.NewValue(script))
tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script)
fmt.Printf("contract addr %x\n", tx.Hash()[12:])
contract := MakeContract(tx, state)
vm := &Vm{}
vm.Process(contract, state, RuntimeVars{
address: tx.Hash()[12:],
blockNumber: 1,
sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"),
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
txValue: tx.Value,
txData: tx.Data,
})
}
func TestRun2(t *testing.T) {
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script := Compile([]string{
"PUSH", "0",
"PUSH", "0",
"TXSENDER",
"PUSH", "10000000",
"MKTX",
})
fmt.Println(ethutil.NewValue(script))
tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script)
fmt.Printf("contract addr %x\n", tx.Hash()[12:])
contract := MakeContract(tx, state)
vm := &Vm{}
vm.Process(contract, state, RuntimeVars{
address: tx.Hash()[12:],
blockNumber: 1,
sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"),
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
txValue: tx.Value,
txData: tx.Data,
})
}
......@@ -11,8 +11,8 @@ type LDBDatabase struct {
db *leveldb.DB
}
func NewLDBDatabase() (*LDBDatabase, error) {
dbPath := path.Join(ethutil.Config.ExecPath, "database")
func NewLDBDatabase(name string) (*LDBDatabase, error) {
dbPath := path.Join(ethutil.Config.ExecPath, name)
// Open the db
db, err := leveldb.OpenFile(dbPath, nil)
......@@ -36,6 +36,14 @@ func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
return db.db.Get(key, nil)
}
func (db *LDBDatabase) Delete(key []byte) error {
return db.db.Delete(key, nil)
}
func (db *LDBDatabase) Db() *leveldb.DB {
return db.db
}
func (db *LDBDatabase) LastKnownTD() []byte {
data, _ := db.db.Get([]byte("LastKnownTotalDifficulty"), nil)
......@@ -46,13 +54,19 @@ func (db *LDBDatabase) LastKnownTD() []byte {
return data
}
func (db *LDBDatabase) GetKeys() []*ethutil.Key {
data, _ := db.Get([]byte("KeyRing"))
return []*ethutil.Key{ethutil.NewKeyFromBytes(data)}
}
func (db *LDBDatabase) Close() {
// Close the leveldb database
db.db.Close()
}
func (db *LDBDatabase) Print() {
iter := db.db.NewIterator(nil)
iter := db.db.NewIterator(nil, nil)
for iter.Next() {
key := iter.Key()
value := iter.Value()
......
......@@ -26,6 +26,18 @@ func (db *MemDatabase) Get(key []byte) ([]byte, error) {
return db.db[string(key)], nil
}
func (db *MemDatabase) GetKeys() []*ethutil.Key {
data, _ := db.Get([]byte("KeyRing"))
return []*ethutil.Key{ethutil.NewKeyFromBytes(data)}
}
func (db *MemDatabase) Delete(key []byte) error {
delete(db.db, string(key))
return nil
}
func (db *MemDatabase) Print() {
for key, val := range db.db {
fmt.Printf("%x(%d): ", key, len(key))
......
......@@ -47,6 +47,7 @@ type Ethereum struct {
Nonce uint64
Addr net.Addr
Port string
peerMut sync.Mutex
......@@ -60,7 +61,7 @@ type Ethereum struct {
}
func New(caps Caps, usePnp bool) (*Ethereum, error) {
db, err := ethdb.NewLDBDatabase()
db, err := ethdb.NewLDBDatabase("database")
//db, err := ethdb.NewMemDatabase()
if err != nil {
return nil, err
......@@ -70,7 +71,7 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) {
if usePnp {
nat, err = Discover()
if err != nil {
log.Println("UPnP failed", err)
ethutil.Config.Log.Debugln("UPnP failed", err)
}
}
......@@ -85,7 +86,6 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) {
Nonce: nonce,
serverCaps: caps,
nat: nat,
MaxPeers: 5,
}
ethereum.TxPool = ethchain.NewTxPool()
ethereum.TxPool.Speaker = ethereum
......@@ -94,6 +94,9 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) {
ethereum.TxPool.BlockManager = ethereum.BlockManager
ethereum.BlockManager.TransactionPool = ethereum.TxPool
// Start the tx pool
ethereum.TxPool.Start()
return ethereum, nil
}
......@@ -114,28 +117,32 @@ func (s *Ethereum) ProcessPeerList(addrs []string) {
}
func (s *Ethereum) ConnectToPeer(addr string) error {
var alreadyConnected bool
if s.peers.Len() < s.MaxPeers {
var alreadyConnected bool
eachPeer(s.peers, func(p *Peer, v *list.Element) {
if p.conn == nil {
return
}
phost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String())
ahost, _, _ := net.SplitHostPort(addr)
eachPeer(s.peers, func(p *Peer, v *list.Element) {
if p.conn == nil {
return
}
phost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String())
ahost, _, _ := net.SplitHostPort(addr)
if phost == ahost {
alreadyConnected = true
return
if phost == ahost {
alreadyConnected = true
return
}
})
if alreadyConnected {
return nil
}
})
if alreadyConnected {
return nil
}
peer := NewOutboundPeer(addr, s, s.serverCaps)
peer := NewOutboundPeer(addr, s, s.serverCaps)
s.peers.PushBack(peer)
s.peers.PushBack(peer)
log.Printf("[SERV] Adding peer %d / %d\n", s.peers.Len(), s.MaxPeers)
}
return nil
}
......@@ -226,12 +233,12 @@ func (s *Ethereum) ReapDeadPeerHandler() {
// Start the ethereum
func (s *Ethereum) Start() {
// Bind to addr and port
ln, err := net.Listen("tcp", ":30303")
ln, err := net.Listen("tcp", ":"+s.Port)
if err != nil {
log.Println("Connection listening disabled. Acting as client")
} else {
// Starting accepting connections
log.Println("Ready and accepting connections")
ethutil.Config.Log.Infoln("Ready and accepting connections")
// Start the peer handler
go s.peerHandler(ln)
}
......@@ -243,13 +250,10 @@ func (s *Ethereum) Start() {
// Start the reaping processes
go s.ReapDeadPeerHandler()
// Start the tx pool
s.TxPool.Start()
if ethutil.Config.Seed {
log.Println("Seeding")
ethutil.Config.Log.Debugln("Seeding")
// Testnet seed bootstrapping
resp, err := http.Get("http://www.ethereum.org/servers.poc2.txt")
resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt")
if err != nil {
log.Println("Fetching seed failed:", err)
return
......@@ -269,7 +273,7 @@ func (s *Ethereum) peerHandler(listener net.Listener) {
for {
conn, err := listener.Accept()
if err != nil {
log.Println(err)
ethutil.Config.Log.Debugln(err)
continue
}
......@@ -303,7 +307,7 @@ func (s *Ethereum) upnpUpdateThread() {
// Go off immediately to prevent code duplication, thereafter we renew
// lease every 15 minutes.
timer := time.NewTimer(0 * time.Second)
lport, _ := strconv.ParseInt("30303", 10, 16)
lport, _ := strconv.ParseInt(s.Port, 10, 16)
first := true
out:
for {
......@@ -312,13 +316,13 @@ out:
var err error
_, err = s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60)
if err != nil {
log.Println("can't add UPnP port mapping:", err)
ethutil.Config.Log.Debugln("can't add UPnP port mapping:", err)
break out
}
if first && err == nil {
_, err = s.nat.GetExternalAddress()
if err != nil {
log.Println("UPnP can't get external address:", err)
ethutil.Config.Log.Debugln("UPnP can't get external address:", err)
continue out
}
first = false
......@@ -332,8 +336,8 @@ out:
timer.Stop()
if err := s.nat.DeletePortMapping("TCP", int(lport), int(lport)); err != nil {
log.Println("unable to remove UPnP port mapping:", err)
ethutil.Config.Log.Debugln("unable to remove UPnP port mapping:", err)
} else {
log.Println("succesfully disestablished UPnP port mapping")
ethutil.Config.Log.Debugln("succesfully disestablished UPnP port mapping")
}
}
......@@ -53,6 +53,8 @@ trie.Put("doge", "coin")
// Look up the key "do" in the trie
out := trie.Get("do")
fmt.Println(out) // => verb
trie.Delete("puppy")
```
The patricia trie, in combination with RLP, provides a robust,
......@@ -82,7 +84,7 @@ type (e.g. `Slice()` returns []interface{}, `Uint()` return 0, etc).
`NewEmptyValue()` returns a new \*Value with it's initial value set to a
`[]interface{}`
`AppendLint()` appends a list to the current value.
`AppendList()` appends a list to the current value.
`Append(v)` appends the value (v) to the current value/list.
......
......@@ -35,3 +35,18 @@ func BigD(data []byte) *big.Int {
return n
}
func BigToBytes(num *big.Int, base int) []byte {
ret := make([]byte, base/8)
return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...)
}
// Functions like the build in "copy" function
// but works on big integers
func BigCopy(src *big.Int) (ret *big.Int) {
ret = new(big.Int)
ret.Add(ret, src)
return
}
package ethutil
import (
"fmt"
"math/big"
)
var (
Ether = BigPow(10, 18)
Finney = BigPow(10, 15)
Szabo = BigPow(10, 12)
Vito = BigPow(10, 9)
Turing = BigPow(10, 6)
Eins = BigPow(10, 3)
Wei = big.NewInt(1)
)
func CurrencyToString(num *big.Int) string {
switch {
case num.Cmp(Ether) >= 0:
return fmt.Sprintf("%v Ether", new(big.Int).Div(num, Ether))
case num.Cmp(Finney) >= 0:
return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney))
case num.Cmp(Szabo) >= 0:
return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo))
case num.Cmp(Vito) >= 0:
return fmt.Sprintf("%v Vito", new(big.Int).Div(num, Vito))
case num.Cmp(Turing) >= 0:
return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing))
case num.Cmp(Eins) >= 0:
return fmt.Sprintf("%v Eins", new(big.Int).Div(num, Eins))
}
return fmt.Sprintf("%v Wei", num)
}
package ethutil
import (
"fmt"
"math/big"
"testing"
)
func TestCommon(t *testing.T) {
fmt.Println(CurrencyToString(BigPow(10, 19)))
fmt.Println(CurrencyToString(BigPow(10, 16)))
fmt.Println(CurrencyToString(BigPow(10, 13)))
fmt.Println(CurrencyToString(BigPow(10, 10)))
fmt.Println(CurrencyToString(BigPow(10, 7)))
fmt.Println(CurrencyToString(BigPow(10, 4)))
fmt.Println(CurrencyToString(big.NewInt(10)))
}
package ethutil
import (
"fmt"
"log"
"os"
"os/user"
......@@ -18,7 +19,7 @@ const (
type config struct {
Db Database
Log Logger
Log *Logger
ExecPath string
Debug bool
Ver string
......@@ -34,17 +35,19 @@ func ReadConfig(base string) *config {
usr, _ := user.Current()
path := path.Join(usr.HomeDir, base)
//Check if the logging directory already exists, create it if not
_, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
log.Printf("Debug logging directory %s doesn't exist, creating it", path)
os.Mkdir(path, 0777)
if len(base) > 0 {
//Check if the logging directory already exists, create it if not
_, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
log.Printf("Debug logging directory %s doesn't exist, creating it\n", path)
os.Mkdir(path, 0777)
}
}
}
Config = &config{ExecPath: path, Debug: true, Ver: "0.2.2"}
Config.Log = NewLogger(LogFile|LogStd, 0)
Config = &config{ExecPath: path, Debug: true, Ver: "0.3.0"}
Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug)
}
return Config
......@@ -57,15 +60,20 @@ const (
LogStd = 0x2
)
type LogSystem interface {
Println(v ...interface{})
Printf(format string, v ...interface{})
}
type Logger struct {
logSys []*log.Logger
logSys []LogSystem
logLevel int
}
func NewLogger(flag LoggerType, level int) Logger {
var loggers []*log.Logger
func NewLogger(flag LoggerType, level int) *Logger {
var loggers []LogSystem
flags := log.LstdFlags | log.Lshortfile
flags := log.LstdFlags
if flag&LogFile > 0 {
file, err := os.OpenFile(path.Join(Config.ExecPath, "debug.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm)
......@@ -73,30 +81,60 @@ func NewLogger(flag LoggerType, level int) Logger {
log.Panic("unable to create file logger", err)
}
log := log.New(file, "[ETH]", flags)
log := log.New(file, "", flags)
loggers = append(loggers, log)
}
if flag&LogStd > 0 {
log := log.New(os.Stdout, "[ETH]", flags)
log := log.New(os.Stdout, "", flags)
loggers = append(loggers, log)
}
return Logger{logSys: loggers, logLevel: level}
return &Logger{logSys: loggers, logLevel: level}
}
func (log *Logger) AddLogSystem(logger LogSystem) {
log.logSys = append(log.logSys, logger)
}
const (
LogLevelDebug = iota
LogLevelInfo
)
func (log *Logger) Debugln(v ...interface{}) {
if log.logLevel != LogLevelDebug {
return
}
for _, logger := range log.logSys {
logger.Println(v...)
}
}
func (log *Logger) Debugf(format string, v ...interface{}) {
if log.logLevel != LogLevelDebug {
return
}
for _, logger := range log.logSys {
logger.Printf(format, v...)
}
}
func (log Logger) Debugln(v ...interface{}) {
if log.logLevel != 0 {
func (log *Logger) Infoln(v ...interface{}) {
if log.logLevel > LogLevelInfo {
return
}
fmt.Println(len(log.logSys))
for _, logger := range log.logSys {
logger.Println(v...)
}
}
func (log Logger) Debugf(format string, v ...interface{}) {
if log.logLevel != 0 {
func (log *Logger) Infof(format string, v ...interface{}) {
if log.logLevel > LogLevelInfo {
return
}
......
......@@ -4,6 +4,8 @@ package ethutil
type Database interface {
Put(key []byte, value []byte)
Get(key []byte) ([]byte, error)
GetKeys() []*Key
Delete(key []byte) error
LastKnownTD() []byte
Close()
Print()
......
......@@ -3,7 +3,6 @@ package ethutil
import (
"bytes"
"encoding/hex"
_ "fmt"
"strings"
)
......@@ -36,7 +35,7 @@ func CompactEncode(hexSlice []int) string {
func CompactDecode(str string) []int {
base := CompactHexDecode(str)
base = base[:len(base)-1]
if base[0] >= 2 { // && base[len(base)-1] != 16 {
if base[0] >= 2 {
base = append(base, 16)
}
if base[0]%2 == 1 {
......
......@@ -35,3 +35,33 @@ func TestCompactHexDecode(t *testing.T) {
t.Error("Error compact hex decode. Expected", exp, "got", res)
}
}
func TestCompactDecode(t *testing.T) {
exp := []int{1, 2, 3, 4, 5}
res := CompactDecode("\x11\x23\x45")
if !CompareIntSlice(res, exp) {
t.Error("odd compact decode. Expected", exp, "got", res)
}
exp = []int{0, 1, 2, 3, 4, 5}
res = CompactDecode("\x00\x01\x23\x45")
if !CompareIntSlice(res, exp) {
t.Error("even compact decode. Expected", exp, "got", res)
}
exp = []int{0, 15, 1, 12, 11, 8 /*term*/, 16}
res = CompactDecode("\x20\x0f\x1c\xb8")
if !CompareIntSlice(res, exp) {
t.Error("even terminated compact decode. Expected", exp, "got", res)
}
exp = []int{15, 1, 12, 11, 8 /*term*/, 16}
res = CompactDecode("\x3f\x1c\xb8")
if !CompareIntSlice(res, exp) {
t.Error("even terminated compact decode. Expected", exp, "got", res)
}
}
\ No newline at end of file
......@@ -27,7 +27,6 @@ func Ripemd160(data []byte) []byte {
func Sha3Bin(data []byte) []byte {
d := sha3.NewKeccak256()
d.Reset()
d.Write(data)
return d.Sum(nil)
......@@ -59,3 +58,7 @@ func MatchingNibbleLength(a, b []int) int {
func Hex(d []byte) string {
return hex.EncodeToString(d)
}
func FromHex(str string) []byte {
h, _ := hex.DecodeString(str)
return h
}
package ethutil
type Key struct {
PrivateKey []byte
PublicKey []byte
}
func NewKeyFromBytes(data []byte) *Key {
val := NewValueFromBytes(data)
return &Key{val.Get(0).Bytes(), val.Get(1).Bytes()}
}
func (k *Key) Address() []byte {
return Sha3Bin(k.PublicKey[1:])[12:]
}
func (k *Key) RlpEncode() []byte {
return EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode()
}
package ethutil
import (
"errors"
"fmt"
"math/big"
"strconv"
"strings"
)
// Op codes
var OpCodes = map[string]string{
"STOP": "0",
"ADD": "1",
"MUL": "2",
"SUB": "3",
"DIV": "4",
"SDIV": "5",
"MOD": "6",
"SMOD": "7",
"EXP": "8",
"NEG": "9",
"LT": "10",
"LE": "11",
"GT": "12",
"GE": "13",
"EQ": "14",
"NOT": "15",
"MYADDRESS": "16",
"TXSENDER": "17",
"PUSH": "48",
"POP": "49",
"LOAD": "54",
var OpCodes = map[string]byte{
"STOP": 0x00,
"ADD": 0x01,
"MUL": 0x02,
"SUB": 0x03,
"DIV": 0x04,
"SDIV": 0x05,
"MOD": 0x06,
"SMOD": 0x07,
"EXP": 0x08,
"NEG": 0x09,
"LT": 0x0a,
"LE": 0x0b,
"GT": 0x0c,
"GE": 0x0d,
"EQ": 0x0e,
"NOT": 0x0f,
"MYADDRESS": 0x10,
"TXSENDER": 0x11,
"TXVALUE": 0x12,
"TXDATAN": 0x13,
"TXDATA": 0x14,
"BLK_PREVHASH": 0x15,
"BLK_COINBASE": 0x16,
"BLK_TIMESTAMP": 0x17,
"BLK_NUMBER": 0x18,
"BLK_DIFFICULTY": 0x19,
"BLK_NONCE": 0x1a,
"BASEFEE": 0x1b,
"SHA256": 0x20,
"RIPEMD160": 0x21,
"ECMUL": 0x22,
"ECADD": 0x23,
"ECSIGN": 0x24,
"ECRECOVER": 0x25,
"ECVALID": 0x26,
"SHA3": 0x27,
"PUSH": 0x30,
"POP": 0x31,
"DUP": 0x32,
"SWAP": 0x33,
"MLOAD": 0x34,
"MSTORE": 0x35,
"SLOAD": 0x36,
"SSTORE": 0x37,
"JMP": 0x38,
"JMPI": 0x39,
"IND": 0x3a,
"EXTRO": 0x3b,
"BALANCE": 0x3c,
"MKTX": 0x3d,
"SUICIDE": 0x3f,
}
func CompileInstr(s string) (string, error) {
tokens := strings.Split(s, " ")
if OpCodes[tokens[0]] == "" {
return s, errors.New(fmt.Sprintf("OP not found: %s", tokens[0]))
func IsOpCode(s string) bool {
for key, _ := range OpCodes {
if key == s {
return true
}
}
return false
}
code := OpCodes[tokens[0]] // Replace op codes with the proper numerical equivalent
op := new(big.Int)
op.SetString(code, 0)
args := make([]*big.Int, 6)
for i, val := range tokens[1:len(tokens)] {
num := new(big.Int)
num.SetString(val, 0)
args[i] = num
}
// Big int equation = op + x * 256 + y * 256**2 + z * 256**3 + a * 256**4 + b * 256**5 + c * 256**6
base := new(big.Int)
x := new(big.Int)
y := new(big.Int)
z := new(big.Int)
a := new(big.Int)
b := new(big.Int)
c := new(big.Int)
if args[0] != nil {
x.Mul(args[0], big.NewInt(256))
}
if args[1] != nil {
y.Mul(args[1], BigPow(256, 2))
}
if args[2] != nil {
z.Mul(args[2], BigPow(256, 3))
}
if args[3] != nil {
a.Mul(args[3], BigPow(256, 4))
}
if args[4] != nil {
b.Mul(args[4], BigPow(256, 5))
}
if args[5] != nil {
c.Mul(args[5], BigPow(256, 6))
func CompileInstr(s string) ([]byte, error) {
isOp := IsOpCode(s)
if isOp {
return []byte{OpCodes[s]}, nil
}
base.Add(op, x)
base.Add(base, y)
base.Add(base, z)
base.Add(base, a)
base.Add(base, b)
base.Add(base, c)
num := new(big.Int)
num.SetString(s, 0)
return base.String(), nil
return num.Bytes(), nil
}
func Instr(instr string) (int, []string, error) {
base := new(big.Int)
base.SetString(instr, 0)
......
package ethutil
/*
import (
"math"
"testing"
......@@ -13,20 +14,19 @@ func TestCompile(t *testing.T) {
}
calc := (48 + 0*256 + 0*int64(math.Pow(256, 2)))
if Big(instr).Int64() != calc {
if BigD(instr).Int64() != calc {
t.Error("Expected", calc, ", got:", instr)
}
}
func TestValidInstr(t *testing.T) {
/*
op, args, err := Instr("68163")
if err != nil {
t.Error("Error decoding instruction")
}
*/
}
func TestInvalidInstr(t *testing.T) {
}
*/
......@@ -86,13 +86,6 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} {
// TODO Use a bytes.Buffer instead of a raw byte slice.
// Cleaner code, and use draining instead of seeking the next bytes to read
func Decode(data []byte, pos uint64) (interface{}, uint64) {
/*
if pos > uint64(len(data)-1) {
log.Println(data)
log.Panicf("index out of range %d for data %q, l = %d", pos, data, len(data))
}
*/
var slice []interface{}
char := int(data[pos])
switch {
......@@ -131,7 +124,6 @@ func Decode(data []byte, pos uint64) (interface{}, uint64) {
case char <= 0xff:
l := uint64(data[pos]) - 0xf7
//b := BigD(data[pos+1 : pos+1+l]).Uint64()
b := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+l]))
pos = pos + l + 1
......
......@@ -2,15 +2,13 @@ package ethutil
import (
"bytes"
"encoding/hex"
"fmt"
"math/big"
"reflect"
"testing"
)
func TestRlpValueEncoding(t *testing.T) {
val := EmptyRlpValue()
val := EmptyValue()
val.AppendList().Append(1).Append(2).Append(3)
val.Append("4").AppendList().Append(5)
......@@ -63,7 +61,7 @@ func TestEncode(t *testing.T) {
str := string(bytes)
if str != strRes {
t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str))
t.Errorf("Expected %q, got %q", strRes, str)
}
sliceRes := "\xcc\x83dog\x83god\x83cat"
......@@ -71,7 +69,7 @@ func TestEncode(t *testing.T) {
bytes = Encode(strs)
slice := string(bytes)
if slice != sliceRes {
t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice))
t.Error("Expected %q, got %q", sliceRes, slice)
}
intRes := "\x82\x04\x00"
......@@ -108,13 +106,9 @@ func TestEncodeDecodeBigInt(t *testing.T) {
encoded := Encode(bigInt)
value := NewValueFromBytes(encoded)
fmt.Println(value.BigInt(), bigInt)
if value.BigInt().Cmp(bigInt) != 0 {
t.Errorf("Expected %v, got %v", bigInt, value.BigInt())
}
dec, _ := hex.DecodeString("52f4fc1e")
fmt.Println(NewValueFromBytes(dec).BigInt())
}
func TestEncodeDecodeBytes(t *testing.T) {
......@@ -125,43 +119,6 @@ func TestEncodeDecodeBytes(t *testing.T) {
}
}
/*
var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20)
var EmptyShaList = Sha3Bin(Encode([]interface{}{}))
var GenisisHeader = []interface{}{
// Previous hash (none)
//"",
ZeroHash256,
// Sha of uncles
Sha3Bin(Encode([]interface{}{})),
// Coinbase
ZeroHash160,
// Root state
"",
// Sha of transactions
//EmptyShaList,
Sha3Bin(Encode([]interface{}{})),
// Difficulty
BigPow(2, 22),
// Time
//big.NewInt(0),
int64(0),
// extra
"",
// Nonce
big.NewInt(42),
}
func TestEnc(t *testing.T) {
//enc := Encode(GenisisHeader)
//fmt.Printf("%x (%d)\n", enc, len(enc))
h, _ := hex.DecodeString("f8a0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06d076baa9c4074fb2df222dd16a96b0155a1e6686b3e5748b4e9ca0a208a425ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493478340000080802a")
fmt.Printf("%x\n", Sha3Bin(h))
}
*/
func BenchmarkEncodeDecode(b *testing.B) {
for i := 0; i < b.N; i++ {
bytes := Encode([]interface{}{"dog", "god", "cat"})
......
......@@ -5,6 +5,15 @@ import (
"reflect"
)
// TODO
// A StateObject is an object that has a state root
// This is goig to be the object for the second level caching (the caching of object which have a state such as contracts)
type StateObject interface {
State() *Trie
Sync()
Undo()
}
type Node struct {
Key []byte
Value *Value
......@@ -20,8 +29,9 @@ func (n *Node) Copy() *Node {
}
type Cache struct {
nodes map[string]*Node
db Database
nodes map[string]*Node
db Database
IsDirty bool
}
func NewCache(db Database) *Cache {
......@@ -36,6 +46,7 @@ func (cache *Cache) Put(v interface{}) interface{} {
sha := Sha3Bin(enc)
cache.nodes[string(sha)] = NewNode(sha, value, true)
cache.IsDirty = true
return sha
}
......@@ -59,13 +70,25 @@ func (cache *Cache) Get(key []byte) *Value {
return value
}
func (cache *Cache) Delete(key []byte) {
delete(cache.nodes, string(key))
cache.db.Delete(key)
}
func (cache *Cache) Commit() {
// Don't try to commit if it isn't dirty
if !cache.IsDirty {
return
}
for key, node := range cache.nodes {
if node.Dirty {
cache.db.Put([]byte(key), node.Value.Encode())
node.Dirty = false
}
}
cache.IsDirty = false
// If the nodes grows beyond the 200 entries we simple empty it
// FIXME come up with something better
......@@ -80,6 +103,7 @@ func (cache *Cache) Undo() {
delete(cache.nodes, key)
}
}
cache.IsDirty = false
}
// A (modified) Radix Trie implementation. The Trie implements
......@@ -89,18 +113,29 @@ func (cache *Cache) Undo() {
// Please note that the data isn't persisted unless `Sync` is
// explicitly called.
type Trie struct {
Root interface{}
prevRoot interface{}
Root interface{}
//db Database
cache *Cache
}
func NewTrie(db Database, Root interface{}) *Trie {
return &Trie{cache: NewCache(db), Root: Root}
return &Trie{cache: NewCache(db), Root: Root, prevRoot: Root}
}
// Save the cached value to the database.
func (t *Trie) Sync() {
t.cache.Commit()
t.prevRoot = t.Root
}
func (t *Trie) Undo() {
t.cache.Undo()
t.Root = t.prevRoot
}
func (t *Trie) Cache() *Cache {
return t.cache
}
/*
......@@ -119,6 +154,10 @@ func (t *Trie) Get(key string) string {
return c.Str()
}
func (t *Trie) Delete(key string) {
t.Update(key, "")
}
func (t *Trie) GetState(node interface{}, key []int) interface{} {
n := NewValue(node)
// Return the node if key is empty (= found)
......@@ -168,13 +207,15 @@ func (t *Trie) GetNode(node interface{}) *Value {
}
func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} {
if value != "" {
return t.InsertState(node, key, value)
} else {
// delete it
return t.DeleteState(node, key)
}
return ""
return t.Root
}
func (t *Trie) Put(node interface{}) interface{} {
......@@ -228,6 +269,7 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter
// Check for "special" 2 slice type node
if currentNode.Len() == 2 {
// Decode the key
k := CompactDecode(currentNode.Get(0).Str())
v := currentNode.Get(1).Raw()
......@@ -282,6 +324,87 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter
return ""
}
func (t *Trie) DeleteState(node interface{}, key []int) interface{} {
if len(key) == 0 {
return ""
}
// New node
n := NewValue(node)
if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 {
return ""
}
currentNode := t.GetNode(node)
// Check for "special" 2 slice type node
if currentNode.Len() == 2 {
// Decode the key
k := CompactDecode(currentNode.Get(0).Str())
v := currentNode.Get(1).Raw()
// Matching key pair (ie. there's already an object with this key)
if CompareIntSlice(k, key) {
return ""
} else if CompareIntSlice(key[:len(k)], k) {
hash := t.DeleteState(v, key[len(k):])
child := t.GetNode(hash)
var newNode []interface{}
if child.Len() == 2 {
newKey := append(k, CompactDecode(child.Get(0).Str())...)
newNode = []interface{}{CompactEncode(newKey), child.Get(1).Raw()}
} else {
newNode = []interface{}{currentNode.Get(0).Str(), hash}
}
return t.Put(newNode)
} else {
return node
}
} else {
// Copy the current node over to the new node and replace the first nibble in the key
n := EmptyStringSlice(17)
var newNode []interface{}
for i := 0; i < 17; i++ {
cpy := currentNode.Get(i).Raw()
if cpy != nil {
n[i] = cpy
}
}
n[key[0]] = t.DeleteState(n[key[0]], key[1:])
amount := -1
for i := 0; i < 17; i++ {
if n[i] != "" {
if amount == -1 {
amount = i
} else {
amount = -2
}
}
}
if amount == 16 {
newNode = []interface{}{CompactEncode([]int{16}), n[amount]}
} else if amount >= 0 {
child := t.GetNode(n[amount])
if child.Len() == 17 {
newNode = []interface{}{CompactEncode([]int{amount}), n[amount]}
} else if child.Len() == 2 {
key := append([]int{amount}, CompactDecode(child.Get(0).Str())...)
newNode = []interface{}{CompactEncode(key), child.Get(1).Str()}
}
} else {
newNode = n
}
return t.Put(newNode)
}
return ""
}
// Simple compare function which creates a rlp value out of the evaluated objects
func (t *Trie) Cmp(trie *Trie) bool {
return NewValue(t.Root).Cmp(NewValue(trie.Root))
......@@ -296,3 +419,82 @@ func (t *Trie) Copy() *Trie {
return trie
}
type TrieIterator struct {
trie *Trie
key string
value string
shas [][]byte
values []string
}
func (t *Trie) NewIterator() *TrieIterator {
return &TrieIterator{trie: t}
}
// Some time in the near future this will need refactoring :-)
// XXX Note to self, IsSlice == inline node. Str == sha3 to node
func (it *TrieIterator) workNode(currentNode *Value) {
if currentNode.Len() == 2 {
k := CompactDecode(currentNode.Get(0).Str())
if currentNode.Get(1).Str() == "" {
it.workNode(currentNode.Get(1))
} else {
if k[len(k)-1] == 16 {
it.values = append(it.values, currentNode.Get(1).Str())
} else {
it.shas = append(it.shas, currentNode.Get(1).Bytes())
it.getNode(currentNode.Get(1).Bytes())
}
}
} else {
for i := 0; i < currentNode.Len(); i++ {
if i == 16 && currentNode.Get(i).Len() != 0 {
it.values = append(it.values, currentNode.Get(i).Str())
} else {
if currentNode.Get(i).Str() == "" {
it.workNode(currentNode.Get(i))
} else {
val := currentNode.Get(i).Str()
if val != "" {
it.shas = append(it.shas, currentNode.Get(1).Bytes())
it.getNode([]byte(val))
}
}
}
}
}
}
func (it *TrieIterator) getNode(node []byte) {
currentNode := it.trie.cache.Get(node)
it.workNode(currentNode)
}
func (it *TrieIterator) Collect() [][]byte {
if it.trie.Root == "" {
return nil
}
it.getNode(NewValue(it.trie.Root).Bytes())
return it.shas
}
func (it *TrieIterator) Purge() int {
shas := it.Collect()
for _, sha := range shas {
it.trie.cache.Delete(sha)
}
return len(it.values)
}
func (it *TrieIterator) Key() string {
return ""
}
func (it *TrieIterator) Value() string {
return ""
}
package ethutil
import (
_ "encoding/hex"
_ "fmt"
"reflect"
"testing"
)
const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ"
type MemDatabase struct {
db map[string][]byte
}
......@@ -20,15 +21,24 @@ func (db *MemDatabase) Put(key []byte, value []byte) {
func (db *MemDatabase) Get(key []byte) ([]byte, error) {
return db.db[string(key)], nil
}
func (db *MemDatabase) Delete(key []byte) error {
delete(db.db, string(key))
return nil
}
func (db *MemDatabase) GetKeys() []*Key { return nil }
func (db *MemDatabase) Print() {}
func (db *MemDatabase) Close() {}
func (db *MemDatabase) LastKnownTD() []byte { return nil }
func TestTrieSync(t *testing.T) {
func New() (*MemDatabase, *Trie) {
db, _ := NewMemDatabase()
trie := NewTrie(db, "")
return db, NewTrie(db, "")
}
trie.Update("dog", "kindofalongsentencewhichshouldbeencodedinitsentirety")
func TestTrieSync(t *testing.T) {
db, trie := New()
trie.Update("dog", LONG_WORD)
if len(db.db) != 0 {
t.Error("Expected no data in database")
}
......@@ -38,3 +48,125 @@ func TestTrieSync(t *testing.T) {
t.Error("Expected data to be persisted")
}
}
func TestTrieDirtyTracking(t *testing.T) {
_, trie := New()
trie.Update("dog", LONG_WORD)
if !trie.cache.IsDirty {
t.Error("Expected trie to be dirty")
}
trie.Sync()
if trie.cache.IsDirty {
t.Error("Expected trie not to be dirty")
}
trie.Update("test", LONG_WORD)
trie.cache.Undo()
if trie.cache.IsDirty {
t.Error("Expected trie not to be dirty")
}
}
func TestTrieReset(t *testing.T) {
_, trie := New()
trie.Update("cat", LONG_WORD)
if len(trie.cache.nodes) == 0 {
t.Error("Expected cached nodes")
}
trie.cache.Undo()
if len(trie.cache.nodes) != 0 {
t.Error("Expected no nodes after undo")
}
}
func TestTrieGet(t *testing.T) {
_, trie := New()
trie.Update("cat", LONG_WORD)
x := trie.Get("cat")
if x != LONG_WORD {
t.Error("expected %s, got %s", LONG_WORD, x)
}
}
func TestTrieUpdating(t *testing.T) {
_, trie := New()
trie.Update("cat", LONG_WORD)
trie.Update("cat", LONG_WORD+"1")
x := trie.Get("cat")
if x != LONG_WORD+"1" {
t.Error("expected %S, got %s", LONG_WORD+"1", x)
}
}
func TestTrieCmp(t *testing.T) {
_, trie1 := New()
_, trie2 := New()
trie1.Update("doge", LONG_WORD)
trie2.Update("doge", LONG_WORD)
if !trie1.Cmp(trie2) {
t.Error("Expected tries to be equal")
}
trie1.Update("dog", LONG_WORD)
trie2.Update("cat", LONG_WORD)
if trie1.Cmp(trie2) {
t.Errorf("Expected tries not to be equal %x %x", trie1.Root, trie2.Root)
}
}
func TestTrieDelete(t *testing.T) {
_, trie := New()
trie.Update("cat", LONG_WORD)
exp := trie.Root
trie.Update("dog", LONG_WORD)
trie.Delete("dog")
if !reflect.DeepEqual(exp, trie.Root) {
t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root)
}
trie.Update("dog", LONG_WORD)
exp = trie.Root
trie.Update("dude", LONG_WORD)
trie.Delete("dude")
if !reflect.DeepEqual(exp, trie.Root) {
t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root)
}
}
func TestTrieDeleteWithValue(t *testing.T) {
_, trie := New()
trie.Update("c", LONG_WORD)
exp := trie.Root
trie.Update("ca", LONG_WORD)
trie.Update("cat", LONG_WORD)
trie.Delete("ca")
trie.Delete("cat")
if !reflect.DeepEqual(exp, trie.Root) {
t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root)
}
}
func TestTrieIterator(t *testing.T) {
_, trie := New()
trie.Update("c", LONG_WORD)
trie.Update("ca", LONG_WORD)
trie.Update("cat", LONG_WORD)
lenBefore := len(trie.cache.nodes)
it := trie.NewIterator()
if num := it.Purge(); num != 3 {
t.Errorf("Expected purge to return 3, got %d", num)
}
if lenBefore == len(trie.cache.nodes) {
t.Errorf("Expected cached nodes to be deleted")
}
}
......@@ -36,7 +36,8 @@ func (val *Value) Len() int {
if data, ok := val.Val.([]interface{}); ok {
return len(data)
} else if data, ok := val.Val.([]byte); ok {
// FIXME
return len(data)
} else if data, ok := val.Val.(string); ok {
return len(data)
}
......@@ -60,6 +61,10 @@ func (val *Value) Uint() uint64 {
return uint64(Val)
} else if Val, ok := val.Val.(uint64); ok {
return Val
} else if Val, ok := val.Val.(int); ok {
return uint64(Val)
} else if Val, ok := val.Val.(uint); ok {
return uint64(Val)
} else if Val, ok := val.Val.([]byte); ok {
return ReadVarint(bytes.NewReader(Val))
}
......@@ -80,6 +85,8 @@ func (val *Value) BigInt() *big.Int {
b := new(big.Int).SetBytes(a)
return b
} else if a, ok := val.Val.(*big.Int); ok {
return a
} else {
return big.NewInt(int64(val.Uint()))
}
......@@ -92,6 +99,8 @@ func (val *Value) Str() string {
return string(a)
} else if a, ok := val.Val.(string); ok {
return a
} else if a, ok := val.Val.(byte); ok {
return string(a)
}
return ""
......@@ -102,7 +111,7 @@ func (val *Value) Bytes() []byte {
return a
}
return make([]byte, 0)
return []byte{}
}
func (val *Value) Slice() []interface{} {
......@@ -131,6 +140,19 @@ func (val *Value) SliceFromTo(from, to int) *Value {
return NewValue(slice[from:to])
}
// TODO More type checking methods
func (val *Value) IsSlice() bool {
return val.Type() == reflect.Slice
}
func (val *Value) IsStr() bool {
return val.Type() == reflect.String
}
func (val *Value) IsEmpty() bool {
return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0)
}
// Threat the value as a slice
func (val *Value) Get(idx int) *Value {
if d, ok := val.Val.([]interface{}); ok {
......@@ -140,7 +162,7 @@ func (val *Value) Get(idx int) *Value {
}
if idx < 0 {
panic("negative idx for Rlp Get")
panic("negative idx for Value Get")
}
return NewValue(d[idx])
......@@ -158,9 +180,9 @@ func (val *Value) Encode() []byte {
return Encode(val.Val)
}
func NewValueFromBytes(rlpData []byte) *Value {
if len(rlpData) != 0 {
data, _ := Decode(rlpData, 0)
func NewValueFromBytes(data []byte) *Value {
if len(data) != 0 {
data, _ := Decode(data, 0)
return NewValue(data)
}
......
package ethutil
import (
"bytes"
"math/big"
"testing"
)
func TestValueCmp(t *testing.T) {
val1 := NewValue("hello")
val2 := NewValue("world")
if val1.Cmp(val2) {
t.Error("Expected values not to be equal")
}
val3 := NewValue("hello")
val4 := NewValue("hello")
if !val3.Cmp(val4) {
t.Error("Expected values to be equal")
}
}
func TestValueTypes(t *testing.T) {
str := NewValue("str")
num := NewValue(1)
inter := NewValue([]interface{}{1})
byt := NewValue([]byte{1, 2, 3, 4})
bigInt := NewValue(big.NewInt(10))
if str.Str() != "str" {
t.Errorf("expected Str to return 'str', got %s", str.Str())
}
if num.Uint() != 1 {
t.Errorf("expected Uint to return '1', got %d", num.Uint())
}
interExp := []interface{}{1}
if !NewValue(inter.Interface()).Cmp(NewValue(interExp)) {
t.Errorf("expected Interface to return '%v', got %v", interExp, num.Interface())
}
bytExp := []byte{1, 2, 3, 4}
if bytes.Compare(byt.Bytes(), bytExp) != 0 {
t.Errorf("expected Bytes to return '%v', got %v", bytExp, byt.Bytes())
}
bigExp := big.NewInt(10)
if bigInt.BigInt().Cmp(bigExp) != 0 {
t.Errorf("expected BigInt to return '%v', got %v", bigExp, bigInt.BigInt())
}
}
......@@ -19,6 +19,9 @@ var MagicToken = []byte{34, 64, 8, 145}
type MsgType byte
const (
// Values are given explicitly instead of by iota because these values are
// defined by the wire protocol spec; it is easier for humans to ensure
// correctness when values are explicit.
MsgHandshakeTy = 0x00
MsgDiscTy = 0x01
MsgPingTy = 0x02
......
......@@ -6,7 +6,6 @@ import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"log"
"net"
"runtime"
"strconv"
......@@ -23,6 +22,9 @@ const (
type DiscReason byte
const (
// Values are given explicitly instead of by iota because these values are
// defined by the wire protocol spec; it is easier for humans to ensure
// correctness when values are explicit.
DiscReRequested = 0x00
DiscReTcpSysErr = 0x01
DiscBadProto = 0x02
......@@ -56,9 +58,9 @@ func (d DiscReason) String() string {
type Caps byte
const (
CapPeerDiscTy = 0x01
CapTxTy = 0x02
CapChainTy = 0x04
CapPeerDiscTy = 1 << iota
CapTxTy
CapChainTy
CapDefault = CapChainTy | CapTxTy | CapPeerDiscTy
)
......@@ -162,7 +164,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer {
conn, err := net.DialTimeout("tcp", addr, 30*time.Second)
if err != nil {
log.Println("Connection to peer failed", err)
ethutil.Config.Log.Debugln("Connection to peer failed", err)
p.Stop()
return
}
......@@ -199,7 +201,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) {
err := ethwire.WriteMessage(p.conn, msg)
if err != nil {
log.Println("Can't send message:", err)
ethutil.Config.Log.Debugln("Can't send message:", err)
// Stop the client if there was an error writing to it
p.Stop()
return
......@@ -261,7 +263,7 @@ func (p *Peer) HandleInbound() {
// Wait for a message from the peer
msgs, err := ethwire.ReadMessages(p.conn)
if err != nil {
log.Println(err)
ethutil.Config.Log.Debugln(err)
}
for _, msg := range msgs {
switch msg.Type {
......@@ -274,7 +276,7 @@ func (p *Peer) HandleInbound() {
}
case ethwire.MsgDiscTy:
p.Stop()
log.Println("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint()))
ethutil.Config.Log.Infoln("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint()))
case ethwire.MsgPingTy:
// Respond back with pong
p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, ""))
......@@ -285,7 +287,6 @@ func (p *Peer) HandleInbound() {
p.lastPong = time.Now().Unix()
case ethwire.MsgBlockTy:
// Get all blocks and process them
msg.Data = msg.Data
var block, lastBlock *ethchain.Block
var err error
for i := msg.Data.Len() - 1; i >= 0; i-- {
......@@ -293,7 +294,10 @@ func (p *Peer) HandleInbound() {
err = p.ethereum.BlockManager.ProcessBlock(block)
if err != nil {
log.Println("bckmsg", err)
if ethutil.Config.Debug {
ethutil.Config.Log.Infof("[PEER] Block %x failed\n", block.Hash())
ethutil.Config.Log.Infof("[PEER] %v\n", err)
}
break
} else {
lastBlock = block
......@@ -303,7 +307,7 @@ func (p *Peer) HandleInbound() {
if err != nil {
// If the parent is unknown try to catch up with this peer
if ethchain.IsParentErr(err) {
log.Println("Attempting to catch up")
ethutil.Config.Log.Infoln("Attempting to catch up")
p.catchingUp = false
p.CatchupWithPeer()
} else if ethchain.IsValidationErr(err) {
......@@ -315,7 +319,7 @@ func (p *Peer) HandleInbound() {
if p.catchingUp && msg.Data.Len() > 1 {
if ethutil.Config.Debug && lastBlock != nil {
blockInfo := lastBlock.BlockInfo()
log.Printf("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash)
ethutil.Config.Log.Infof("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash)
}
p.catchingUp = false
p.CatchupWithPeer()
......@@ -386,12 +390,12 @@ func (p *Peer) HandleInbound() {
p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()}))
}
case ethwire.MsgNotInChainTy:
log.Printf("Not in chain %x\n", msg.Data)
ethutil.Config.Log.Infof("Not in chain %x\n", msg.Data)
// TODO
// Unofficial but fun nonetheless
case ethwire.MsgTalkTy:
log.Printf("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str())
ethutil.Config.Log.Infoln("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str())
}
}
}
......@@ -434,7 +438,7 @@ func (p *Peer) Start() {
err := p.pushHandshake()
if err != nil {
log.Printf("Peer can't send outbound version ack", err)
ethutil.Config.Log.Debugln("Peer can't send outbound version ack", err)
p.Stop()
......@@ -465,7 +469,7 @@ func (p *Peer) pushHandshake() error {
pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes()
msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{
uint32(4), uint32(0), p.Version, byte(p.caps), p.port, pubkey,
uint32(5), uint32(0), p.Version, byte(p.caps), p.port, pubkey,
})
p.QueueMessage(msg)
......@@ -492,8 +496,8 @@ func (p *Peer) pushPeers() {
func (p *Peer) handleHandshake(msg *ethwire.Msg) {
c := msg.Data
if c.Get(0).Uint() != 4 {
log.Println("Invalid peer version. Require protocol v4")
if c.Get(0).Uint() != 5 {
ethutil.Config.Log.Debugln("Invalid peer version. Require protocol v5")
p.Stop()
return
}
......@@ -525,7 +529,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
// Get a reference to the peers version
p.Version = c.Get(2).Str()
log.Println(p)
ethutil.Config.Log.Debugln("[PEER]", p)
}
func (p *Peer) String() string {
......@@ -542,7 +546,7 @@ func (p *Peer) String() string {
strConnectType = "disconnected"
}
return fmt.Sprintf("peer [%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps)
return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps)
}
......@@ -552,7 +556,7 @@ func (p *Peer) CatchupWithPeer() {
msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(50)})
p.QueueMessage(msg)
log.Printf("Requesting blockchain %x...\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()[:4])
ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()[:4])
}
}
......
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