aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block_pool.go27
-rw-r--r--cmd/ethereum/main.go2
-rw-r--r--cmd/mist/assets/qml/views/wallet.qml23
-rw-r--r--cmd/mist/gui.go33
-rw-r--r--cmd/mist/main.go2
-rw-r--r--cmd/utils/cmd.go2
-rw-r--r--core/block_manager.go39
-rw-r--r--core/chain_manager.go29
-rw-r--r--core/execution.go16
-rw-r--r--core/transaction_pool.go10
-rw-r--r--core/types/bloom9.go12
-rw-r--r--core/types/receipt.go13
-rw-r--r--crypto/crypto.go42
-rw-r--r--crypto/curve.go363
-rw-r--r--crypto/encrypt_decrypt_test.go40
-rw-r--r--crypto/key_manager.go4
-rw-r--r--ethutil/script_unix.go42
-rw-r--r--ethutil/script_windows.go23
-rw-r--r--miner/miner.go25
-rw-r--r--peer.go40
-rw-r--r--vm/address.go18
-rw-r--r--vm/common.go7
-rw-r--r--vm/vm_debug.go26
-rw-r--r--vm/vm_test.go15
-rw-r--r--whisper/envelope.go96
-rw-r--r--whisper/main.go46
-rw-r--r--whisper/message.go64
-rw-r--r--whisper/peer.go128
-rw-r--r--whisper/sort.go25
-rw-r--r--whisper/sort_test.go19
-rw-r--r--whisper/whisper.go193
-rw-r--r--wire/messaging.go3
-rw-r--r--xeth/pipe.go8
33 files changed, 1217 insertions, 218 deletions
diff --git a/block_pool.go b/block_pool.go
index 95c766e53..803927f21 100644
--- a/block_pool.go
+++ b/block_pool.go
@@ -88,7 +88,7 @@ func (self *BlockPool) FetchHashes(peer *Peer) bool {
if (self.peer == nil && peer.td.Cmp(highestTd) >= 0) || (self.peer != nil && peer.td.Cmp(self.peer.td) > 0) || self.peer == peer {
if self.peer != peer {
- poollogger.Debugf("Found better suitable peer (%v vs %v)\n", self.td, peer.td)
+ poollogger.Infof("Found better suitable peer (%v vs %v)\n", self.td, peer.td)
if self.peer != nil {
self.peer.doneFetchingHashes = true
@@ -99,11 +99,7 @@ func (self *BlockPool) FetchHashes(peer *Peer) bool {
self.td = peer.td
if !self.HasLatestHash() {
- peer.doneFetchingHashes = false
-
- const amount = 256
- peerlogger.Debugf("Fetching hashes (%d) %x...\n", amount, peer.lastReceivedHash[0:4])
- peer.QueueMessage(wire.NewMessage(wire.MsgGetBlockHashesTy, []interface{}{peer.lastReceivedHash, uint32(amount)}))
+ self.fetchHashes()
}
return true
@@ -112,6 +108,16 @@ func (self *BlockPool) FetchHashes(peer *Peer) bool {
return false
}
+func (self *BlockPool) fetchHashes() {
+ peer := self.peer
+
+ peer.doneFetchingHashes = false
+
+ const amount = 256
+ peerlogger.Debugf("Fetching hashes (%d) %x...\n", amount, peer.lastReceivedHash[0:4])
+ peer.QueueMessage(wire.NewMessage(wire.MsgGetBlockHashesTy, []interface{}{peer.lastReceivedHash, uint32(amount)}))
+}
+
func (self *BlockPool) AddHash(hash []byte, peer *Peer) {
self.mut.Lock()
defer self.mut.Unlock()
@@ -148,7 +154,7 @@ func (self *BlockPool) addBlock(b *types.Block, peer *Peer, newBlock bool) {
fmt.Println("1.", !self.eth.ChainManager().HasBlock(b.PrevHash), ethutil.Bytes2Hex(b.Hash()[0:4]), ethutil.Bytes2Hex(b.PrevHash[0:4]))
fmt.Println("2.", self.pool[string(b.PrevHash)] == nil)
fmt.Println("3.", !self.fetchingHashes)
- if !self.eth.ChainManager().HasBlock(b.PrevHash) && self.pool[string(b.PrevHash)] == nil && !self.fetchingHashes {
+ if !self.eth.ChainManager().HasBlock(b.PrevHash) /*&& self.pool[string(b.PrevHash)] == nil*/ && !self.fetchingHashes {
poollogger.Infof("Unknown chain, requesting (%x...)\n", b.PrevHash[0:4])
peer.QueueMessage(wire.NewMessage(wire.MsgGetBlockHashesTy, []interface{}{b.Hash(), uint32(256)}))
}
@@ -259,6 +265,13 @@ out:
self.ChainLength = len(self.hashes)
}
+ if self.peer != nil &&
+ !self.peer.doneFetchingHashes &&
+ time.Since(self.peer.lastHashAt) > 10*time.Second &&
+ time.Since(self.peer.lastHashRequestedAt) > 5*time.Second {
+ self.fetchHashes()
+ }
+
/*
if !self.fetchingHashes {
blocks := self.Blocks()
diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go
index c39f904fb..43551fb3a 100644
--- a/cmd/ethereum/main.go
+++ b/cmd/ethereum/main.go
@@ -30,7 +30,7 @@ import (
const (
ClientIdentifier = "Ethereum(G)"
- Version = "0.7.7"
+ Version = "0.7.9"
)
var clilogger = logger.NewLogger("CLI")
diff --git a/cmd/mist/assets/qml/views/wallet.qml b/cmd/mist/assets/qml/views/wallet.qml
index 9ffb1024d..9727ef35c 100644
--- a/cmd/mist/assets/qml/views/wallet.qml
+++ b/cmd/mist/assets/qml/views/wallet.qml
@@ -148,17 +148,21 @@ Rectangle {
id: txTableView
anchors.fill : parent
TableViewColumn{ role: "num" ; title: "#" ; width: 30 }
- TableViewColumn{ role: "from" ; title: "From" ; width: 280 }
- TableViewColumn{ role: "to" ; title: "To" ; width: 280 }
+ TableViewColumn{ role: "from" ; title: "From" ; width: 340 }
+ TableViewColumn{ role: "to" ; title: "To" ; width: 340 }
TableViewColumn{ role: "value" ; title: "Amount" ; width: 100 }
model: ListModel {
id: txModel
Component.onCompleted: {
- var filter = ethx.watch({latest: -1, from: eth.key().address});
- filter.changed(addTxs)
-
- addTxs(filter.messages())
+ var me = eth.key().address;
+ var filterTo = ethx.watch({latest: -1, to: me});
+ var filterFrom = ethx.watch({latest: -1, from: me});
+ filterTo.changed(addTxs)
+ filterFrom.changed(addTxs)
+
+ addTxs(filterTo.messages())
+ addTxs(filterFrom.messages())
}
function addTxs(messages) {
@@ -167,7 +171,12 @@ Rectangle {
for(var i = 0; i < messages.length; i++) {
var message = messages.get(i);
var to = eth.lookupName(message.to);
- var from = eth.lookupName(message.from);
+ var from;
+ if(message.from.length == 0) {
+ from = "- MINED -";
+ } else {
+ from = eth.lookupName(message.from);
+ }
txModel.insert(0, {num: txModel.count, from: from, to: to, value: eth.numberToHuman(message.value)})
}
}
diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go
index e58e349d1..0b03cdc1b 100644
--- a/cmd/mist/gui.go
+++ b/cmd/mist/gui.go
@@ -389,7 +389,6 @@ func (gui *Gui) update() {
gui.loadAddressBook()
gui.loadMergedMiningOptions()
gui.setPeerInfo()
- //gui.readPreviousTransactions()
}()
for _, plugin := range gui.plugins {
@@ -404,7 +403,6 @@ func (gui *Gui) update() {
state := gui.eth.BlockManager().TransState()
- unconfirmedFunds := new(big.Int)
gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Balance())))
lastBlockLabel := gui.getObjectByName("lastBlockLabel")
@@ -418,9 +416,6 @@ func (gui *Gui) update() {
core.TxPostEvent{},
)
- // nameReg := gui.pipe.World().Config().Get("NameReg")
- // mux.Subscribe("object:"+string(nameReg.Address()), objectChan)
-
go func() {
defer events.Unsubscribe()
for {
@@ -438,15 +433,15 @@ func (gui *Gui) update() {
case core.TxPreEvent:
tx := ev.Tx
- object := state.GetAccount(gui.address())
- if bytes.Compare(tx.Sender(), gui.address()) == 0 {
- unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
- } else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
- unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
- }
+ tstate := gui.eth.BlockManager().TransState()
+ cstate := gui.eth.BlockManager().CurrentState()
+
+ taccount := tstate.GetAccount(gui.address())
+ caccount := cstate.GetAccount(gui.address())
+ unconfirmedFunds := new(big.Int).Sub(taccount.Balance(), caccount.Balance())
- gui.setWalletValue(object.Balance(), unconfirmedFunds)
+ gui.setWalletValue(taccount.Balance(), unconfirmedFunds)
gui.insertTransaction("pre", tx)
case core.TxPostEvent:
@@ -456,32 +451,18 @@ func (gui *Gui) update() {
if bytes.Compare(tx.Sender(), gui.address()) == 0 {
object.SubAmount(tx.Value)
- //gui.getObjectByName("transactionView").Call("addTx", xeth.NewJSTx(tx), "send")
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
} else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
object.AddAmount(tx.Value)
- //gui.getObjectByName("transactionView").Call("addTx", xeth.NewJSTx(tx), "recv")
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
}
gui.setWalletValue(object.Balance(), nil)
state.UpdateStateObject(object)
- // case object:
- // gui.loadAddressBook()
-
case eth.PeerListEvent:
gui.setPeerInfo()
-
- /*
- case miner.Event:
- if ev.Type == miner.Started {
- gui.miner = ev.Miner
- } else {
- gui.miner = nil
- }
- */
}
case <-peerUpdateTicker.C:
diff --git a/cmd/mist/main.go b/cmd/mist/main.go
index 8c46de6d9..14336b4e8 100644
--- a/cmd/mist/main.go
+++ b/cmd/mist/main.go
@@ -31,7 +31,7 @@ import (
const (
ClientIdentifier = "Mist"
- Version = "0.7.7"
+ Version = "0.7.9"
)
var ethereum *eth.Ethereum
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index d9b26c701..db7bcd35e 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -145,7 +145,6 @@ func NewDatabase() ethutil.Database {
}
func NewClientIdentity(clientIdentifier, version, customIdentifier string) *wire.SimpleClientIdentity {
- clilogger.Infoln("identity created")
return wire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
}
@@ -240,6 +239,7 @@ func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, Secre
exit(err)
}
}
+ clilogger.Infof("Main address %x\n", keyManager.Address())
}
func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
diff --git a/core/block_manager.go b/core/block_manager.go
index c2ffc7ae0..4c1cea35a 100644
--- a/core/block_manager.go
+++ b/core/block_manager.go
@@ -123,7 +123,7 @@ func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *t
coinbase.SetGasPool(block.CalcGasLimit(parent))
// Process the transactions on to current block
- receipts, _, _, _, err = sm.ProcessTransactions(coinbase, statedb, block, parent, block.Transactions())
+ receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
if err != nil {
return nil, err
}
@@ -131,7 +131,7 @@ func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *t
return receipts, nil
}
-func (self *BlockManager) ProcessTransactions(coinbase *state.StateObject, state *state.StateDB, block, parent *types.Block, txs types.Transactions) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
+func (self *BlockManager) ApplyTransactions(coinbase *state.StateObject, state *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
var (
receipts types.Receipts
handled, unhandled types.Transactions
@@ -180,7 +180,9 @@ done:
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
// Notify all subscribers
- go self.eth.EventMux().Post(TxPostEvent{tx})
+ if !transientProcess {
+ go self.eth.EventMux().Post(TxPostEvent{tx})
+ }
receipts = append(receipts, receipt)
handled = append(handled, tx)
@@ -229,38 +231,33 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
return
}
- _, err = sm.TransitionState(state, parent, block)
+ receipts, err := sm.TransitionState(state, parent, block)
if err != nil {
return
}
+ rbloom := types.CreateBloom(receipts)
+ if bytes.Compare(rbloom, block.LogsBloom) != 0 {
+ err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
+ return
+ }
+
txSha := types.DeriveSha(block.Transactions())
if bytes.Compare(txSha, block.TxSha) != 0 {
err = fmt.Errorf("validating transaction root. received=%x got=%x", block.TxSha, txSha)
return
}
- /*
- receiptSha := types.DeriveSha(receipts)
- if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
- err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
- return
- }
- */
+ receiptSha := types.DeriveSha(receipts)
+ if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
+ err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
+ return
+ }
if err = sm.AccumelateRewards(state, block, parent); err != nil {
return
}
- /*
- //block.receipts = receipts // although this isn't necessary it be in the future
- rbloom := types.CreateBloom(receipts)
- if bytes.Compare(rbloom, block.LogsBloom) != 0 {
- err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
- return
- }
- */
-
state.Update(ethutil.Big0)
if !block.State().Cmp(state) {
@@ -378,7 +375,7 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent
account.AddAmount(reward)
statedb.Manifest().AddMessage(&state.Message{
- To: block.Coinbase, From: block.Coinbase,
+ To: block.Coinbase,
Input: nil,
Origin: nil,
Block: block.Hash(), Timestamp: block.Time, Coinbase: block.Coinbase, Number: block.Number,
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 7acd171ec..150139def 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -125,7 +125,8 @@ func (bc *ChainManager) Reset() {
bc.genesisBlock.Trie().Sync()
// Prepare the genesis block
- bc.add(bc.genesisBlock)
+ bc.write(bc.genesisBlock)
+ bc.insert(bc.genesisBlock)
bc.CurrentBlock = bc.genesisBlock
bc.SetTotalDifficulty(ethutil.Big("0"))
@@ -134,18 +135,18 @@ func (bc *ChainManager) Reset() {
bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
}
-// Add a block to the chain and record addition information
-func (bc *ChainManager) add(block *types.Block) {
- bc.writeBlockInfo(block)
-
+func (bc *ChainManager) insert(block *types.Block) {
+ encodedBlock := block.RlpEncode()
+ ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
bc.CurrentBlock = block
bc.LastBlockHash = block.Hash()
+}
+
+func (bc *ChainManager) write(block *types.Block) {
+ bc.writeBlockInfo(block)
encodedBlock := block.RlpEncode()
ethutil.Config.Db.Put(block.Hash(), encodedBlock)
- ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
-
- //chainlogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4])
}
// Accessors
@@ -266,8 +267,16 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
return err
}
- self.add(block)
- self.SetTotalDifficulty(td)
+ self.write(block)
+ if td.Cmp(self.TD) > 0 {
+ if block.Number.Cmp(new(big.Int).Add(self.CurrentBlock.Number, ethutil.Big1)) < 0 {
+ chainlogger.Infof("Split detected. New head #%v (%x), was #%v (%x)\n", block.Number, block.Hash()[:4], self.CurrentBlock.Number, self.CurrentBlock.Hash()[:4])
+ }
+
+ self.SetTotalDifficulty(td)
+ self.insert(block)
+ }
+
self.eventMux.Post(NewBlockEvent{block})
self.eventMux.Post(messages)
}
diff --git a/core/execution.go b/core/execution.go
index 9f9d9a5d9..5176f7351 100644
--- a/core/execution.go
+++ b/core/execution.go
@@ -34,8 +34,14 @@ func (self *Execution) Call(codeAddr []byte, caller vm.ClosureRef) ([]byte, erro
func (self *Execution) exec(code, caddr []byte, caller vm.ClosureRef) (ret []byte, err error) {
env := self.vm.Env()
-
chainlogger.Debugf("pre state %x\n", env.State().Root())
+
+ from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address)
+ // Skipping transfer is used on testing for the initial call
+ if !self.SkipTransfer {
+ err = env.Transfer(from, to, self.value)
+ }
+
snapshot := env.State().Copy()
defer func() {
if vm.IsDepthErr(err) || vm.IsOOGErr(err) {
@@ -44,12 +50,6 @@ func (self *Execution) exec(code, caddr []byte, caller vm.ClosureRef) (ret []byt
chainlogger.Debugf("post state %x\n", env.State().Root())
}()
- from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address)
- // Skipping transfer is used on testing for the initial call
- if !self.SkipTransfer {
- err = env.Transfer(from, to, self.value)
- }
-
if err != nil {
caller.ReturnGas(self.Gas, self.price)
@@ -59,7 +59,7 @@ func (self *Execution) exec(code, caddr []byte, caller vm.ClosureRef) (ret []byt
// Pre-compiled contracts (address.go) 1, 2 & 3.
naddr := ethutil.BigD(caddr).Uint64()
if p := vm.Precompiled[naddr]; p != nil {
- if self.Gas.Cmp(p.Gas) >= 0 {
+ if self.Gas.Cmp(p.Gas(len(self.input))) >= 0 {
ret = p.Call(self.input)
self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret)
self.vm.Endl()
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index abacb14f1..1d1f478e4 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -115,10 +115,6 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
return fmt.Errorf("tx.v != (28 || 27)")
}
- if tx.GasPrice.Cmp(MinGasPrice) < 0 {
- return fmt.Errorf("Gas price to low. Require %v > Got %v", MinGasPrice, tx.GasPrice)
- }
-
// Get the sender
sender := pool.Ethereum.BlockManager().CurrentState().GetAccount(tx.Sender())
@@ -164,11 +160,15 @@ func (self *TxPool) Add(tx *types.Transaction) error {
txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash())
// Notify the subscribers
- self.Ethereum.EventMux().Post(TxPreEvent{tx})
+ go self.Ethereum.EventMux().Post(TxPreEvent{tx})
return nil
}
+func (self *TxPool) Size() int {
+ return self.pool.Len()
+}
+
func (pool *TxPool) CurrentTransactions() []*types.Transaction {
pool.mutex.Lock()
defer pool.mutex.Unlock()
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
index d04656b0d..c1841e553 100644
--- a/core/types/bloom9.go
+++ b/core/types/bloom9.go
@@ -20,18 +20,16 @@ func CreateBloom(receipts Receipts) []byte {
func LogsBloom(logs state.Logs) *big.Int {
bin := new(big.Int)
for _, log := range logs {
- data := [][]byte{log.Address()}
- for _, topic := range log.Topics() {
- data = append(data, topic)
+ data := make([][]byte, len(log.Topics())+1)
+ data[0] = log.Address()
+
+ for i, topic := range log.Topics() {
+ data[i+1] = topic
}
for _, b := range data {
bin.Or(bin, ethutil.BigD(bloom9(crypto.Sha3(b)).Bytes()))
}
-
- //if log.Data != nil {
- // data = append(data, log.Data)
- //}
}
return bin
diff --git a/core/types/receipt.go b/core/types/receipt.go
index 25fa8fb07..bac64e41d 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -64,5 +64,18 @@ func (self *Receipt) String() string {
type Receipts []*Receipt
+func (self Receipts) RlpData() interface{} {
+ data := make([]interface{}, len(self))
+ for i, receipt := range self {
+ data[i] = receipt.RlpData()
+ }
+
+ return data
+}
+
+func (self Receipts) RlpEncode() []byte {
+ return ethutil.Encode(self.RlpData())
+}
+
func (self Receipts) Len() int { return len(self) }
func (self Receipts) GetRlp(i int) []byte { return ethutil.Rlp(self[i]) }
diff --git a/crypto/crypto.go b/crypto/crypto.go
index e10a9e81f..87dd72dc7 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -1,14 +1,35 @@
package crypto
import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
"crypto/sha256"
"code.google.com/p/go.crypto/ripemd160"
"github.com/ethereum/go-ethereum/ethutil"
+ "github.com/obscuren/ecies"
"github.com/obscuren/secp256k1-go"
"github.com/obscuren/sha3"
)
+func init() {
+ // specify the params for the s256 curve
+ ecies.AddParamsForCurve(S256(), ecies.ECIES_AES128_SHA256)
+}
+
+func ToECDSA(prv []byte) *ecdsa.PrivateKey {
+ priv := new(ecdsa.PrivateKey)
+ priv.PublicKey.Curve = S256()
+ priv.D = ethutil.BigD(prv)
+ priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(prv)
+ return priv
+}
+
+func FromECDSA(prv *ecdsa.PrivateKey) []byte {
+ return prv.D.Bytes()
+}
+
// TODO refactor, remove (bin)
func Sha3(data []byte) []byte {
d := sha3.NewKeccak256()
@@ -45,3 +66,24 @@ func Ecrecover(data []byte) []byte {
return r
}
+
+func SigToPub(hash, sig []byte) []byte {
+ return Ecrecover(append(hash, sig...))
+}
+
+func Sign(hash, prv []byte) (sig []byte, err error) {
+ sig, err = secp256k1.Sign(hash, prv)
+ return
+}
+
+func Encrypt(pub, message []byte) ([]byte, error) {
+ x, y := elliptic.Unmarshal(S256(), pub)
+ epub := &ecdsa.PublicKey{S256(), x, y}
+
+ return ecies.Encrypt(rand.Reader, ecies.ImportECDSAPublic(epub), message, nil, nil)
+}
+
+func Decrypt(prv, ct []byte) ([]byte, error) {
+ key := ecies.ImportECDSA(ToECDSA(prv))
+ return key.Decrypt(rand.Reader, ct, nil, nil)
+}
diff --git a/crypto/curve.go b/crypto/curve.go
new file mode 100644
index 000000000..131a0dd2f
--- /dev/null
+++ b/crypto/curve.go
@@ -0,0 +1,363 @@
+package crypto
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2011 ThePiachu. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bitelliptic implements several Koblitz elliptic curves over prime
+// fields.
+
+// This package operates, internally, on Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
+// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
+// calculation can be performed within the transform (as in ScalarMult and
+// ScalarBaseMult). But even for Add and Double, it's faster to apply and
+// reverse the transform than to operate in affine coordinates.
+
+import (
+ "crypto/elliptic"
+ "io"
+ "math/big"
+ "sync"
+)
+
+// A BitCurve represents a Koblitz Curve with a=0.
+// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+type BitCurve struct {
+ P *big.Int // the order of the underlying field
+ N *big.Int // the order of the base point
+ B *big.Int // the constant of the BitCurve equation
+ Gx, Gy *big.Int // (x,y) of the base point
+ BitSize int // the size of the underlying field
+}
+
+func (BitCurve *BitCurve) Params() *elliptic.CurveParams {
+ return &elliptic.CurveParams{BitCurve.P, BitCurve.N, BitCurve.B, BitCurve.Gx, BitCurve.Gy, BitCurve.BitSize}
+}
+
+// IsOnBitCurve returns true if the given (x,y) lies on the BitCurve.
+func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool {
+ // y² = x³ + b
+ y2 := new(big.Int).Mul(y, y) //y²
+ y2.Mod(y2, BitCurve.P) //y²%P
+
+ x3 := new(big.Int).Mul(x, x) //x²
+ x3.Mul(x3, x) //x³
+
+ x3.Add(x3, BitCurve.B) //x³+B
+ x3.Mod(x3, BitCurve.P) //(x³+B)%P
+
+ return x3.Cmp(y2) == 0
+}
+
+//TODO: double check if the function is okay
+// affineFromJacobian reverses the Jacobian transform. See the comment at the
+// top of the file.
+func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
+ zinv := new(big.Int).ModInverse(z, BitCurve.P)
+ zinvsq := new(big.Int).Mul(zinv, zinv)
+
+ xOut = new(big.Int).Mul(x, zinvsq)
+ xOut.Mod(xOut, BitCurve.P)
+ zinvsq.Mul(zinvsq, zinv)
+ yOut = new(big.Int).Mul(y, zinvsq)
+ yOut.Mod(yOut, BitCurve.P)
+ return
+}
+
+// Add returns the sum of (x1,y1) and (x2,y2)
+func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ z := new(big.Int).SetInt64(1)
+ return BitCurve.affineFromJacobian(BitCurve.addJacobian(x1, y1, z, x2, y2, z))
+}
+
+// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
+// (x2, y2, z2) and returns their sum, also in Jacobian form.
+func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ z1z1 := new(big.Int).Mul(z1, z1)
+ z1z1.Mod(z1z1, BitCurve.P)
+ z2z2 := new(big.Int).Mul(z2, z2)
+ z2z2.Mod(z2z2, BitCurve.P)
+
+ u1 := new(big.Int).Mul(x1, z2z2)
+ u1.Mod(u1, BitCurve.P)
+ u2 := new(big.Int).Mul(x2, z1z1)
+ u2.Mod(u2, BitCurve.P)
+ h := new(big.Int).Sub(u2, u1)
+ if h.Sign() == -1 {
+ h.Add(h, BitCurve.P)
+ }
+ i := new(big.Int).Lsh(h, 1)
+ i.Mul(i, i)
+ j := new(big.Int).Mul(h, i)
+
+ s1 := new(big.Int).Mul(y1, z2)
+ s1.Mul(s1, z2z2)
+ s1.Mod(s1, BitCurve.P)
+ s2 := new(big.Int).Mul(y2, z1)
+ s2.Mul(s2, z1z1)
+ s2.Mod(s2, BitCurve.P)
+ r := new(big.Int).Sub(s2, s1)
+ if r.Sign() == -1 {
+ r.Add(r, BitCurve.P)
+ }
+ r.Lsh(r, 1)
+ v := new(big.Int).Mul(u1, i)
+
+ x3 := new(big.Int).Set(r)
+ x3.Mul(x3, x3)
+ x3.Sub(x3, j)
+ x3.Sub(x3, v)
+ x3.Sub(x3, v)
+ x3.Mod(x3, BitCurve.P)
+
+ y3 := new(big.Int).Set(r)
+ v.Sub(v, x3)
+ y3.Mul(y3, v)
+ s1.Mul(s1, j)
+ s1.Lsh(s1, 1)
+ y3.Sub(y3, s1)
+ y3.Mod(y3, BitCurve.P)
+
+ z3 := new(big.Int).Add(z1, z2)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, z1z1)
+ if z3.Sign() == -1 {
+ z3.Add(z3, BitCurve.P)
+ }
+ z3.Sub(z3, z2z2)
+ if z3.Sign() == -1 {
+ z3.Add(z3, BitCurve.P)
+ }
+ z3.Mul(z3, h)
+ z3.Mod(z3, BitCurve.P)
+
+ return x3, y3, z3
+}
+
+// Double returns 2*(x,y)
+func (BitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ z1 := new(big.Int).SetInt64(1)
+ return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z1))
+}
+
+// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
+// returns its double, also in Jacobian form.
+func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
+
+ a := new(big.Int).Mul(x, x) //X1²
+ b := new(big.Int).Mul(y, y) //Y1²
+ c := new(big.Int).Mul(b, b) //B²
+
+ d := new(big.Int).Add(x, b) //X1+B
+ d.Mul(d, d) //(X1+B)²
+ d.Sub(d, a) //(X1+B)²-A
+ d.Sub(d, c) //(X1+B)²-A-C
+ d.Mul(d, big.NewInt(2)) //2*((X1+B)²-A-C)
+
+ e := new(big.Int).Mul(big.NewInt(3), a) //3*A
+ f := new(big.Int).Mul(e, e) //E²
+
+ x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D
+ x3.Sub(f, x3) //F-2*D
+ x3.Mod(x3, BitCurve.P)
+
+ y3 := new(big.Int).Sub(d, x3) //D-X3
+ y3.Mul(e, y3) //E*(D-X3)
+ y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C
+ y3.Mod(y3, BitCurve.P)
+
+ z3 := new(big.Int).Mul(y, z) //Y1*Z1
+ z3.Mul(big.NewInt(2), z3) //3*Y1*Z1
+ z3.Mod(z3, BitCurve.P)
+
+ return x3, y3, z3
+}
+
+//TODO: double check if it is okay
+// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
+func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
+ // We have a slight problem in that the identity of the group (the
+ // point at infinity) cannot be represented in (x, y) form on a finite
+ // machine. Thus the standard add/double algorithm has to be tweaked
+ // slightly: our initial state is not the identity, but x, and we
+ // ignore the first true bit in |k|. If we don't find any true bits in
+ // |k|, then we return nil, nil, because we cannot return the identity
+ // element.
+
+ Bz := new(big.Int).SetInt64(1)
+ x := Bx
+ y := By
+ z := Bz
+
+ seenFirstTrue := false
+ for _, byte := range k {
+ for bitNum := 0; bitNum < 8; bitNum++ {
+ if seenFirstTrue {
+ x, y, z = BitCurve.doubleJacobian(x, y, z)
+ }
+ if byte&0x80 == 0x80 {
+ if !seenFirstTrue {
+ seenFirstTrue = true
+ } else {
+ x, y, z = BitCurve.addJacobian(Bx, By, Bz, x, y, z)
+ }
+ }
+ byte <<= 1
+ }
+ }
+
+ if !seenFirstTrue {
+ return nil, nil
+ }
+
+ return BitCurve.affineFromJacobian(x, y, z)
+}
+
+// ScalarBaseMult returns k*G, where G is the base point of the group and k is
+// an integer in big-endian form.
+func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+ return BitCurve.ScalarMult(BitCurve.Gx, BitCurve.Gy, k)
+}
+
+var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
+
+//TODO: double check if it is okay
+// GenerateKey returns a public/private key pair. The private key is generated
+// using the given reader, which must return random data.
+func (BitCurve *BitCurve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err error) {
+ byteLen := (BitCurve.BitSize + 7) >> 3
+ priv = make([]byte, byteLen)
+
+ for x == nil {
+ _, err = io.ReadFull(rand, priv)
+ if err != nil {
+ return
+ }
+ // We have to mask off any excess bits in the case that the size of the
+ // underlying field is not a whole number of bytes.
+ priv[0] &= mask[BitCurve.BitSize%8]
+ // This is because, in tests, rand will return all zeros and we don't
+ // want to get the point at infinity and loop forever.
+ priv[1] ^= 0x42
+ x, y = BitCurve.ScalarBaseMult(priv)
+ }
+ return
+}
+
+// Marshal converts a point into the form specified in section 4.3.6 of ANSI
+// X9.62.
+func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
+ byteLen := (BitCurve.BitSize + 7) >> 3
+
+ ret := make([]byte, 1+2*byteLen)
+ ret[0] = 4 // uncompressed point
+
+ xBytes := x.Bytes()
+ copy(ret[1+byteLen-len(xBytes):], xBytes)
+ yBytes := y.Bytes()
+ copy(ret[1+2*byteLen-len(yBytes):], yBytes)
+ return ret
+}
+
+// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
+// error, x = nil.
+func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
+ byteLen := (BitCurve.BitSize + 7) >> 3
+ if len(data) != 1+2*byteLen {
+ return
+ }
+ if data[0] != 4 { // uncompressed form
+ return
+ }
+ x = new(big.Int).SetBytes(data[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(data[1+byteLen:])
+ return
+}
+
+//curve parameters taken from:
+//http://www.secg.org/collateral/sec2_final.pdf
+
+var initonce sync.Once
+var ecp160k1 *BitCurve
+var ecp192k1 *BitCurve
+var ecp224k1 *BitCurve
+var ecp256k1 *BitCurve
+
+func initAll() {
+ initS160()
+ initS192()
+ initS224()
+ initS256()
+}
+
+func initS160() {
+ // See SEC 2 section 2.4.1
+ ecp160k1 = new(BitCurve)
+ ecp160k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", 16)
+ ecp160k1.N, _ = new(big.Int).SetString("0100000000000000000001B8FA16DFAB9ACA16B6B3", 16)
+ ecp160k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000007", 16)
+ ecp160k1.Gx, _ = new(big.Int).SetString("3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", 16)
+ ecp160k1.Gy, _ = new(big.Int).SetString("938CF935318FDCED6BC28286531733C3F03C4FEE", 16)
+ ecp160k1.BitSize = 160
+}
+
+func initS192() {
+ // See SEC 2 section 2.5.1
+ ecp192k1 = new(BitCurve)
+ ecp192k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", 16)
+ ecp192k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 16)
+ ecp192k1.B, _ = new(big.Int).SetString("000000000000000000000000000000000000000000000003", 16)
+ ecp192k1.Gx, _ = new(big.Int).SetString("DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", 16)
+ ecp192k1.Gy, _ = new(big.Int).SetString("9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", 16)
+ ecp192k1.BitSize = 192
+}
+
+func initS224() {
+ // See SEC 2 section 2.6.1
+ ecp224k1 = new(BitCurve)
+ ecp224k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", 16)
+ ecp224k1.N, _ = new(big.Int).SetString("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 16)
+ ecp224k1.B, _ = new(big.Int).SetString("00000000000000000000000000000000000000000000000000000005", 16)
+ ecp224k1.Gx, _ = new(big.Int).SetString("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", 16)
+ ecp224k1.Gy, _ = new(big.Int).SetString("7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", 16)
+ ecp224k1.BitSize = 224
+}
+
+func initS256() {
+ // See SEC 2 section 2.7.1
+ ecp256k1 = new(BitCurve)
+ ecp256k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
+ ecp256k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
+ ecp256k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
+ ecp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
+ ecp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
+ ecp256k1.BitSize = 256
+}
+
+// S160 returns a BitCurve which implements secp160k1 (see SEC 2 section 2.4.1)
+func S160() *BitCurve {
+ initonce.Do(initAll)
+ return ecp160k1
+}
+
+// S192 returns a BitCurve which implements secp192k1 (see SEC 2 section 2.5.1)
+func S192() *BitCurve {
+ initonce.Do(initAll)
+ return ecp192k1
+}
+
+// S224 returns a BitCurve which implements secp224k1 (see SEC 2 section 2.6.1)
+func S224() *BitCurve {
+ initonce.Do(initAll)
+ return ecp224k1
+}
+
+// S256 returns a BitCurve which implements secp256k1 (see SEC 2 section 2.7.1)
+func S256() *BitCurve {
+ initonce.Do(initAll)
+ return ecp256k1
+}
diff --git a/crypto/encrypt_decrypt_test.go b/crypto/encrypt_decrypt_test.go
new file mode 100644
index 000000000..44bb26f47
--- /dev/null
+++ b/crypto/encrypt_decrypt_test.go
@@ -0,0 +1,40 @@
+package crypto
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+func TestBox(t *testing.T) {
+ prv1 := ethutil.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f")
+ prv2 := ethutil.Hex2Bytes("d0b043b4c5d657670778242d82d68a29d25d7d711127d17b8e299f156dad361a")
+ pub2 := ethutil.Hex2Bytes("04bd27a63c91fe3233c5777e6d3d7b39204d398c8f92655947eb5a373d46e1688f022a1632d264725cbc7dc43ee1cfebde42fa0a86d08b55d2acfbb5e9b3b48dc5")
+
+ message := []byte("Hello, world.")
+ ct, err := Encrypt(pub2, message)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ pt, err := Decrypt(prv2, ct)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if !bytes.Equal(pt, message) {
+ fmt.Println("ecies: plaintext doesn't match message")
+ t.FailNow()
+ }
+
+ _, err = Decrypt(prv1, pt)
+ if err == nil {
+ fmt.Println("ecies: encryption should not have succeeded")
+ t.FailNow()
+ }
+
+}
diff --git a/crypto/key_manager.go b/crypto/key_manager.go
index cc2b9ff90..326e559e0 100644
--- a/crypto/key_manager.go
+++ b/crypto/key_manager.go
@@ -5,8 +5,11 @@ import (
"sync"
"github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/logger"
)
+var keylogger = logger.NewLogger("KEY")
+
type KeyManager struct {
keyRing *KeyRing
session string
@@ -104,6 +107,7 @@ func (k *KeyManager) Init(session string, cursor int, force bool) error {
}
if keyRing == nil {
keyRing = NewGeneratedKeyRing(1)
+ keylogger.Infof("Created keypair. Private key: %x\n", keyRing.keys[0].PrivateKey)
}
return k.reset(session, cursor, keyRing)
}
diff --git a/ethutil/script_unix.go b/ethutil/script_unix.go
index 6827d4e2f..9250dda57 100644
--- a/ethutil/script_unix.go
+++ b/ethutil/script_unix.go
@@ -2,47 +2,17 @@
package ethutil
-import (
- "fmt"
- "strings"
-
- "github.com/ethereum/serpent-go"
- "github.com/obscuren/mutan"
- "github.com/obscuren/mutan/backends"
-)
+import "github.com/ethereum/serpent-go"
// General compile function
func Compile(script string, silent bool) (ret []byte, err error) {
if len(script) > 2 {
- line := strings.Split(script, "\n")[0]
-
- if len(line) > 1 && line[0:2] == "#!" {
- switch line {
- case "#!serpent":
- byteCode, err := serpent.Compile(script)
- if err != nil {
- return nil, err
- }
-
- return byteCode, nil
- }
- } else {
-
- compiler := mutan.NewCompiler(backend.NewEthereumBackend())
- compiler.Silent = silent
- byteCode, errors := compiler.Compile(strings.NewReader(script))
- if len(errors) > 0 {
- var errs string
- for _, er := range errors {
- if er != nil {
- errs += er.Error()
- }
- }
- return nil, fmt.Errorf("%v", errs)
- }
-
- return byteCode, nil
+ byteCode, err := serpent.Compile(script)
+ if err != nil {
+ return nil, err
}
+
+ return byteCode, nil
}
return nil, nil
diff --git a/ethutil/script_windows.go b/ethutil/script_windows.go
index ef239cd51..1dedc5f60 100644
--- a/ethutil/script_windows.go
+++ b/ethutil/script_windows.go
@@ -2,31 +2,10 @@
package ethutil
-import (
- "fmt"
- "strings"
-
- "github.com/obscuren/mutan"
- "github.com/obscuren/mutan/backends"
-)
-
// General compile function
func Compile(script string, silent bool) (ret []byte, err error) {
if len(script) > 2 {
- compiler := mutan.NewCompiler(backend.NewEthereumBackend())
- compiler.Silent = silent
- byteCode, errors := compiler.Compile(strings.NewReader(script))
- if len(errors) > 0 {
- var errs string
- for _, er := range errors {
- if er != nil {
- errs += er.Error()
- }
- }
- return nil, fmt.Errorf("%v", errs)
- }
-
- return byteCode, nil
+ return nil, nil
}
return nil, nil
diff --git a/miner/miner.go b/miner/miner.go
index 589144c0c..4f677cbef 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -167,7 +167,6 @@ out:
}
func (self *Miner) reset() {
- println("reset")
close(self.powQuitCh)
self.powQuitCh = make(chan struct{})
}
@@ -192,7 +191,7 @@ func (self *Miner) mine() {
// Accumulate all valid transactions and apply them to the new state
// Error may be ignored. It's not important during mining
- receipts, txs, _, erroneous, err := blockManager.ProcessTransactions(coinbase, block.State(), block, block, transactions)
+ receipts, txs, _, erroneous, err := blockManager.ApplyTransactions(coinbase, block.State(), block, transactions, true)
if err != nil {
minerlogger.Debugln(err)
}
@@ -228,23 +227,33 @@ func (self *Miner) mine() {
func (self *Miner) finiliseTxs() types.Transactions {
// Sort the transactions by nonce in case of odd network propagation
- var txs types.Transactions
+ actualSize := len(self.localTxs) // See copy below
+ txs := make(types.Transactions, actualSize+self.eth.TxPool().Size())
state := self.eth.BlockManager().TransState()
// XXX This has to change. Coinbase is, for new, same as key.
key := self.eth.KeyManager()
- for _, ltx := range self.localTxs {
+ for i, ltx := range self.localTxs {
tx := types.NewTransactionMessage(ltx.To, ethutil.Big(ltx.Value), ethutil.Big(ltx.Gas), ethutil.Big(ltx.GasPrice), ltx.Data)
tx.Nonce = state.GetNonce(self.Coinbase)
state.SetNonce(self.Coinbase, tx.Nonce+1)
tx.Sign(key.PrivateKey())
- txs = append(txs, tx)
+ txs[i] = tx
}
- txs = append(txs, self.eth.TxPool().CurrentTransactions()...)
- sort.Sort(types.TxByNonce{txs})
+ // Faster than append
+ for _, tx := range self.eth.TxPool().CurrentTransactions() {
+ if tx.GasPrice.Cmp(self.MinAcceptedGasPrice) >= 0 {
+ txs[actualSize] = tx
+ actualSize++
+ }
+ }
+
+ newTransactions := make(types.Transactions, actualSize)
+ copy(newTransactions, txs[:actualSize])
+ sort.Sort(types.TxByNonce{newTransactions})
- return txs
+ return newTransactions
}
diff --git a/peer.go b/peer.go
index bf84f6e35..331e9de37 100644
--- a/peer.go
+++ b/peer.go
@@ -24,7 +24,7 @@ const (
// The size of the output buffer for writing messages
outputBufferSize = 50
// Current protocol version
- ProtocolVersion = 47
+ ProtocolVersion = 49
// Current P2P version
P2PVersion = 2
// Ethereum network version
@@ -129,9 +129,11 @@ type Peer struct {
statusKnown bool
// Last received pong message
- lastPong int64
- lastBlockReceived time.Time
- doneFetchingHashes bool
+ lastPong int64
+ lastBlockReceived time.Time
+ doneFetchingHashes bool
+ lastHashAt time.Time
+ lastHashRequestedAt time.Time
host []byte
port uint16
@@ -327,19 +329,16 @@ out:
}
}
+ switch msg.Type {
+ case wire.MsgGetBlockHashesTy:
+ p.lastHashRequestedAt = time.Now()
+ }
+
p.writeMessage(msg)
p.lastSend = time.Now()
// Ping timer
case <-pingTimer.C:
- /*
- timeSince := time.Since(time.Unix(p.lastPong, 0))
- if !p.pingStartTime.IsZero() && p.lastPong != 0 && timeSince > (pingPongTimer+30*time.Second) {
- peerlogger.Infof("Peer did not respond to latest pong fast enough, it took %s, disconnecting.\n", timeSince)
- p.Stop()
- return
- }
- */
p.writeMessage(wire.NewMessage(wire.MsgPingTy, ""))
p.pingStartTime = time.Now()
@@ -462,18 +461,6 @@ func (p *Peer) HandleInbound() {
// TMP
if p.statusKnown {
switch msg.Type {
- /*
- case wire.MsgGetTxsTy:
- // Get the current transactions of the pool
- txs := p.ethereum.TxPool().CurrentTransactions()
- // Get the RlpData values from the txs
- txsInterface := make([]interface{}, len(txs))
- for i, tx := range txs {
- txsInterface[i] = tx.RlpData()
- }
- // Broadcast it back to the peer
- p.QueueMessage(wire.NewMessage(wire.MsgTxTy, txsInterface))
- */
case wire.MsgGetBlockHashesTy:
if msg.Data.Len() < 2 {
@@ -508,6 +495,7 @@ func (p *Peer) HandleInbound() {
blockPool := p.ethereum.blockPool
foundCommonHash := false
+ p.lastHashAt = time.Now()
it := msg.Data.NewIterator()
for it.Next() {
@@ -524,9 +512,6 @@ func (p *Peer) HandleInbound() {
}
if !foundCommonHash {
- //if !p.FetchHashes() {
- // p.doneFetchingHashes = true
- //}
p.FetchHashes()
} else {
peerlogger.Infof("Found common hash (%x...)\n", p.lastReceivedHash[0:4])
@@ -756,7 +741,6 @@ func (p *Peer) handleHandshake(msg *wire.Msg) {
// Check correctness of p2p protocol version
if p2pVersion != P2PVersion {
- fmt.Println(p)
peerlogger.Debugf("Invalid P2P version. Require protocol %d, received %d\n", P2PVersion, p2pVersion)
p.Stop()
return
diff --git a/vm/address.go b/vm/address.go
index 06bd35f6b..be8921a3b 100644
--- a/vm/address.go
+++ b/vm/address.go
@@ -12,7 +12,7 @@ type Address interface {
}
type PrecompiledAddress struct {
- Gas *big.Int
+ Gas func(l int) *big.Int
fn func(in []byte) []byte
}
@@ -21,9 +21,19 @@ func (self PrecompiledAddress) Call(in []byte) []byte {
}
var Precompiled = map[uint64]*PrecompiledAddress{
- 1: &PrecompiledAddress{big.NewInt(500), ecrecoverFunc},
- 2: &PrecompiledAddress{big.NewInt(100), sha256Func},
- 3: &PrecompiledAddress{big.NewInt(100), ripemd160Func},
+ 1: &PrecompiledAddress{func(l int) *big.Int {
+ return GasEcrecover
+ }, ecrecoverFunc},
+ 2: &PrecompiledAddress{func(l int) *big.Int {
+ n := big.NewInt(int64(l+31)/32 + 1)
+ n.Mul(n, GasSha256)
+ return n
+ }, sha256Func},
+ 3: &PrecompiledAddress{func(l int) *big.Int {
+ n := big.NewInt(int64(l+31)/32 + 1)
+ n.Mul(n, GasRipemd)
+ return n
+ }, ripemd160Func},
}
func sha256Func(in []byte) []byte {
diff --git a/vm/common.go b/vm/common.go
index 9514ff6d3..5fd512687 100644
--- a/vm/common.go
+++ b/vm/common.go
@@ -27,10 +27,17 @@ var (
GasBalance = big.NewInt(20)
GasCreate = big.NewInt(100)
GasCall = big.NewInt(20)
+ GasCreateByte = big.NewInt(5)
+ GasSha3Byte = big.NewInt(10)
+ GasSha256Byte = big.NewInt(50)
+ GasRipemdByte = big.NewInt(50)
GasMemory = big.NewInt(1)
GasData = big.NewInt(5)
GasTx = big.NewInt(500)
GasLog = big.NewInt(32)
+ GasSha256 = big.NewInt(50)
+ GasRipemd = big.NewInt(50)
+ GasEcrecover = big.NewInt(100)
Pow256 = ethutil.BigPow(2, 256)
diff --git a/vm/vm_debug.go b/vm/vm_debug.go
index 0a541a769..c0a2d6d98 100644
--- a/vm/vm_debug.go
+++ b/vm/vm_debug.go
@@ -166,13 +166,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
case EXP:
require(2)
- exp := new(big.Int).Set(stack.data[stack.Len()-2])
- nbytes := 0
- for exp.Cmp(ethutil.Big0) > 0 {
- nbytes += 1
- exp.Rsh(exp, 8)
- }
- gas.Set(big.NewInt(int64(nbytes + 1)))
+ gas.Set(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()) + 1)))
// Gas only
case STOP:
gas.Set(ethutil.Big0)
@@ -260,9 +254,12 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
newMemSize.Mul(newMemSize, u256(32))
switch op {
- // Additional gas usage on *CODPY
case CALLDATACOPY, CODECOPY, EXTCODECOPY:
addStepGasUsage(new(big.Int).Div(newMemSize, u256(32)))
+ case SHA3:
+ g := new(big.Int).Div(newMemSize, u256(32))
+ g.Mul(g, GasSha3Byte)
+ addStepGasUsage(g)
}
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
@@ -744,12 +741,12 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
topics := make([][]byte, n)
- mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64()
- data := mem.Geti(mStart, mSize)
+ mSize, mStart := stack.Popn()
for i := 0; i < n; i++ {
topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32)
}
+ data := mem.Geti(mStart.Int64(), mSize.Int64())
log := &Log{closure.Address(), topics, data}
self.env.AddLog(log)
@@ -839,8 +836,13 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *
self.Printf("CREATE err %v", err)
} else {
- ref.SetCode(ret)
- msg.Output = ret
+ // gas < len(ret) * CreateDataGas == NO_CODE
+ dataGas := big.NewInt(int64(len(ret)))
+ dataGas.Mul(dataGas, GasCreateByte)
+ if closure.UseGas(dataGas) {
+ ref.SetCode(ret)
+ msg.Output = ret
+ }
stack.Push(ethutil.BigD(addr))
}
diff --git a/vm/vm_test.go b/vm/vm_test.go
index 19aa171a6..84ebf378f 100644
--- a/vm/vm_test.go
+++ b/vm/vm_test.go
@@ -13,7 +13,6 @@ import (
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/trie"
checker "gopkg.in/check.v1"
- // "github.com/obscuren/mutan"
)
type VmSuite struct{}
@@ -68,24 +67,18 @@ func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) {
}
func (s *VmSuite) TestDebugVm(c *checker.C) {
- // if mutan.Version < "0.6" {
- // t.Skip("skipping for mutan version", mutan.Version, " < 0.6")
- // }
closure, vm := setup(logger.DebugLevel, DebugVmTy)
ret, _, e := closure.Call(vm, nil)
c.Assert(e, checker.NotNil)
- c.Skip("Depends on mutan")
+ c.Skip("Depends on mutan. Requires serpent implementation")
c.Assert(ret, checker.DeepEquals, big9)
}
func (s *VmSuite) TestVm(c *checker.C) {
- // if mutan.Version < "0.6" {
- // t.Skip("skipping for mutan version", mutan.Version, " < 0.6")
- // }
closure, vm := setup(logger.DebugLevel, StandardVmTy)
ret, _, e := closure.Call(vm, nil)
c.Assert(e, checker.NotNil)
- c.Skip("Depends on mutan")
+ c.Skip("Depends on mutan. Requires serpent implementation")
c.Assert(ret, checker.DeepEquals, big9)
}
@@ -142,7 +135,7 @@ func (s *VmSuite) TestBuildInSha256(c *checker.C) {
`, DebugVmTy)
exp := crypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32))
- c.Skip("Depends on mutan")
+ c.Skip("Depends on mutan. Requires serpent implementation")
c.Assert(ret, checker.DeepEquals, exp)
}
@@ -157,7 +150,7 @@ func (s *VmSuite) TestBuildInRipemd(c *checker.C) {
`, DebugVmTy)
exp := ethutil.RightPadBytes(crypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32)
- c.Skip("Depends on mutan")
+ c.Skip("Depends on mutan. Requires serpent implementation")
c.Assert(ret, checker.DeepEquals, exp)
}
diff --git a/whisper/envelope.go b/whisper/envelope.go
new file mode 100644
index 000000000..eb80098ad
--- /dev/null
+++ b/whisper/envelope.go
@@ -0,0 +1,96 @@
+package whisper
+
+import (
+ "bytes"
+ "encoding/binary"
+ "io"
+ "time"
+
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+const (
+ DefaultPow = 50 * time.Millisecond
+)
+
+type Envelope struct {
+ Expiry uint32 // Whisper protocol specifies int32, really should be int64
+ Ttl uint32 // ^^^^^^
+ Topics [][]byte
+ Data []byte
+ Nonce uint32
+
+ hash Hash
+}
+
+func NewEnvelopeFromReader(reader io.Reader) (*Envelope, error) {
+ var envelope Envelope
+
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(reader)
+
+ h := H(crypto.Sha3(buf.Bytes()))
+ if err := rlp.Decode(buf, &envelope); err != nil {
+ return nil, err
+ }
+
+ envelope.hash = h
+
+ return &envelope, nil
+}
+
+func (self *Envelope) Hash() Hash {
+ if self.hash == EmptyHash {
+ self.hash = H(crypto.Sha3(ethutil.Encode(self)))
+ }
+
+ return self.hash
+}
+
+func NewEnvelope(ttl time.Duration, topics [][]byte, data *Message) *Envelope {
+ exp := time.Now().Add(ttl)
+
+ return &Envelope{uint32(exp.Unix()), uint32(ttl.Seconds()), topics, data.Bytes(), 0, Hash{}}
+}
+
+func (self *Envelope) Seal(pow time.Duration) {
+ self.proveWork(pow)
+}
+
+func (self *Envelope) proveWork(dura time.Duration) {
+ var bestBit int
+ d := make([]byte, 64)
+ copy(d[:32], ethutil.Encode(self.withoutNonce()))
+
+ then := time.Now().Add(dura).UnixNano()
+ for n := uint32(0); time.Now().UnixNano() < then; {
+ for i := 0; i < 1024; i++ {
+ binary.BigEndian.PutUint32(d[60:], n)
+
+ fbs := ethutil.FirstBitSet(ethutil.BigD(crypto.Sha3(d)))
+ if fbs > bestBit {
+ bestBit = fbs
+ self.Nonce = n
+ }
+
+ n++
+ }
+ }
+}
+
+func (self *Envelope) valid() bool {
+ d := make([]byte, 64)
+ copy(d[:32], ethutil.Encode(self.withoutNonce()))
+ binary.BigEndian.PutUint32(d[60:], self.Nonce)
+ return ethutil.FirstBitSet(ethutil.BigD(crypto.Sha3(d))) > 0
+}
+
+func (self *Envelope) withoutNonce() interface{} {
+ return []interface{}{self.Expiry, self.Ttl, ethutil.ByteSliceToInterface(self.Topics), self.Data}
+}
+
+func (self *Envelope) RlpData() interface{} {
+ return []interface{}{self.Expiry, self.Ttl, ethutil.ByteSliceToInterface(self.Topics), self.Data, self.Nonce}
+}
diff --git a/whisper/main.go b/whisper/main.go
new file mode 100644
index 000000000..3868f604f
--- /dev/null
+++ b/whisper/main.go
@@ -0,0 +1,46 @@
+// +build none
+
+package main
+
+import (
+ "fmt"
+ "log"
+ "net"
+ "os"
+
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/whisper"
+ "github.com/obscuren/secp256k1-go"
+)
+
+func main() {
+ logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel))
+
+ pub, sec := secp256k1.GenerateKeyPair()
+
+ whisper := whisper.New(pub, sec)
+
+ srv := p2p.Server{
+ MaxPeers: 10,
+ Identity: p2p.NewSimpleClientIdentity("whisper-go", "1.0", "", string(pub)),
+ ListenAddr: ":30303",
+ NAT: p2p.UPNP(),
+
+ Protocols: []p2p.Protocol{whisper.Protocol()},
+ }
+ if err := srv.Start(); err != nil {
+ fmt.Println("could not start server:", err)
+ os.Exit(1)
+ }
+
+ // add seed peers
+ seed, err := net.ResolveTCPAddr("tcp", "poc-7.ethdev.com:30300")
+ if err != nil {
+ fmt.Println("couldn't resolve:", err)
+ os.Exit(1)
+ }
+ srv.SuggestPeer(seed.IP, seed.Port, nil)
+
+ select {}
+}
diff --git a/whisper/message.go b/whisper/message.go
new file mode 100644
index 000000000..408b9f7df
--- /dev/null
+++ b/whisper/message.go
@@ -0,0 +1,64 @@
+package whisper
+
+import (
+ "time"
+
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+type Message struct {
+ Flags byte
+ Signature []byte
+ Payload []byte
+}
+
+func NewMessage(payload []byte) *Message {
+ return &Message{Flags: 0, Payload: payload}
+}
+
+func (self *Message) hash() []byte {
+ return crypto.Sha3(append([]byte{self.Flags}, self.Payload...))
+}
+
+func (self *Message) sign(key []byte) (err error) {
+ self.Flags = 1
+ self.Signature, err = crypto.Sign(self.hash(), key)
+ return
+}
+
+func (self *Message) Encrypt(from, to []byte) (err error) {
+ err = self.sign(from)
+ if err != nil {
+ return err
+ }
+
+ self.Payload, err = crypto.Encrypt(to, self.Payload)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (self *Message) Bytes() []byte {
+ return append([]byte{self.Flags}, append(self.Signature, self.Payload...)...)
+}
+
+type Opts struct {
+ From, To []byte // private(sender), public(receiver) key
+ Ttl time.Duration
+ Topics [][]byte
+}
+
+func (self *Message) Seal(pow time.Duration, opts Opts) (*Envelope, error) {
+ if len(opts.To) > 0 && len(opts.From) > 0 {
+ if err := self.Encrypt(opts.From, opts.To); err != nil {
+ return nil, err
+ }
+ }
+
+ envelope := NewEnvelope(DefaultTtl, opts.Topics, self)
+ envelope.Seal(pow)
+
+ return envelope, nil
+}
diff --git a/whisper/peer.go b/whisper/peer.go
new file mode 100644
index 000000000..d42b374b5
--- /dev/null
+++ b/whisper/peer.go
@@ -0,0 +1,128 @@
+package whisper
+
+import (
+ "fmt"
+ "io/ioutil"
+ "time"
+
+ "github.com/ethereum/go-ethereum/p2p"
+ "gopkg.in/fatih/set.v0"
+)
+
+const (
+ protocolVersion = 0x02
+)
+
+type peer struct {
+ host *Whisper
+ peer *p2p.Peer
+ ws p2p.MsgReadWriter
+
+ // XXX Eventually this is going to reach exceptional large space. We need an expiry here
+ known *set.Set
+
+ quit chan struct{}
+}
+
+func NewPeer(host *Whisper, p *p2p.Peer, ws p2p.MsgReadWriter) *peer {
+ return &peer{host, p, ws, set.New(), make(chan struct{})}
+}
+
+func (self *peer) init() error {
+ if err := self.handleStatus(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (self *peer) start() {
+ go self.update()
+ self.peer.Infoln("whisper started")
+}
+
+func (self *peer) stop() {
+ self.peer.Infoln("whisper stopped")
+
+ close(self.quit)
+}
+
+func (self *peer) update() {
+ relay := time.NewTicker(300 * time.Millisecond)
+out:
+ for {
+ select {
+ case <-relay.C:
+ err := self.broadcast(self.host.envelopes())
+ if err != nil {
+ self.peer.Infoln(err)
+ break out
+ }
+
+ case <-self.quit:
+ break out
+ }
+ }
+}
+
+func (self *peer) broadcast(envelopes []*Envelope) error {
+ envs := make([]interface{}, len(envelopes))
+ i := 0
+ for _, envelope := range envelopes {
+ if !self.known.Has(envelope.Hash()) {
+ envs[i] = envelope
+ self.known.Add(envelope.Hash())
+ i++
+ }
+ }
+
+ if i > 0 {
+ msg := p2p.NewMsg(envelopesMsg, envs[:i]...)
+ if err := self.ws.WriteMsg(msg); err != nil {
+ return err
+ }
+ self.peer.Infoln("broadcasted", i, "message(s)")
+ }
+
+ return nil
+}
+
+func (self *peer) addKnown(envelope *Envelope) {
+ self.known.Add(envelope.Hash())
+}
+
+func (self *peer) handleStatus() error {
+ ws := self.ws
+
+ if err := ws.WriteMsg(self.statusMsg()); err != nil {
+ return err
+ }
+
+ msg, err := ws.ReadMsg()
+ if err != nil {
+ return err
+ }
+
+ if msg.Code != statusMsg {
+ return fmt.Errorf("peer send %x before status msg", msg.Code)
+ }
+
+ data, err := ioutil.ReadAll(msg.Payload)
+ if err != nil {
+ return err
+ }
+
+ if len(data) == 0 {
+ return fmt.Errorf("malformed status. data len = 0")
+ }
+
+ if pv := data[0]; pv != protocolVersion {
+ return fmt.Errorf("protocol version mismatch %d != %d", pv, protocolVersion)
+ }
+
+ return nil
+}
+
+func (self *peer) statusMsg() p2p.Msg {
+ return p2p.NewMsg(statusMsg, protocolVersion)
+}
diff --git a/whisper/sort.go b/whisper/sort.go
new file mode 100644
index 000000000..8c5b46e9e
--- /dev/null
+++ b/whisper/sort.go
@@ -0,0 +1,25 @@
+package whisper
+
+import "sort"
+
+type sortedKeys struct {
+ k []int32
+}
+
+func (self *sortedKeys) Len() int { return len(self.k) }
+func (self *sortedKeys) Less(i, j int) bool { return self.k[i] < self.k[j] }
+func (self *sortedKeys) Swap(i, j int) { self.k[i], self.k[j] = self.k[j], self.k[i] }
+
+func sortKeys(m map[int32]Hash) []int32 {
+ sorted := new(sortedKeys)
+ sorted.k = make([]int32, len(m))
+ i := 0
+ for key, _ := range m {
+ sorted.k[i] = key
+ i++
+ }
+
+ sort.Sort(sorted)
+
+ return sorted.k
+}
diff --git a/whisper/sort_test.go b/whisper/sort_test.go
new file mode 100644
index 000000000..5d8177d41
--- /dev/null
+++ b/whisper/sort_test.go
@@ -0,0 +1,19 @@
+package whisper
+
+import "testing"
+
+func TestSorting(t *testing.T) {
+ m := map[int32]Hash{
+ 1: HS("1"),
+ 3: HS("3"),
+ 2: HS("2"),
+ 5: HS("5"),
+ }
+ exp := []int32{1, 2, 3, 5}
+ res := sortKeys(m)
+ for i, k := range res {
+ if k != exp[i] {
+ t.Error(k, "failed. Expected", exp[i])
+ }
+ }
+}
diff --git a/whisper/whisper.go b/whisper/whisper.go
new file mode 100644
index 000000000..b4e37b959
--- /dev/null
+++ b/whisper/whisper.go
@@ -0,0 +1,193 @@
+package whisper
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/p2p"
+ "gopkg.in/fatih/set.v0"
+)
+
+// MOVE ME
+type Hash struct {
+ hash string
+}
+
+var EmptyHash Hash
+
+func H(hash []byte) Hash {
+ return Hash{string(hash)}
+}
+func HS(hash string) Hash {
+ return Hash{hash}
+}
+
+func (self Hash) Compare(other Hash) int {
+ return bytes.Compare([]byte(self.hash), []byte(other.hash))
+}
+
+// MOVE ME END
+
+const (
+ statusMsg = 0x0
+ envelopesMsg = 0x01
+)
+
+const DefaultTtl = 50 * time.Second
+
+type Whisper struct {
+ pub, sec []byte
+ protocol p2p.Protocol
+
+ mmu sync.RWMutex
+ messages map[Hash]*Envelope
+ expiry map[uint32]*set.SetNonTS
+
+ quit chan struct{}
+}
+
+func New(pub, sec []byte) *Whisper {
+ whisper := &Whisper{
+ pub: pub,
+ sec: sec,
+ messages: make(map[Hash]*Envelope),
+ expiry: make(map[uint32]*set.SetNonTS),
+ quit: make(chan struct{}),
+ }
+ go whisper.update()
+
+ msg := NewMessage([]byte(fmt.Sprintf("Hello world. This is whisper-go. Incase you're wondering; the time is %v", time.Now())))
+ envelope, _ := msg.Seal(DefaultPow, Opts{
+ Ttl: DefaultTtl,
+ })
+ if err := whisper.Send(envelope); err != nil {
+ fmt.Println(err)
+ }
+
+ // p2p whisper sub protocol handler
+ whisper.protocol = p2p.Protocol{
+ Name: "shh",
+ Version: 2,
+ Length: 2,
+ Run: whisper.msgHandler,
+ }
+
+ return whisper
+}
+
+func (self *Whisper) Stop() {
+ close(self.quit)
+}
+
+func (self *Whisper) Send(envelope *Envelope) error {
+ return self.add(envelope)
+}
+
+// Main handler for passing whisper messages to whisper peer objects
+func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
+ wpeer := NewPeer(self, peer, ws)
+ // initialise whisper peer (handshake/status)
+ if err := wpeer.init(); err != nil {
+ return err
+ }
+ // kick of the main handler for broadcasting/managing envelopes
+ go wpeer.start()
+ defer wpeer.stop()
+
+ // Main *read* loop. Writing is done by the peer it self.
+ for {
+ msg, err := ws.ReadMsg()
+ if err != nil {
+ return err
+ }
+
+ envelope, err := NewEnvelopeFromReader(msg.Payload)
+ if err != nil {
+ peer.Infoln(err)
+ continue
+ }
+
+ if err := self.add(envelope); err != nil {
+ // TODO Punish peer here. Invalid envelope.
+ peer.Infoln(err)
+ }
+ wpeer.addKnown(envelope)
+ }
+}
+
+// takes care of adding envelopes to the messages pool. At this moment no sanity checks are being performed.
+func (self *Whisper) add(envelope *Envelope) error {
+ if !envelope.valid() {
+ return errors.New("invalid pow for envelope")
+ }
+
+ self.mmu.Lock()
+ defer self.mmu.Unlock()
+
+ hash := envelope.Hash()
+ self.messages[hash] = envelope
+ if self.expiry[envelope.Expiry] == nil {
+ self.expiry[envelope.Expiry] = set.NewNonTS()
+ }
+
+ if !self.expiry[envelope.Expiry].Has(hash) {
+ self.expiry[envelope.Expiry].Add(hash)
+ // TODO notify listeners (given that we had any ...)
+ }
+
+ fmt.Println("add", envelope)
+
+ return nil
+}
+
+func (self *Whisper) update() {
+ expire := time.NewTicker(800 * time.Millisecond)
+out:
+ for {
+ select {
+ case <-expire.C:
+ self.expire()
+ case <-self.quit:
+ break out
+ }
+ }
+}
+
+func (self *Whisper) expire() {
+ self.mmu.Lock()
+ defer self.mmu.Unlock()
+
+ now := uint32(time.Now().Unix())
+ for then, hashSet := range self.expiry {
+ if then > now {
+ continue
+ }
+
+ hashSet.Each(func(v interface{}) bool {
+ delete(self.messages, v.(Hash))
+ return true
+ })
+ self.expiry[then].Clear()
+ }
+}
+
+func (self *Whisper) envelopes() (envelopes []*Envelope) {
+ self.mmu.RLock()
+ defer self.mmu.RUnlock()
+
+ envelopes = make([]*Envelope, len(self.messages))
+ i := 0
+ for _, envelope := range self.messages {
+ envelopes[i] = envelope
+ i++
+ }
+
+ return
+}
+
+func (self *Whisper) Protocol() p2p.Protocol {
+ return self.protocol
+}
diff --git a/wire/messaging.go b/wire/messaging.go
index b919aa0f4..9c6cb5944 100644
--- a/wire/messaging.go
+++ b/wire/messaging.go
@@ -33,8 +33,7 @@ const (
MsgGetPeersTy = 0x04
MsgPeersTy = 0x05
- MsgStatusTy = 0x10
- //MsgGetTxsTy = 0x11
+ MsgStatusTy = 0x10
MsgTxTy = 0x12
MsgGetBlockHashesTy = 0x13
MsgBlockHashesTy = 0x14
diff --git a/xeth/pipe.go b/xeth/pipe.go
index 6da92cd23..2ca8134ce 100644
--- a/xeth/pipe.go
+++ b/xeth/pipe.go
@@ -136,11 +136,17 @@ func (self *XEth) Transact(key *crypto.KeyPair, to []byte, value, gas, price *et
tx.Nonce = nonce
tx.Sign(key.PrivateKey)
+
+ // Do some pre processing for our "pre" events and hooks
+ block := self.blockChain.NewBlock(key.Address())
+ coinbase := state.GetStateObject(key.Address())
+ coinbase.SetGasPool(block.GasLimit)
+ self.blockManager.ApplyTransactions(coinbase, state, block, types.Transactions{tx}, true)
+
err := self.obj.TxPool().Add(tx)
if err != nil {
return nil, err
}
-
state.SetNonce(key.Address(), nonce+1)
if contractCreation {