aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain
diff options
context:
space:
mode:
Diffstat (limited to 'ethchain')
-rw-r--r--ethchain/.gitignore12
-rw-r--r--ethchain/block.go363
-rw-r--r--ethchain/block_chain.go184
-rw-r--r--ethchain/block_manager.go627
-rw-r--r--ethchain/block_manager_test.go75
-rw-r--r--ethchain/contract.go66
-rw-r--r--ethchain/dagger.go199
-rw-r--r--ethchain/dagger_test.go18
-rw-r--r--ethchain/error.go42
-rw-r--r--ethchain/fees.go65
-rw-r--r--ethchain/genesis.go39
-rw-r--r--ethchain/stack.go167
-rw-r--r--ethchain/transaction.go157
-rw-r--r--ethchain/transaction_pool.go219
-rw-r--r--ethchain/transaction_test.go54
15 files changed, 2287 insertions, 0 deletions
diff --git a/ethchain/.gitignore b/ethchain/.gitignore
new file mode 100644
index 000000000..f725d58d1
--- /dev/null
+++ b/ethchain/.gitignore
@@ -0,0 +1,12 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile ~/.gitignore_global
+
+/tmp
+*/**/*un~
+*un~
+.DS_Store
+*/**/.DS_Store
+
diff --git a/ethchain/block.go b/ethchain/block.go
new file mode 100644
index 000000000..a7a1f787b
--- /dev/null
+++ b/ethchain/block.go
@@ -0,0 +1,363 @@
+package ethchain
+
+import (
+ "fmt"
+ "github.com/ethereum/eth-go/ethutil"
+ "math/big"
+ "time"
+)
+
+type BlockInfo struct {
+ Number uint64
+ Hash []byte
+ Parent []byte
+}
+
+func (bi *BlockInfo) RlpDecode(data []byte) {
+ decoder := ethutil.NewValueFromBytes(data)
+
+ bi.Number = decoder.Get(0).Uint()
+ bi.Hash = decoder.Get(1).Bytes()
+ bi.Parent = decoder.Get(2).Bytes()
+}
+
+func (bi *BlockInfo) RlpEncode() []byte {
+ return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent})
+}
+
+type Block struct {
+ // Hash to the previous block
+ PrevHash []byte
+ // Uncles of this block
+ Uncles []*Block
+ UncleSha []byte
+ // The coin base address
+ Coinbase []byte
+ // Block Trie state
+ state *ethutil.Trie
+ // Difficulty for the current block
+ Difficulty *big.Int
+ // Creation time
+ Time int64
+ // Extra data
+ Extra string
+ // Block Nonce for verification
+ Nonce []byte
+ // List of transactions and/or contracts
+ transactions []*Transaction
+ TxSha []byte
+}
+
+// New block takes a raw encoded string
+// XXX DEPRICATED
+func NewBlockFromData(raw []byte) *Block {
+ return NewBlockFromBytes(raw)
+}
+
+func NewBlockFromBytes(raw []byte) *Block {
+ block := &Block{}
+ block.RlpDecode(raw)
+
+ return block
+}
+
+// New block takes a raw encoded string
+func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block {
+ block := &Block{}
+ block.RlpValueDecode(rlpValue)
+
+ return block
+}
+
+func CreateBlock(root interface{},
+ prevHash []byte,
+ base []byte,
+ Difficulty *big.Int,
+ Nonce []byte,
+ extra string,
+ txes []*Transaction) *Block {
+
+ 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,
+ }
+ block.SetTransactions(txes)
+ block.SetUncles([]*Block{})
+
+ block.state = ethutil.NewTrie(ethutil.Config.Db, root)
+
+ for _, tx := range txes {
+ block.MakeContract(tx)
+ }
+
+ return block
+}
+
+// Returns a hash of the block
+func (block *Block) Hash() []byte {
+ return ethutil.Sha3Bin(block.RlpValue().Encode())
+}
+
+func (block *Block) HashNoNonce() []byte {
+ return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra}))
+}
+
+func (block *Block) PrintHash() {
+ fmt.Println(block)
+ fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce})))
+}
+
+func (block *Block) State() *ethutil.Trie {
+ return block.state
+}
+
+func (block *Block) Transactions() []*Transaction {
+ return block.transactions
+}
+
+func (block *Block) GetContract(addr []byte) *Contract {
+ data := block.state.Get(string(addr))
+ if data == "" {
+ return nil
+ }
+
+ contract := &Contract{}
+ contract.RlpDecode([]byte(data))
+
+ return contract
+}
+func (block *Block) UpdateContract(addr []byte, contract *Contract) {
+ // Make sure the state is synced
+ contract.State().Sync()
+
+ block.state.Update(string(addr), string(contract.RlpEncode()))
+}
+
+func (block *Block) GetAddr(addr []byte) *Address {
+ var address *Address
+
+ data := block.State().Get(string(addr))
+ if data == "" {
+ address = NewAddress(big.NewInt(0))
+ } else {
+ address = NewAddressFromData([]byte(data))
+ }
+
+ return address
+}
+func (block *Block) UpdateAddr(addr []byte, address *Address) {
+ block.state.Update(string(addr), string(address.RlpEncode()))
+}
+
+func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
+ contract := block.GetContract(addr)
+ // If we can't pay the fee return
+ if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ {
+ fmt.Println("Contract has insufficient funds", contract.Amount, fee)
+
+ return false
+ }
+
+ base := new(big.Int)
+ contract.Amount = base.Sub(contract.Amount, fee)
+ block.state.Update(string(addr), string(contract.RlpEncode()))
+
+ data := block.state.Get(string(block.Coinbase))
+
+ // Get the ether (Coinbase) and add the fee (gief fee to miner)
+ ether := NewAddressFromData([]byte(data))
+
+ base = new(big.Int)
+ ether.Amount = base.Add(ether.Amount, fee)
+
+ block.state.Update(string(block.Coinbase), string(ether.RlpEncode()))
+
+ return true
+}
+
+func (block *Block) BlockInfo() BlockInfo {
+ bi := BlockInfo{}
+ data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
+ bi.RlpDecode(data)
+
+ return bi
+}
+
+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)
+ }
+}
+
+/////// Block Encoding
+func (block *Block) encodedUncles() interface{} {
+ uncles := make([]interface{}, len(block.Uncles))
+ for i, uncle := range block.Uncles {
+ uncles[i] = uncle.RlpEncode()
+ }
+
+ return uncles
+}
+
+func (block *Block) encodedTxs() interface{} {
+ // Marshal the transactions of this block
+ encTx := make([]interface{}, len(block.transactions))
+ for i, tx := range block.transactions {
+ // Cast it to a string (safe)
+ encTx[i] = tx.RlpData()
+ }
+
+ return encTx
+}
+
+func (block *Block) rlpTxs() interface{} {
+ // Marshal the transactions of this block
+ encTx := make([]interface{}, len(block.transactions))
+ for i, tx := range block.transactions {
+ // Cast it to a string (safe)
+ encTx[i] = tx.RlpData()
+ }
+
+ return encTx
+}
+
+func (block *Block) rlpUncles() interface{} {
+ // Marshal the transactions of this block
+ uncles := make([]interface{}, len(block.Uncles))
+ for i, uncle := range block.Uncles {
+ // Cast it to a string (safe)
+ uncles[i] = uncle.header()
+ }
+
+ return uncles
+}
+
+func (block *Block) SetUncles(uncles []*Block) {
+ block.Uncles = uncles
+
+ // Sha of the concatenated uncles
+ block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles()))
+}
+
+func (block *Block) SetTransactions(txs []*Transaction) {
+ block.transactions = txs
+
+ block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs()))
+}
+
+func (block *Block) RlpValue() *ethutil.RlpValue {
+ return ethutil.NewRlpValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()})
+}
+
+func (block *Block) RlpEncode() []byte {
+ // Encode a slice interface which contains the header and the list of
+ // transactions.
+ return block.RlpValue().Encode()
+}
+
+func (block *Block) RlpDecode(data []byte) {
+ rlpValue := ethutil.NewValueFromBytes(data)
+ block.RlpValueDecode(rlpValue)
+}
+
+func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
+ header := decoder.Get(0)
+
+ block.PrevHash = header.Get(0).Bytes()
+ block.UncleSha = header.Get(1).Bytes()
+ block.Coinbase = header.Get(2).Bytes()
+ block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
+ block.TxSha = header.Get(4).Bytes()
+ block.Difficulty = header.Get(5).BigInt()
+ block.Time = int64(header.Get(6).BigInt().Uint64())
+ block.Extra = header.Get(7).Str()
+ block.Nonce = header.Get(8).Bytes()
+
+ // Tx list might be empty if this is an uncle. Uncles only have their
+ // header set.
+ if decoder.Get(1).IsNil() == false { // Yes explicitness
+ txes := decoder.Get(1)
+ block.transactions = make([]*Transaction, txes.Len())
+ for i := 0; i < txes.Len(); i++ {
+ tx := NewTransactionFromValue(txes.Get(i))
+
+ block.transactions[i] = tx
+
+ /*
+ if ethutil.Config.Debug {
+ ethutil.Config.Db.Put(tx.Hash(), ethutil.Encode(tx))
+ }
+ */
+ }
+
+ }
+
+ if decoder.Get(2).IsNil() == false { // Yes explicitness
+ uncles := decoder.Get(2)
+ block.Uncles = make([]*Block, uncles.Len())
+ for i := 0; i < uncles.Len(); i++ {
+ block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i))
+ }
+ }
+
+}
+
+func NewUncleBlockFromValue(header *ethutil.Value) *Block {
+ block := &Block{}
+
+ block.PrevHash = header.Get(0).Bytes()
+ block.UncleSha = header.Get(1).Bytes()
+ block.Coinbase = header.Get(2).Bytes()
+ block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
+ block.TxSha = header.Get(4).Bytes()
+ block.Difficulty = header.Get(5).BigInt()
+ block.Time = int64(header.Get(6).BigInt().Uint64())
+ block.Extra = header.Get(7).Str()
+ block.Nonce = header.Get(8).Bytes()
+
+ return 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)
+}
+
+//////////// UNEXPORTED /////////////////
+func (block *Block) header() []interface{} {
+ return []interface{}{
+ // Sha of the previous block
+ block.PrevHash,
+ // Sha of uncles
+ block.UncleSha,
+ // Coinbase address
+ block.Coinbase,
+ // root state
+ block.state.Root,
+ // Sha of tx
+ block.TxSha,
+ // Current block Difficulty
+ block.Difficulty,
+ // Time the block was found?
+ block.Time,
+ // Extra data
+ block.Extra,
+ // Block's Nonce for validation
+ block.Nonce,
+ }
+}
diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go
new file mode 100644
index 000000000..56bc43a8e
--- /dev/null
+++ b/ethchain/block_chain.go
@@ -0,0 +1,184 @@
+package ethchain
+
+import (
+ "bytes"
+ "github.com/ethereum/eth-go/ethutil"
+ "log"
+ "math"
+ "math/big"
+)
+
+type BlockChain struct {
+ // The famous, the fabulous Mister GENESIIIIIIS (block)
+ genesisBlock *Block
+ // Last known total difficulty
+ TD *big.Int
+
+ LastBlockNumber uint64
+
+ CurrentBlock *Block
+ LastBlockHash []byte
+}
+
+func NewBlockChain() *BlockChain {
+ bc := &BlockChain{}
+ bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis))
+
+ bc.setLastBlock()
+
+ return bc
+}
+
+func (bc *BlockChain) Genesis() *Block {
+ return bc.genesisBlock
+}
+
+func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
+ var root interface{}
+ var lastBlockTime int64
+ hash := ZeroHash256
+
+ if bc.CurrentBlock != nil {
+ root = bc.CurrentBlock.State().Root
+ hash = bc.LastBlockHash
+ lastBlockTime = bc.CurrentBlock.Time
+ }
+
+ block := CreateBlock(
+ root,
+ hash,
+ coinbase,
+ ethutil.BigPow(2, 32),
+ nil,
+ "",
+ txs)
+
+ if bc.CurrentBlock != nil {
+ var mul *big.Int
+ if block.Time < lastBlockTime+42 {
+ mul = big.NewInt(1)
+ } else {
+ mul = big.NewInt(-1)
+ }
+
+ diff := new(big.Int)
+ diff.Add(diff, bc.CurrentBlock.Difficulty)
+ diff.Div(diff, big.NewInt(1024))
+ diff.Mul(diff, mul)
+ diff.Add(diff, bc.CurrentBlock.Difficulty)
+ block.Difficulty = diff
+ }
+
+ return block
+}
+
+func (bc *BlockChain) HasBlock(hash []byte) bool {
+ data, _ := ethutil.Config.Db.Get(hash)
+ return len(data) != 0
+}
+
+func (bc *BlockChain) GenesisBlock() *Block {
+ return bc.genesisBlock
+}
+
+// Get chain return blocks from hash up to max in RLP format
+func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} {
+ var chain []interface{}
+ // Get the current hash to start with
+ currentHash := bc.CurrentBlock.Hash()
+ // Get the last number on the block chain
+ lastNumber := bc.BlockInfo(bc.CurrentBlock).Number
+ // Get the parents number
+ parentNumber := bc.BlockInfoByHash(hash).Number
+ // Get the min amount. We might not have max amount of blocks
+ count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max)))
+ startNumber := parentNumber + count
+
+ num := lastNumber
+ for ; num > startNumber; currentHash = bc.GetBlock(currentHash).PrevHash {
+ num--
+ }
+ for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ {
+ // Get the block of the chain
+ block := bc.GetBlock(currentHash)
+ currentHash = block.PrevHash
+
+ chain = append(chain, block.RlpValue().Value)
+ //chain = append([]interface{}{block.RlpValue().Value}, chain...)
+
+ num--
+ }
+
+ return chain
+}
+
+func (bc *BlockChain) setLastBlock() {
+ data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
+ if len(data) != 0 {
+ block := NewBlockFromBytes(data)
+ info := bc.BlockInfo(block)
+ bc.CurrentBlock = block
+ bc.LastBlockHash = block.Hash()
+ bc.LastBlockNumber = info.Number
+
+ log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber)
+ }
+
+ // Set the last know difficulty (might be 0x0 as initial value, Genesis)
+ bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
+}
+
+func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
+ ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes())
+ bc.TD = td
+}
+
+// Add a block to the chain and record addition information
+func (bc *BlockChain) Add(block *Block) {
+ bc.writeBlockInfo(block)
+
+ // Prepare the genesis block
+ bc.CurrentBlock = block
+ bc.LastBlockHash = block.Hash()
+
+ ethutil.Config.Db.Put(block.Hash(), block.RlpEncode())
+}
+
+func (bc *BlockChain) GetBlock(hash []byte) *Block {
+ data, _ := ethutil.Config.Db.Get(hash)
+
+ return NewBlockFromData(data)
+}
+
+func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo {
+ bi := BlockInfo{}
+ data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...))
+ bi.RlpDecode(data)
+
+ return bi
+}
+
+func (bc *BlockChain) BlockInfo(block *Block) BlockInfo {
+ bi := BlockInfo{}
+ data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
+ bi.RlpDecode(data)
+
+ return bi
+}
+
+// Unexported method for writing extra non-essential block info to the db
+func (bc *BlockChain) writeBlockInfo(block *Block) {
+ bc.LastBlockNumber++
+ bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash}
+
+ // For now we use the block hash with the words "info" appended as key
+ ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode())
+}
+
+func (bc *BlockChain) Stop() {
+ if bc.CurrentBlock != nil {
+ ethutil.Config.Db.Put([]byte("LastBlock"), bc.CurrentBlock.RlpEncode())
+
+ log.Println("[CHAIN] Stopped")
+ }
+}
diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go
new file mode 100644
index 000000000..92f20e253
--- /dev/null
+++ b/ethchain/block_manager.go
@@ -0,0 +1,627 @@
+package ethchain
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/obscuren/secp256k1-go"
+ "log"
+ "math"
+ "math/big"
+ "strconv"
+ "sync"
+ "time"
+)
+
+type BlockProcessor interface {
+ ProcessBlock(block *Block)
+}
+
+func CalculateBlockReward(block *Block, uncleLength int) *big.Int {
+ return BlockReward
+}
+
+type BlockManager struct {
+ // Mutex for locking the block processor. Blocks can only be handled one at a time
+ mutex sync.Mutex
+
+ // The block chain :)
+ bc *BlockChain
+
+ // Stack for processing contracts
+ stack *Stack
+ // non-persistent key/value memory storage
+ mem map[string]*big.Int
+
+ TransactionPool *TxPool
+
+ Pow PoW
+
+ Speaker PublicSpeaker
+
+ SecondaryBlockProcessor BlockProcessor
+}
+
+func AddTestNetFunds(block *Block) {
+ for _, addr := range []string{
+ "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin
+ "93658b04240e4bd4046fd2d6d417d20f146f4b43", // Jeffrey
+ "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit
+ "80c01a26338f0d905e295fccb71fa9ea849ffa12", // Alex
+ } {
+ //log.Println("2^200 Wei to", addr)
+ codedAddr, _ := hex.DecodeString(addr)
+ addr := block.GetAddr(codedAddr)
+ addr.Amount = ethutil.BigPow(2, 200)
+ block.UpdateAddr(codedAddr, addr)
+ }
+}
+
+func NewBlockManager(speaker PublicSpeaker) *BlockManager {
+ bm := &BlockManager{
+ //server: s,
+ bc: NewBlockChain(),
+ stack: NewStack(),
+ mem: make(map[string]*big.Int),
+ Pow: &EasyPow{},
+ Speaker: speaker,
+ }
+
+ if bm.bc.CurrentBlock == nil {
+ AddTestNetFunds(bm.bc.genesisBlock)
+ // Prepare the genesis block
+ //bm.bc.genesisBlock.State().Sync()
+ bm.bc.Add(bm.bc.genesisBlock)
+ log.Println(bm.bc.genesisBlock)
+
+ log.Printf("Genesis: %x\n", bm.bc.genesisBlock.Hash())
+ //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root)
+ //bm.bc.genesisBlock.PrintHash()
+ }
+
+ return bm
+}
+
+func (bm *BlockManager) BlockChain() *BlockChain {
+ return bm.bc
+}
+
+func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) {
+ // Process each transaction/contract
+ for _, tx := range txs {
+ // If there's no recipient, it's a contract
+ if tx.IsContract() {
+ block.MakeContract(tx)
+ bm.ProcessContract(tx, block)
+ } else {
+ bm.TransactionPool.ProcessTransaction(tx, block)
+ }
+ }
+}
+
+// Block processing and validating with a given (temporarily) state
+func (bm *BlockManager) ProcessBlock(block *Block) error {
+ // Processing a blocks may never happen simultaneously
+ bm.mutex.Lock()
+ defer bm.mutex.Unlock()
+
+ hash := block.Hash()
+
+ if bm.bc.HasBlock(hash) {
+ return nil
+ }
+
+ /*
+ if ethutil.Config.Debug {
+ log.Printf("[BMGR] Processing block(%x)\n", hash)
+ }
+ */
+
+ // Check if we have the parent hash, if it isn't known we discard it
+ // Reasons might be catching up or simply an invalid block
+ if !bm.bc.HasBlock(block.PrevHash) && bm.bc.CurrentBlock != nil {
+ return ParentError(block.PrevHash)
+ }
+
+ // Process the transactions on to current block
+ bm.ApplyTransactions(bm.bc.CurrentBlock, block.Transactions())
+
+ // Block validation
+ if err := bm.ValidateBlock(block); err != nil {
+ return err
+ }
+
+ // I'm not sure, but I don't know if there should be thrown
+ // any errors at this time.
+ if err := bm.AccumelateRewards(bm.bc.CurrentBlock, block); err != nil {
+ return err
+ }
+
+ if !block.State().Cmp(bm.bc.CurrentBlock.State()) {
+ //if block.State().Root != state.Root {
+ return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().Root, bm.bc.CurrentBlock.State().Root)
+ }
+
+ // Calculate the new total difficulty and sync back to the db
+ if bm.CalculateTD(block) {
+ // Sync the current block's state to the database
+ bm.bc.CurrentBlock.State().Sync()
+ // Add the block to the chain
+ bm.bc.Add(block)
+
+ /*
+ ethutil.Config.Db.Put(block.Hash(), block.RlpEncode())
+ bm.bc.CurrentBlock = block
+ bm.LastBlockHash = block.Hash()
+ bm.writeBlockInfo(block)
+ */
+
+ /*
+ txs := bm.TransactionPool.Flush()
+ var coded = []interface{}{}
+ for _, tx := range txs {
+ err := bm.TransactionPool.ValidateTransaction(tx)
+ if err == nil {
+ coded = append(coded, tx.RlpEncode())
+ }
+ }
+ */
+
+ // Broadcast the valid block back to the wire
+ //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.RlpValue().Value})
+
+ // If there's a block processor present, pass in the block for further
+ // processing
+ if bm.SecondaryBlockProcessor != nil {
+ bm.SecondaryBlockProcessor.ProcessBlock(block)
+ }
+
+ log.Printf("[BMGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash())
+ } else {
+ fmt.Println("total diff failed")
+ }
+
+ return nil
+}
+
+func (bm *BlockManager) CalculateTD(block *Block) bool {
+ uncleDiff := new(big.Int)
+ for _, uncle := range block.Uncles {
+ uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
+ }
+
+ // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
+ td := new(big.Int)
+ td = td.Add(bm.bc.TD, uncleDiff)
+ td = td.Add(td, block.Difficulty)
+
+ // The new TD will only be accepted if the new difficulty is
+ // is greater than the previous.
+ if td.Cmp(bm.bc.TD) > 0 {
+ // Set the new total difficulty back to the block chain
+ bm.bc.SetTotalDifficulty(td)
+
+ /*
+ if ethutil.Config.Debug {
+ log.Println("[BMGR] TD(block) =", td)
+ }
+ */
+
+ return true
+ }
+
+ return false
+}
+
+// Validates the current block. Returns an error if the block was invalid,
+// an uncle or anything that isn't on the current block chain.
+// Validation validates easy over difficult (dagger takes longer time = difficult)
+func (bm *BlockManager) ValidateBlock(block *Block) error {
+ // TODO
+ // 2. Check if the difficulty is correct
+
+ // Check each uncle's previous hash. In order for it to be valid
+ // is if it has the same block hash as the current
+ previousBlock := bm.bc.GetBlock(block.PrevHash)
+ for _, uncle := range block.Uncles {
+ if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 {
+ return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash)
+ }
+ }
+
+ diff := block.Time - bm.bc.CurrentBlock.Time
+ if diff < 0 {
+ return ValidationError("Block timestamp less then prev block %v", diff)
+ }
+
+ // New blocks must be within the 15 minute range of the last block.
+ if diff > int64(15*time.Minute) {
+ return ValidationError("Block is too far in the future of last block (> 15 minutes)")
+ }
+
+ // Verify the nonce of the block. Return an error if it's not valid
+ if !bm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) {
+ return ValidationError("Block's nonce is invalid (= %v)", block.Nonce)
+ }
+
+ return nil
+}
+
+func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error {
+ // Get the coinbase rlp data
+ addr := processor.GetAddr(block.Coinbase)
+ // Reward amount of ether to the coinbase address
+ addr.AddFee(CalculateBlockReward(block, len(block.Uncles)))
+
+ processor.UpdateAddr(block.Coinbase, addr)
+
+ // TODO Reward each uncle
+
+ return nil
+}
+
+func (bm *BlockManager) Stop() {
+ bm.bc.Stop()
+}
+
+func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) {
+ // Recovering function in case the VM had any errors
+ defer func() {
+ if r := recover(); r != nil {
+ fmt.Println("Recovered from VM execution with err =", r)
+ }
+ }()
+
+ // Process contract
+ bm.ProcContract(tx, block, func(opType OpType) bool {
+ // TODO turn on once big ints are in place
+ //if !block.PayFee(tx.Hash(), StepFee.Uint64()) {
+ // return false
+ //}
+
+ return true // Continue
+ })
+}
+
+// Contract evaluation is done here.
+func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallback) {
+
+ // Instruction pointer
+ pc := 0
+ blockInfo := bm.bc.BlockInfo(block)
+
+ contract := block.GetContract(tx.Hash())
+ if contract == nil {
+ fmt.Println("Contract not found")
+ return
+ }
+
+ Pow256 := ethutil.BigPow(2, 256)
+
+ if ethutil.Config.Debug {
+ fmt.Printf("# op arg\n")
+ }
+out:
+ for {
+ // The base big int for all calculations. Use this for any results.
+ base := new(big.Int)
+ // XXX Should Instr return big int slice instead of string slice?
+ // Get the next instruction from the contract
+ //op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
+ nb := ethutil.NumberToBytes(uint64(pc), 32)
+ o, _, _ := ethutil.Instr(contract.State().Get(string(nb)))
+ op := OpCode(o)
+
+ if !cb(0) {
+ break
+ }
+
+ if ethutil.Config.Debug {
+ fmt.Printf("%-3d %-4s\n", pc, op.String())
+ }
+
+ switch op {
+ case oSTOP:
+ break out
+ case oADD:
+ x, y := bm.stack.Popn()
+ // (x + y) % 2 ** 256
+ base.Add(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ bm.stack.Push(base)
+ case oSUB:
+ x, y := bm.stack.Popn()
+ // (x - y) % 2 ** 256
+ base.Sub(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ bm.stack.Push(base)
+ case oMUL:
+ x, y := bm.stack.Popn()
+ // (x * y) % 2 ** 256
+ base.Mul(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ bm.stack.Push(base)
+ case oDIV:
+ x, y := bm.stack.Popn()
+ // floor(x / y)
+ base.Div(x, y)
+ // Pop result back on the stack
+ bm.stack.Push(base)
+ case oSDIV:
+ x, y := bm.stack.Popn()
+ // n > 2**255
+ if x.Cmp(Pow256) > 0 {
+ x.Sub(Pow256, x)
+ }
+ if y.Cmp(Pow256) > 0 {
+ y.Sub(Pow256, y)
+ }
+ z := new(big.Int)
+ z.Div(x, y)
+ if z.Cmp(Pow256) > 0 {
+ z.Sub(Pow256, z)
+ }
+ // Push result on to the stack
+ bm.stack.Push(z)
+ case oMOD:
+ x, y := bm.stack.Popn()
+ base.Mod(x, y)
+ bm.stack.Push(base)
+ case oSMOD:
+ x, y := bm.stack.Popn()
+ // n > 2**255
+ if x.Cmp(Pow256) > 0 {
+ x.Sub(Pow256, x)
+ }
+ if y.Cmp(Pow256) > 0 {
+ y.Sub(Pow256, y)
+ }
+ z := new(big.Int)
+ z.Mod(x, y)
+ if z.Cmp(Pow256) > 0 {
+ z.Sub(Pow256, z)
+ }
+ // Push result on to the stack
+ bm.stack.Push(z)
+ case oEXP:
+ x, y := bm.stack.Popn()
+ base.Exp(x, y, Pow256)
+
+ bm.stack.Push(base)
+ case oNEG:
+ base.Sub(Pow256, bm.stack.Pop())
+ bm.stack.Push(base)
+ case oLT:
+ x, y := bm.stack.Popn()
+ // x < y
+ if x.Cmp(y) < 0 {
+ bm.stack.Push(ethutil.BigTrue)
+ } else {
+ bm.stack.Push(ethutil.BigFalse)
+ }
+ case oLE:
+ x, y := bm.stack.Popn()
+ // x <= y
+ if x.Cmp(y) < 1 {
+ bm.stack.Push(ethutil.BigTrue)
+ } else {
+ bm.stack.Push(ethutil.BigFalse)
+ }
+ case oGT:
+ x, y := bm.stack.Popn()
+ // x > y
+ if x.Cmp(y) > 0 {
+ bm.stack.Push(ethutil.BigTrue)
+ } else {
+ bm.stack.Push(ethutil.BigFalse)
+ }
+ case oGE:
+ x, y := bm.stack.Popn()
+ // x >= y
+ if x.Cmp(y) > -1 {
+ bm.stack.Push(ethutil.BigTrue)
+ } else {
+ bm.stack.Push(ethutil.BigFalse)
+ }
+ case oNOT:
+ x, y := bm.stack.Popn()
+ // x != y
+ if x.Cmp(y) != 0 {
+ bm.stack.Push(ethutil.BigTrue)
+ } else {
+ bm.stack.Push(ethutil.BigFalse)
+ }
+
+ // Please note that the following code contains some
+ // ugly string casting. This will have to change to big
+ // ints. TODO :)
+ case oMYADDRESS:
+ bm.stack.Push(ethutil.BigD(tx.Hash()))
+ case oTXSENDER:
+ bm.stack.Push(ethutil.BigD(tx.Sender()))
+ case oTXVALUE:
+ bm.stack.Push(tx.Value)
+ case oTXDATAN:
+ bm.stack.Push(big.NewInt(int64(len(tx.Data))))
+ case oTXDATA:
+ v := bm.stack.Pop()
+ // v >= len(data)
+ if v.Cmp(big.NewInt(int64(len(tx.Data)))) >= 0 {
+ bm.stack.Push(ethutil.Big("0"))
+ } else {
+ bm.stack.Push(ethutil.Big(tx.Data[v.Uint64()]))
+ }
+ case oBLK_PREVHASH:
+ bm.stack.Push(ethutil.BigD(block.PrevHash))
+ case oBLK_COINBASE:
+ bm.stack.Push(ethutil.BigD(block.Coinbase))
+ case oBLK_TIMESTAMP:
+ bm.stack.Push(big.NewInt(block.Time))
+ case oBLK_NUMBER:
+ bm.stack.Push(big.NewInt(int64(blockInfo.Number)))
+ case oBLK_DIFFICULTY:
+ bm.stack.Push(block.Difficulty)
+ case oBASEFEE:
+ // e = 10^21
+ e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0))
+ d := new(big.Rat)
+ d.SetInt(block.Difficulty)
+ c := new(big.Rat)
+ c.SetFloat64(0.5)
+ // d = diff / 0.5
+ d.Quo(d, c)
+ // base = floor(d)
+ base.Div(d.Num(), d.Denom())
+
+ x := new(big.Int)
+ x.Div(e, base)
+
+ // x = floor(10^21 / floor(diff^0.5))
+ bm.stack.Push(x)
+ case oSHA256, oSHA3, oRIPEMD160:
+ // This is probably save
+ // ceil(pop / 32)
+ length := int(math.Ceil(float64(bm.stack.Pop().Uint64()) / 32.0))
+ // New buffer which will contain the concatenated popped items
+ data := new(bytes.Buffer)
+ for i := 0; i < length; i++ {
+ // Encode the number to bytes and have it 32bytes long
+ num := ethutil.NumberToBytes(bm.stack.Pop().Bytes(), 256)
+ data.WriteString(string(num))
+ }
+
+ if op == oSHA256 {
+ bm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes())))
+ } else if op == oSHA3 {
+ bm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes())))
+ } else {
+ bm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes())))
+ }
+ case oECMUL:
+ y := bm.stack.Pop()
+ x := bm.stack.Pop()
+ //n := bm.stack.Pop()
+
+ //if ethutil.Big(x).Cmp(ethutil.Big(y)) {
+ data := new(bytes.Buffer)
+ data.WriteString(x.String())
+ data.WriteString(y.String())
+ if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 {
+ // TODO
+ } else {
+ // Invalid, push infinity
+ bm.stack.Push(ethutil.Big("0"))
+ bm.stack.Push(ethutil.Big("0"))
+ }
+ //} else {
+ // // Invalid, push infinity
+ // bm.stack.Push("0")
+ // bm.stack.Push("0")
+ //}
+
+ case oECADD:
+ case oECSIGN:
+ case oECRECOVER:
+ case oECVALID:
+ case oPUSH:
+ pc++
+ bm.stack.Push(bm.mem[strconv.Itoa(pc)])
+ case oPOP:
+ // Pop current value of the stack
+ bm.stack.Pop()
+ case oDUP:
+ // Dup top stack
+ x := bm.stack.Pop()
+ bm.stack.Push(x)
+ bm.stack.Push(x)
+ case oSWAP:
+ // Swap two top most values
+ x, y := bm.stack.Popn()
+ bm.stack.Push(y)
+ bm.stack.Push(x)
+ case oMLOAD:
+ x := bm.stack.Pop()
+ bm.stack.Push(bm.mem[x.String()])
+ case oMSTORE:
+ x, y := bm.stack.Popn()
+ bm.mem[x.String()] = y
+ case oSLOAD:
+ // Load the value in storage and push it on the stack
+ x := bm.stack.Pop()
+ // decode the object as a big integer
+ decoder := ethutil.NewRlpValueFromBytes([]byte(contract.State().Get(x.String())))
+ if !decoder.IsNil() {
+ bm.stack.Push(decoder.AsBigInt())
+ } else {
+ bm.stack.Push(ethutil.BigFalse)
+ }
+ case oSSTORE:
+ // Store Y at index X
+ x, y := bm.stack.Popn()
+ contract.State().Update(x.String(), string(ethutil.Encode(y)))
+ case oJMP:
+ x := int(bm.stack.Pop().Uint64())
+ // Set pc to x - 1 (minus one so the incrementing at the end won't effect it)
+ pc = x
+ pc--
+ case oJMPI:
+ x := bm.stack.Pop()
+ // Set pc to x if it's non zero
+ if x.Cmp(ethutil.BigFalse) != 0 {
+ pc = int(x.Uint64())
+ pc--
+ }
+ case oIND:
+ bm.stack.Push(big.NewInt(int64(pc)))
+ case oEXTRO:
+ memAddr := bm.stack.Pop()
+ contractAddr := bm.stack.Pop().Bytes()
+
+ // Push the contract's memory on to the stack
+ bm.stack.Push(getContractMemory(block, contractAddr, memAddr))
+ case oBALANCE:
+ // Pushes the balance of the popped value on to the stack
+ d := block.State().Get(bm.stack.Pop().String())
+ ether := NewAddressFromData([]byte(d))
+ bm.stack.Push(ether.Amount)
+ case oMKTX:
+ value, addr := bm.stack.Popn()
+ from, length := bm.stack.Popn()
+
+ j := 0
+ dataItems := make([]string, int(length.Uint64()))
+ for i := from.Uint64(); i < length.Uint64(); i++ {
+ dataItems[j] = string(bm.mem[strconv.Itoa(int(i))].Bytes())
+ j++
+ }
+ // TODO sign it?
+ tx := NewTransaction(addr.Bytes(), value, dataItems)
+ // Add the transaction to the tx pool
+ bm.TransactionPool.QueueTransaction(tx)
+ case oSUICIDE:
+ //addr := bm.stack.Pop()
+ }
+ pc++
+ }
+}
+
+// Returns an address from the specified contract's address
+func getContractMemory(block *Block, contractAddr []byte, memAddr *big.Int) *big.Int {
+ contract := block.GetContract(contractAddr)
+ if contract == nil {
+ log.Panicf("invalid contract addr %x", contractAddr)
+ }
+ val := contract.State().Get(memAddr.String())
+
+ // decode the object as a big integer
+ decoder := ethutil.NewRlpValueFromBytes([]byte(val))
+ if decoder.IsNil() {
+ return ethutil.BigFalse
+ }
+
+ return decoder.AsBigInt()
+}
diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go
new file mode 100644
index 000000000..502c50b97
--- /dev/null
+++ b/ethchain/block_manager_test.go
@@ -0,0 +1,75 @@
+package ethchain
+
+/*
+import (
+ _ "fmt"
+ "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",
+ })
+ tx := NewTransaction("1e8a42ea8cce13", 100, []string{})
+
+ block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx})
+ db.Put(block.Hash(), block.RlpEncode())
+
+ bm := NewBlockManager()
+ bm.ProcessBlock(block)
+}
+*/
diff --git a/ethchain/contract.go b/ethchain/contract.go
new file mode 100644
index 000000000..d1fcec3b4
--- /dev/null
+++ b/ethchain/contract.go
@@ -0,0 +1,66 @@
+package ethchain
+
+import (
+ "github.com/ethereum/eth-go/ethutil"
+ "math/big"
+)
+
+type Contract struct {
+ Amount *big.Int
+ Nonce uint64
+ state *ethutil.Trie
+}
+
+func NewContract(Amount *big.Int, root []byte) *Contract {
+ contract := &Contract{Amount: Amount, Nonce: 0}
+ contract.state = ethutil.NewTrie(ethutil.Config.Db, string(root))
+
+ return contract
+}
+
+func (c *Contract) RlpEncode() []byte {
+ return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.Root})
+}
+
+func (c *Contract) RlpDecode(data []byte) {
+ decoder := ethutil.NewRlpValueFromBytes(data)
+
+ c.Amount = decoder.Get(0).AsBigInt()
+ c.Nonce = decoder.Get(1).AsUint()
+ c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).AsRaw())
+}
+
+func (c *Contract) State() *ethutil.Trie {
+ return c.state
+}
+
+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.NewRlpValueFromBytes(data)
+
+ a.Amount = decoder.Get(0).AsBigInt()
+ a.Nonce = decoder.Get(1).AsUint()
+}
diff --git a/ethchain/dagger.go b/ethchain/dagger.go
new file mode 100644
index 000000000..5b4f8b2cd
--- /dev/null
+++ b/ethchain/dagger.go
@@ -0,0 +1,199 @@
+package ethchain
+
+import (
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/obscuren/sha3"
+ "hash"
+ "log"
+ "math/big"
+ "math/rand"
+ "time"
+)
+
+type PoW interface {
+ Search(block *Block) []byte
+ Verify(hash []byte, diff *big.Int, nonce []byte) bool
+}
+
+type EasyPow struct {
+ hash *big.Int
+}
+
+func (pow *EasyPow) Search(block *Block) []byte {
+ r := rand.New(rand.NewSource(time.Now().UnixNano()))
+
+ hash := block.HashNoNonce()
+ diff := block.Difficulty
+ for {
+ sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes())
+ if pow.Verify(hash, diff, sha) {
+ return sha
+ }
+ }
+
+ return nil
+}
+
+func (pow *EasyPow) Verify(hash []byte, diff *big.Int, nonce []byte) bool {
+ sha := sha3.NewKeccak256()
+
+ d := append(hash, nonce...)
+ sha.Write(d)
+
+ v := ethutil.BigPow(2, 256)
+ ret := new(big.Int).Div(v, diff)
+
+ res := new(big.Int)
+ res.SetBytes(sha.Sum(nil))
+
+ return res.Cmp(ret) == -1
+}
+
+func (pow *EasyPow) SetHash(hash *big.Int) {
+}
+
+type Dagger struct {
+ hash *big.Int
+ xn *big.Int
+}
+
+var Found bool
+
+func (dag *Dagger) Find(obj *big.Int, resChan chan int64) {
+ r := rand.New(rand.NewSource(time.Now().UnixNano()))
+
+ for i := 0; i < 1000; i++ {
+ rnd := r.Int63()
+
+ res := dag.Eval(big.NewInt(rnd))
+ log.Printf("rnd %v\nres %v\nobj %v\n", rnd, res, obj)
+ if res.Cmp(obj) < 0 {
+ // Post back result on the channel
+ resChan <- rnd
+ // Notify other threads we've found a valid nonce
+ Found = true
+ }
+
+ // Break out if found
+ if Found {
+ break
+ }
+ }
+
+ resChan <- 0
+}
+
+func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
+ // TODO fix multi threading. Somehow it results in the wrong nonce
+ amountOfRoutines := 1
+
+ dag.hash = hash
+
+ obj := ethutil.BigPow(2, 256)
+ obj = obj.Div(obj, diff)
+
+ Found = false
+ resChan := make(chan int64, 3)
+ var res int64
+
+ for k := 0; k < amountOfRoutines; k++ {
+ go dag.Find(obj, resChan)
+ }
+
+ // Wait for each go routine to finish
+ for k := 0; k < amountOfRoutines; k++ {
+ // Get the result from the channel. 0 = quit
+ if r := <-resChan; r != 0 {
+ res = r
+ }
+ }
+
+ return big.NewInt(res)
+}
+
+func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool {
+ dag.hash = hash
+
+ obj := ethutil.BigPow(2, 256)
+ obj = obj.Div(obj, diff)
+
+ return dag.Eval(nonce).Cmp(obj) < 0
+}
+
+func DaggerVerify(hash, diff, nonce *big.Int) bool {
+ dagger := &Dagger{}
+ dagger.hash = hash
+
+ obj := ethutil.BigPow(2, 256)
+ obj = obj.Div(obj, diff)
+
+ return dagger.Eval(nonce).Cmp(obj) < 0
+}
+
+func (dag *Dagger) Node(L uint64, i uint64) *big.Int {
+ if L == i {
+ return dag.hash
+ }
+
+ var m *big.Int
+ if L == 9 {
+ m = big.NewInt(16)
+ } else {
+ m = big.NewInt(3)
+ }
+
+ sha := sha3.NewKeccak256()
+ sha.Reset()
+ d := sha3.NewKeccak256()
+ b := new(big.Int)
+ ret := new(big.Int)
+
+ for k := 0; k < int(m.Uint64()); k++ {
+ d.Reset()
+ d.Write(dag.hash.Bytes())
+ d.Write(dag.xn.Bytes())
+ d.Write(big.NewInt(int64(L)).Bytes())
+ d.Write(big.NewInt(int64(i)).Bytes())
+ d.Write(big.NewInt(int64(k)).Bytes())
+
+ b.SetBytes(Sum(d))
+ pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1)
+ sha.Write(dag.Node(L-1, pk).Bytes())
+ }
+
+ ret.SetBytes(Sum(sha))
+
+ return ret
+}
+
+func Sum(sha hash.Hash) []byte {
+ //in := make([]byte, 32)
+ return sha.Sum(nil)
+}
+
+func (dag *Dagger) Eval(N *big.Int) *big.Int {
+ pow := ethutil.BigPow(2, 26)
+ dag.xn = pow.Div(N, pow)
+
+ sha := sha3.NewKeccak256()
+ sha.Reset()
+ ret := new(big.Int)
+
+ for k := 0; k < 4; k++ {
+ d := sha3.NewKeccak256()
+ b := new(big.Int)
+
+ d.Reset()
+ d.Write(dag.hash.Bytes())
+ d.Write(dag.xn.Bytes())
+ d.Write(N.Bytes())
+ d.Write(big.NewInt(int64(k)).Bytes())
+
+ b.SetBytes(Sum(d))
+ pk := (b.Uint64() & 0x1ffffff)
+
+ sha.Write(dag.Node(9, pk).Bytes())
+ }
+
+ return ret.SetBytes(Sum(sha))
+}
diff --git a/ethchain/dagger_test.go b/ethchain/dagger_test.go
new file mode 100644
index 000000000..9d4e03c92
--- /dev/null
+++ b/ethchain/dagger_test.go
@@ -0,0 +1,18 @@
+package ethchain
+
+import (
+ "github.com/ethereum/eth-go/ethutil"
+ "math/big"
+ "testing"
+)
+
+func BenchmarkDaggerSearch(b *testing.B) {
+ hash := big.NewInt(0)
+ diff := ethutil.BigPow(2, 36)
+ o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity
+
+ // Reset timer so the big generation isn't included in the benchmark
+ b.ResetTimer()
+ // Validate
+ DaggerVerify(hash, diff, o)
+}
diff --git a/ethchain/error.go b/ethchain/error.go
new file mode 100644
index 000000000..0f1d061c0
--- /dev/null
+++ b/ethchain/error.go
@@ -0,0 +1,42 @@
+package ethchain
+
+import "fmt"
+
+// Parent error. In case a parent is unknown this error will be thrown
+// by the block manager
+type ParentErr struct {
+ Message string
+}
+
+func (err *ParentErr) Error() string {
+ return err.Message
+}
+
+func ParentError(hash []byte) error {
+ return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)}
+}
+
+func IsParentErr(err error) bool {
+ _, ok := err.(*ParentErr)
+
+ return ok
+}
+
+// Block validation error. If any validation fails, this error will be thrown
+type ValidationErr struct {
+ Message string
+}
+
+func (err *ValidationErr) Error() string {
+ return err.Message
+}
+
+func ValidationError(format string, v ...interface{}) *ValidationErr {
+ return &ValidationErr{Message: fmt.Sprintf(format, v...)}
+}
+
+func IsValidationErr(err error) bool {
+ _, ok := err.(*ValidationErr)
+
+ return ok
+}
diff --git a/ethchain/fees.go b/ethchain/fees.go
new file mode 100644
index 000000000..8f1646ab4
--- /dev/null
+++ b/ethchain/fees.go
@@ -0,0 +1,65 @@
+package ethchain
+
+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 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() {
+ /*
+ // Base for 2**64
+ b60 := new(big.Int)
+ b60.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
+ // Base for 2**80
+ b80 := new(big.Int)
+ b80.Exp(big.NewInt(2), big.NewInt(80), big.NewInt(0))
+
+ StepFee.Exp(big.NewInt(10), big.NewInt(16), big.NewInt(0))
+ //StepFee.Div(b60, big.NewInt(64))
+ //fmt.Println("StepFee:", StepFee)
+
+ TxFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
+ //fmt.Println("TxFee:", TxFee)
+
+ ContractFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
+ //fmt.Println("ContractFee:", ContractFee)
+
+ MemFee.Div(b60, big.NewInt(4))
+ //fmt.Println("MemFee:", MemFee)
+
+ DataFee.Div(b60, big.NewInt(16))
+ //fmt.Println("DataFee:", DataFee)
+
+ CryptoFee.Div(b60, big.NewInt(16))
+ //fmt.Println("CrytoFee:", CryptoFee)
+
+ ExtroFee.Div(b60, big.NewInt(16))
+ //fmt.Println("ExtroFee:", ExtroFee)
+
+ Period1Reward.Mul(b80, big.NewInt(1024))
+ //fmt.Println("Period1Reward:", Period1Reward)
+
+ Period2Reward.Mul(b80, big.NewInt(512))
+ //fmt.Println("Period2Reward:", Period2Reward)
+
+ Period3Reward.Mul(b80, big.NewInt(256))
+ //fmt.Println("Period3Reward:", Period3Reward)
+
+ Period4Reward.Mul(b80, big.NewInt(128))
+ //fmt.Println("Period4Reward:", Period4Reward)
+ */
+}
diff --git a/ethchain/genesis.go b/ethchain/genesis.go
new file mode 100644
index 000000000..060d347e4
--- /dev/null
+++ b/ethchain/genesis.go
@@ -0,0 +1,39 @@
+package ethchain
+
+import (
+ "github.com/ethereum/eth-go/ethutil"
+ "math/big"
+)
+
+/*
+ * This is the special genesis block.
+ */
+
+var ZeroHash256 = make([]byte, 32)
+var ZeroHash160 = make([]byte, 20)
+var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{}))
+
+var GenisisHeader = []interface{}{
+ // Previous hash (none)
+ //"",
+ ZeroHash256,
+ // Sha of uncles
+ ethutil.Sha3Bin(ethutil.Encode([]interface{}{})),
+ // Coinbase
+ ZeroHash160,
+ // Root state
+ "",
+ // Sha of transactions
+ //EmptyShaList,
+ ethutil.Sha3Bin(ethutil.Encode([]interface{}{})),
+ // Difficulty
+ ethutil.BigPow(2, 22),
+ // Time
+ int64(0),
+ // Extra
+ "",
+ // Nonce
+ ethutil.Sha3Bin(big.NewInt(42).Bytes()),
+}
+
+var Genesis = []interface{}{GenisisHeader, []interface{}{}, []interface{}{}}
diff --git a/ethchain/stack.go b/ethchain/stack.go
new file mode 100644
index 000000000..c80d01e5c
--- /dev/null
+++ b/ethchain/stack.go
@@ -0,0 +1,167 @@
+package ethchain
+
+import (
+ "fmt"
+ "math/big"
+)
+
+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
+)
+
+// Since the opcodes aren't all in order we can't use a regular slice
+var opCodeToString = map[OpCode]string{
+ oSTOP: "STOP",
+ oADD: "ADD",
+ oMUL: "MUL",
+ oSUB: "SUB",
+ oDIV: "DIV",
+ oSDIV: "SDIV",
+ oMOD: "MOD",
+ oSMOD: "SMOD",
+ oEXP: "EXP",
+ oNEG: "NEG",
+ oLT: "LT",
+ oLE: "LE",
+ oGT: "GT",
+ oGE: "GE",
+ oEQ: "EQ",
+ oNOT: "NOT",
+ oMYADDRESS: "MYADDRESS",
+ oTXSENDER: "TXSENDER",
+ oTXVALUE: "TXVALUE",
+ oTXFEE: "TXFEE",
+ oTXDATAN: "TXDATAN",
+ oTXDATA: "TXDATA",
+ oBLK_PREVHASH: "BLK_PREVHASH",
+ oBLK_COINBASE: "BLK_COINBASE",
+ oBLK_TIMESTAMP: "BLK_TIMESTAMP",
+ oBLK_NUMBER: "BLK_NUMBER",
+ oBLK_DIFFICULTY: "BLK_DIFFICULTY",
+ oBASEFEE: "BASEFEE",
+ oSHA256: "SHA256",
+ oRIPEMD160: "RIPEMD160",
+ oECMUL: "ECMUL",
+ oECADD: "ECADD",
+ oECSIGN: "ECSIGN",
+ oECRECOVER: "ECRECOVER",
+ oECVALID: "ECVALID",
+ oSHA3: "SHA3",
+ oPUSH: "PUSH",
+ oPOP: "POP",
+ oDUP: "DUP",
+ oSWAP: "SWAP",
+ oMLOAD: "MLOAD",
+ oMSTORE: "MSTORE",
+ oSLOAD: "SLOAD",
+ oSSTORE: "SSTORE",
+ oJMP: "JMP",
+ oJMPI: "JMPI",
+ oIND: "IND",
+ oEXTRO: "EXTRO",
+ oBALANCE: "BALANCE",
+ oMKTX: "MKTX",
+ oSUICIDE: "SUICIDE",
+}
+
+func (o OpCode) String() string {
+ return opCodeToString[o]
+}
+
+type OpType int
+
+const (
+ tNorm = iota
+ tData
+ tExtro
+ tCrypto
+)
+
+type TxCallback func(opType OpType) bool
+
+// Simple push/pop stack mechanism
+type Stack struct {
+ data []*big.Int
+}
+
+func NewStack() *Stack {
+ return &Stack{}
+}
+
+func (st *Stack) Pop() *big.Int {
+ s := len(st.data)
+
+ str := st.data[s-1]
+ st.data = st.data[:s-1]
+
+ return str
+}
+
+func (st *Stack) Popn() (*big.Int, *big.Int) {
+ s := len(st.data)
+
+ ints := st.data[s-2:]
+ st.data = 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)
+}
diff --git a/ethchain/transaction.go b/ethchain/transaction.go
new file mode 100644
index 000000000..1a9258201
--- /dev/null
+++ b/ethchain/transaction.go
@@ -0,0 +1,157 @@
+package ethchain
+
+import (
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/obscuren/secp256k1-go"
+ "math/big"
+)
+
+type Transaction struct {
+ Nonce uint64
+ Recipient []byte
+ Value *big.Int
+ Data []string
+ Memory []int
+ v byte
+ r, s []byte
+}
+
+func NewTransaction(to []byte, value *big.Int, data []string) *Transaction {
+ tx := Transaction{Recipient: to, Value: value}
+ 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
+ }
+
+ return &tx
+}
+
+func NewTransactionFromData(data []byte) *Transaction {
+ tx := &Transaction{}
+ tx.RlpDecode(data)
+
+ return tx
+}
+
+func NewTransactionFromValue(val *ethutil.Value) *Transaction {
+ tx := &Transaction{}
+ tx.RlpValueDecode(val)
+
+ return tx
+}
+
+func (tx *Transaction) Hash() []byte {
+ data := make([]interface{}, len(tx.Data))
+ for i, val := range tx.Data {
+ data[i] = val
+ }
+
+ preEnc := []interface{}{
+ tx.Nonce,
+ tx.Recipient,
+ tx.Value,
+ data,
+ }
+
+ return ethutil.Sha3Bin(ethutil.Encode(preEnc))
+}
+
+func (tx *Transaction) IsContract() bool {
+ return len(tx.Recipient) == 0
+}
+
+func (tx *Transaction) Signature(key []byte) []byte {
+ hash := tx.Hash()
+
+ sig, _ := secp256k1.Sign(hash, key)
+
+ return sig
+}
+
+func (tx *Transaction) PublicKey() []byte {
+ hash := tx.Hash()
+
+ // If we don't make a copy we will overwrite the existing underlying array
+ dst := make([]byte, len(tx.r))
+ copy(dst, tx.r)
+
+ sig := append(dst, tx.s...)
+ sig = append(sig, tx.v-27)
+
+ pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
+
+ return pubkey
+}
+
+func (tx *Transaction) Sender() []byte {
+ pubkey := tx.PublicKey()
+
+ // Validate the returned key.
+ // Return nil if public key isn't in full format
+ if pubkey[0] != 4 {
+ return nil
+ }
+
+ return ethutil.Sha3Bin(pubkey[1:])[12:]
+}
+
+func (tx *Transaction) Sign(privk []byte) error {
+
+ sig := tx.Signature(privk)
+
+ tx.r = sig[:32]
+ tx.s = sig[32:64]
+ tx.v = sig[64] + 27
+
+ return nil
+}
+
+func (tx *Transaction) RlpData() interface{} {
+ // Prepare the transaction for serialization
+ return []interface{}{
+ tx.Nonce,
+ tx.Recipient,
+ tx.Value,
+ ethutil.NewSliceValue(tx.Data).Slice(),
+ tx.v,
+ tx.r,
+ tx.s,
+ }
+}
+
+func (tx *Transaction) RlpValue() *ethutil.Value {
+ return ethutil.NewValue(tx.RlpData())
+}
+
+func (tx *Transaction) RlpEncode() []byte {
+ return tx.RlpValue().Encode()
+}
+
+func (tx *Transaction) RlpDecode(data []byte) {
+ tx.RlpValueDecode(ethutil.NewValueFromBytes(data))
+}
+
+func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
+ tx.Nonce = decoder.Get(0).Uint()
+ tx.Recipient = decoder.Get(1).Bytes()
+ tx.Value = decoder.Get(2).BigInt()
+
+ d := decoder.Get(3)
+ tx.Data = make([]string, d.Len())
+ for i := 0; i < d.Len(); i++ {
+ tx.Data[i] = d.Get(i).Str()
+ }
+
+ // TODO something going wrong here
+ tx.v = byte(decoder.Get(4).Uint())
+ tx.r = decoder.Get(5).Bytes()
+ tx.s = decoder.Get(6).Bytes()
+}
diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go
new file mode 100644
index 000000000..c2d65a2a7
--- /dev/null
+++ b/ethchain/transaction_pool.go
@@ -0,0 +1,219 @@
+package ethchain
+
+import (
+ "bytes"
+ "container/list"
+ "errors"
+ "fmt"
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/eth-go/ethwire"
+ "log"
+ "math/big"
+ "sync"
+)
+
+const (
+ txPoolQueueSize = 50
+)
+
+type TxPoolHook chan *Transaction
+
+func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction {
+ for e := pool.Front(); e != nil; e = e.Next() {
+ if tx, ok := e.Value.(*Transaction); ok {
+ if finder(tx, e) {
+ return tx
+ }
+ }
+ }
+
+ return nil
+}
+
+type PublicSpeaker interface {
+ Broadcast(msgType ethwire.MsgType, data []interface{})
+}
+
+// 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
+// pool is being drained or synced for whatever reason the transactions
+// will simple queue up and handled when the mutex is freed.
+type TxPool struct {
+ //server *Server
+ Speaker PublicSpeaker
+ // The mutex for accessing the Tx pool.
+ mutex sync.Mutex
+ // Queueing channel for reading and writing incoming
+ // transactions to
+ queueChan chan *Transaction
+ // Quiting channel
+ quit chan bool
+ // The actual pool
+ pool *list.List
+
+ BlockManager *BlockManager
+
+ Hook TxPoolHook
+}
+
+func NewTxPool() *TxPool {
+ return &TxPool{
+ //server: s,
+ mutex: sync.Mutex{},
+ pool: list.New(),
+ queueChan: make(chan *Transaction, txPoolQueueSize),
+ quit: make(chan bool),
+ }
+}
+
+// Blocking function. Don't use directly. Use QueueTransaction instead
+func (pool *TxPool) addTransaction(tx *Transaction) {
+ pool.mutex.Lock()
+ pool.pool.PushBack(tx)
+ pool.mutex.Unlock()
+
+ // Broadcast the transaction to the rest of the peers
+ pool.Speaker.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()})
+}
+
+// Process transaction validates the Tx and processes funds from the
+// sender to the recipient.
+func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) {
+ log.Printf("[TXPL] Processing Tx %x\n", tx.Hash())
+
+ defer func() {
+ if r := recover(); r != nil {
+ log.Println(r)
+ err = fmt.Errorf("%v", r)
+ }
+ }()
+ // Get the sender
+ sender := block.GetAddr(tx.Sender())
+
+ // Make sure there's enough in the sender's account. Having insufficient
+ // funds won't invalidate this transaction but simple ignores it.
+ totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
+ if sender.Amount.Cmp(totAmount) < 0 {
+ return errors.New("Insufficient amount in sender's account")
+ }
+
+ if sender.Nonce != tx.Nonce {
+ if ethutil.Config.Debug {
+ return fmt.Errorf("Invalid nonce %d(%d) continueing anyway", tx.Nonce, sender.Nonce)
+ } else {
+ return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce)
+ }
+ }
+
+ // 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)
+
+ block.UpdateAddr(tx.Sender(), sender)
+ block.UpdateAddr(tx.Recipient, receiver)
+
+ return
+}
+
+func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
+ // Get the last block so we can retrieve the sender and receiver from
+ // the merkle trie
+ block := pool.BlockManager.BlockChain().CurrentBlock
+ // Something has gone horribly wrong if this happens
+ if block == nil {
+ return errors.New("No last block on the block chain")
+ }
+
+ // Get the sender
+ sender := block.GetAddr(tx.Sender())
+
+ 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
+ // funds won't invalidate this transaction but simple ignores it.
+ if sender.Amount.Cmp(totAmount) < 0 {
+ return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender())
+ }
+
+ // Increment the nonce making each tx valid only once to prevent replay
+ // attacks
+
+ return nil
+}
+
+func (pool *TxPool) queueHandler() {
+out:
+ for {
+ select {
+ case tx := <-pool.queueChan:
+ hash := tx.Hash()
+ foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool {
+ return bytes.Compare(tx.Hash(), hash) == 0
+ })
+
+ if foundTx != nil {
+ break
+ }
+
+ // Validate the transaction
+ err := pool.ValidateTransaction(tx)
+ if err != nil {
+ if ethutil.Config.Debug {
+ log.Println("Validating Tx failed", err)
+ }
+ } else {
+ // Call blocking version. At this point it
+ // doesn't matter since this is a goroutine
+ pool.addTransaction(tx)
+
+ if pool.Hook != nil {
+ pool.Hook <- tx
+ }
+ }
+ case <-pool.quit:
+ break out
+ }
+ }
+}
+
+func (pool *TxPool) QueueTransaction(tx *Transaction) {
+ pool.queueChan <- tx
+}
+
+func (pool *TxPool) Flush() []*Transaction {
+ pool.mutex.Lock()
+ defer pool.mutex.Unlock()
+
+ txList := make([]*Transaction, pool.pool.Len())
+ i := 0
+ for e := pool.pool.Front(); e != nil; e = e.Next() {
+ if tx, ok := e.Value.(*Transaction); ok {
+ txList[i] = tx
+ }
+
+ i++
+ }
+
+ // Recreate a new list all together
+ // XXX Is this the fastest way?
+ pool.pool = list.New()
+
+ return txList
+}
+
+func (pool *TxPool) Start() {
+ go pool.queueHandler()
+}
+
+func (pool *TxPool) Stop() {
+ log.Println("[TXP] Stopping...")
+
+ close(pool.quit)
+
+ pool.Flush()
+}
diff --git a/ethchain/transaction_test.go b/ethchain/transaction_test.go
new file mode 100644
index 000000000..c9090b83d
--- /dev/null
+++ b/ethchain/transaction_test.go
@@ -0,0 +1,54 @@
+package ethchain
+
+import (
+ "encoding/hex"
+ "fmt"
+ "github.com/ethereum/eth-go/ethutil"
+ "math/big"
+ "testing"
+)
+
+func TestAddressRetrieval(t *testing.T) {
+ // TODO
+ // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f
+ key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")
+
+ tx := &Transaction{
+ Nonce: 0,
+ Recipient: ZeroHash160,
+ Value: big.NewInt(0),
+ Data: nil,
+ }
+ //fmt.Printf("rlp %x\n", tx.RlpEncode())
+ //fmt.Printf("sha rlp %x\n", tx.Hash())
+
+ tx.Sign(key)
+
+ //fmt.Printf("hex tx key %x\n", tx.PublicKey())
+ //fmt.Printf("seder %x\n", tx.Sender())
+}
+
+func TestAddressRetrieval2(t *testing.T) {
+ // TODO
+ // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f
+ key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")
+ addr, _ := hex.DecodeString("944400f4b88ac9589a0f17ed4671da26bddb668b")
+ tx := &Transaction{
+ Nonce: 0,
+ Recipient: addr,
+ Value: big.NewInt(1000),
+ Data: nil,
+ }
+ tx.Sign(key)
+ //data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7")
+ //tx := NewTransactionFromData(data)
+ fmt.Println(tx.RlpValue())
+
+ fmt.Printf("rlp %x\n", tx.RlpEncode())
+ fmt.Printf("sha rlp %x\n", tx.Hash())
+
+ //tx.Sign(key)
+
+ fmt.Printf("hex tx key %x\n", tx.PublicKey())
+ fmt.Printf("seder %x\n", tx.Sender())
+}