Commit 2096b3a9 authored by obscuren's avatar obscuren

Merge branch 'release/poc5-rc1'

parents 6a86c517 fedd4c90
...@@ -6,7 +6,7 @@ Ethereum ...@@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke Ethereum Go Development package (C) Jeffrey Wilcke
Ethereum is currently in its testing phase. The current state is "Proof Ethereum is currently in its testing phase. The current state is "Proof
of Concept 3.5". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). of Concept 5.0 RC1". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
Ethereum Go is split up in several sub packages Please refer to each Ethereum Go is split up in several sub packages Please refer to each
individual package for more information. individual package for more information.
......
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type Account struct {
address []byte
Amount *big.Int
Nonce uint64
}
func NewAccount(address []byte, amount *big.Int) *Account {
return &Account{address, amount, 0}
}
func NewAccountFromData(address, data []byte) *Account {
account := &Account{address: address}
account.RlpDecode(data)
return account
}
func (a *Account) AddFee(fee *big.Int) {
a.AddFunds(fee)
}
func (a *Account) AddFunds(funds *big.Int) {
a.Amount.Add(a.Amount, funds)
}
func (a *Account) Address() []byte {
return a.address
}
// Implements Callee
func (a *Account) ReturnGas(value *big.Int, state *State) {
// Return the value back to the sender
a.AddFunds(value)
state.UpdateAccount(a.address, a)
}
func (a *Account) RlpEncode() []byte {
return ethutil.Encode([]interface{}{a.Amount, a.Nonce})
}
func (a *Account) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
a.Amount = decoder.Get(0).BigInt()
a.Nonce = decoder.Get(1).Uint()
}
type AddrStateStore struct {
states map[string]*AccountState
}
func NewAddrStateStore() *AddrStateStore {
return &AddrStateStore{states: make(map[string]*AccountState)}
}
func (s *AddrStateStore) Add(addr []byte, account *Account) *AccountState {
state := &AccountState{Nonce: account.Nonce, Account: account}
s.states[string(addr)] = state
return state
}
func (s *AddrStateStore) Get(addr []byte) *AccountState {
return s.states[string(addr)]
}
type AccountState struct {
Nonce uint64
Account *Account
}
package ethchain
import (
"testing"
)
func TestAddressState(t *testing.T) {
}
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
func Disassemble(script []byte) (asm []string) {
pc := new(big.Int)
for {
if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 {
return
}
// Get the memory location of pc
val := script[pc.Int64()]
// Get the opcode (it must be an opcode!)
op := OpCode(val)
asm = append(asm, fmt.Sprintf("%v", op))
switch op {
case oPUSH: // Push PC+1 on to the stack
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+32]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(31))
case oPUSH20:
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+20]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(19))
}
pc.Add(pc, ethutil.Big1)
}
return
}
...@@ -113,11 +113,6 @@ func (block *Block) HashNoNonce() []byte { ...@@ -113,11 +113,6 @@ func (block *Block) HashNoNonce() []byte {
return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.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.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce})))
}
func (block *Block) State() *State { func (block *Block) State() *State {
return block.state return block.state
} }
...@@ -142,12 +137,13 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { ...@@ -142,12 +137,13 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
data := block.state.trie.Get(string(block.Coinbase)) data := block.state.trie.Get(string(block.Coinbase))
// Get the ether (Coinbase) and add the fee (gief fee to miner) // Get the ether (Coinbase) and add the fee (gief fee to miner)
ether := NewAccountFromData(block.Coinbase, []byte(data)) account := NewStateObjectFromBytes(block.Coinbase, []byte(data))
base = new(big.Int) base = new(big.Int)
ether.Amount = base.Add(ether.Amount, fee) account.Amount = base.Add(account.Amount, fee)
block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) //block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode()))
block.state.UpdateStateObject(account)
return true return true
} }
...@@ -178,26 +174,6 @@ func (block *Block) MakeContract(tx *Transaction) { ...@@ -178,26 +174,6 @@ func (block *Block) MakeContract(tx *Transaction) {
} }
/////// Block Encoding /////// 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{} { func (block *Block) rlpTxs() interface{} {
// Marshal the transactions of this block // Marshal the transactions of this block
encTx := make([]interface{}, len(block.transactions)) encTx := make([]interface{}, len(block.transactions))
...@@ -304,6 +280,9 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { ...@@ -304,6 +280,9 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
func (block *Block) String() string { 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\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
} }
func (block *Block) GetRoot() interface{} {
return block.state.trie.Root
}
//////////// UNEXPORTED ///////////////// //////////// UNEXPORTED /////////////////
func (block *Block) header() []interface{} { func (block *Block) header() []interface{} {
......
...@@ -3,6 +3,7 @@ package ethchain ...@@ -3,6 +3,7 @@ package ethchain
import ( import (
"bytes" "bytes"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"log" "log"
"math" "math"
"math/big" "math/big"
...@@ -23,7 +24,8 @@ type BlockChain struct { ...@@ -23,7 +24,8 @@ type BlockChain struct {
func NewBlockChain(ethereum EthManager) *BlockChain { func NewBlockChain(ethereum EthManager) *BlockChain {
bc := &BlockChain{} bc := &BlockChain{}
bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis))
bc.Ethereum = ethereum
bc.setLastBlock() bc.setLastBlock()
...@@ -78,6 +80,128 @@ func (bc *BlockChain) HasBlock(hash []byte) bool { ...@@ -78,6 +80,128 @@ func (bc *BlockChain) HasBlock(hash []byte) bool {
return len(data) != 0 return len(data) != 0
} }
// TODO: At one point we might want to save a block by prevHash in the db to optimise this...
func (bc *BlockChain) HasBlockWithPrevHash(hash []byte) bool {
block := bc.CurrentBlock
for ; block != nil; block = bc.GetBlock(block.PrevHash) {
if bytes.Compare(hash, block.PrevHash) == 0 {
return true
}
}
return false
}
func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int {
blockDiff := new(big.Int)
for _, uncle := range block.Uncles {
blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty)
}
blockDiff = blockDiff.Add(blockDiff, block.Difficulty)
return blockDiff
}
func (bc *BlockChain) FindCanonicalChainFromMsg(msg *ethwire.Msg, commonBlockHash []byte) bool {
var blocks []*Block
for i := 0; i < (msg.Data.Len() - 1); i++ {
block := NewBlockFromRlpValue(msg.Data.Get(i))
blocks = append(blocks, block)
}
return bc.FindCanonicalChain(blocks, commonBlockHash)
}
// Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one
// Return true if we are the using the canonical chain false if not
func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte) bool {
// 1. Calculate TD of the current chain
// 2. Calculate TD of the new chain
// Reset state to the correct one
chainDifficulty := new(big.Int)
// Calculate the entire chain until the block we both have
// Start with the newest block we got, all the way back to the common block we both know
for _, block := range blocks {
if bytes.Compare(block.Hash(), commonBlockHash) == 0 {
log.Println("[CHAIN] We have found the common parent block, breaking")
break
}
log.Println("Checking incoming blocks:")
chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block))
}
log.Println("[CHAIN] Incoming chain difficulty:", chainDifficulty)
curChainDifficulty := new(big.Int)
block := bc.CurrentBlock
for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) {
i++
if bytes.Compare(block.Hash(), commonBlockHash) == 0 {
log.Println("[CHAIN] We have found the common parent block, breaking")
break
}
anOtherBlock := bc.GetBlock(block.PrevHash)
if anOtherBlock == nil {
// We do not want to count the genesis block for difficulty since that's not being sent
log.Println("[CHAIN] At genesis block, breaking")
break
}
curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block))
}
log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty)
if chainDifficulty.Cmp(curChainDifficulty) == 1 {
log.Printf("[CHAIN] The incoming Chain beat our asses, resetting to block: %x", commonBlockHash)
bc.ResetTillBlockHash(commonBlockHash)
return false
} else {
log.Println("[CHAIN] Our chain showed the incoming chain who is boss. Ignoring.")
return true
}
}
func (bc *BlockChain) ResetTillBlockHash(hash []byte) error {
lastBlock := bc.CurrentBlock
var returnTo *Block
// Reset to Genesis if that's all the origin there is.
if bytes.Compare(hash, bc.genesisBlock.Hash()) == 0 {
returnTo = bc.genesisBlock
bc.CurrentBlock = bc.genesisBlock
bc.LastBlockHash = bc.genesisBlock.Hash()
bc.LastBlockNumber = 1
} else {
// TODO: Somehow this doesn't really give the right numbers, double check.
// TODO: Change logs into debug lines
returnTo = bc.GetBlock(hash)
bc.CurrentBlock = returnTo
bc.LastBlockHash = returnTo.Hash()
info := bc.BlockInfo(returnTo)
bc.LastBlockNumber = info.Number
}
// XXX Why are we resetting? This is the block chain, it has nothing to do with states
//bc.Ethereum.StateManager().PrepareDefault(returnTo)
err := ethutil.Config.Db.Delete(lastBlock.Hash())
if err != nil {
return err
}
var block *Block
for ; block != nil; block = bc.GetBlock(block.PrevHash) {
if bytes.Compare(block.Hash(), hash) == 0 {
log.Println("[CHAIN] We have arrived at the the common parent block, breaking")
break
}
err = ethutil.Config.Db.Delete(block.Hash())
if err != nil {
return err
}
}
log.Println("[CHAIN] Split chain deleted and reverted to common parent block.")
return nil
}
func (bc *BlockChain) GenesisBlock() *Block { func (bc *BlockChain) GenesisBlock() *Block {
return bc.genesisBlock return bc.genesisBlock
} }
...@@ -136,12 +260,13 @@ func AddTestNetFunds(block *Block) { ...@@ -136,12 +260,13 @@ func AddTestNetFunds(block *Block) {
"e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex
"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran
} { } {
//log.Println("2^200 Wei to", addr) //log.Println("2^200 Wei to", addr)
codedAddr := ethutil.FromHex(addr) codedAddr := ethutil.FromHex(addr)
addr := block.state.GetAccount(codedAddr) account := block.state.GetAccount(codedAddr)
addr.Amount = ethutil.BigPow(2, 200) account.Amount = ethutil.BigPow(2, 200)
block.state.UpdateAccount(codedAddr, addr) block.state.UpdateStateObject(account)
} }
} }
...@@ -180,8 +305,8 @@ func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { ...@@ -180,8 +305,8 @@ func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
// Add a block to the chain and record addition information // Add a block to the chain and record addition information
func (bc *BlockChain) Add(block *Block) { func (bc *BlockChain) Add(block *Block) {
bc.writeBlockInfo(block) bc.writeBlockInfo(block)
// Prepare the genesis block // Prepare the genesis block
bc.CurrentBlock = block bc.CurrentBlock = block
bc.LastBlockHash = block.Hash() bc.LastBlockHash = block.Hash()
...@@ -196,7 +321,7 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block { ...@@ -196,7 +321,7 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block {
return nil return nil
} }
return NewBlockFromData(data) return NewBlockFromBytes(data)
} }
func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo {
......
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"testing"
)
// Implement our EthTest Manager
type TestManager struct {
stateManager *StateManager
reactor *ethutil.ReactorEngine
txPool *TxPool
blockChain *BlockChain
Blocks []*Block
}
func (s *TestManager) BlockChain() *BlockChain {
return s.blockChain
}
func (tm *TestManager) TxPool() *TxPool {
return tm.txPool
}
func (tm *TestManager) StateManager() *StateManager {
return tm.stateManager
}
func (tm *TestManager) Reactor() *ethutil.ReactorEngine {
return tm.reactor
}
func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) {
fmt.Println("Broadcast not implemented")
}
func NewTestManager() *TestManager {
ethutil.ReadConfig(".ethtest")
db, err := ethdb.NewMemDatabase()
if err != nil {
fmt.Println("Could not create mem-db, failing")
return nil
}
ethutil.Config.Db = db
testManager := &TestManager{}
testManager.reactor = ethutil.NewReactorEngine()
testManager.txPool = NewTxPool(testManager)
testManager.blockChain = NewBlockChain(testManager)
testManager.stateManager = NewStateManager(testManager)
// Start the tx pool
testManager.txPool.Start()
return testManager
}
func (tm *TestManager) AddFakeBlock(blk []byte) error {
block := NewBlockFromBytes(blk)
tm.Blocks = append(tm.Blocks, block)
tm.StateManager().PrepareDefault(block)
err := tm.StateManager().ProcessBlock(block, false)
return err
}
func (tm *TestManager) CreateChain1() error {
err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 32, 251, 128, 160, 4, 10, 11, 225, 132, 86, 146, 227, 229, 137, 164, 245, 16, 139, 219, 12, 251, 178, 154, 168, 210, 18, 84, 40, 250, 41, 124, 92, 169, 242, 246, 180, 192, 192})
err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 222, 229, 152, 228, 200, 163, 244, 144, 120, 18, 203, 253, 195, 185, 105, 131, 163, 226, 116, 40, 140, 68, 249, 198, 221, 152, 121, 0, 124, 11, 180, 125, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 224, 4, 132, 83, 48, 36, 250, 128, 160, 79, 58, 51, 246, 238, 249, 210, 253, 136, 83, 71, 134, 49, 114, 190, 189, 242, 78, 100, 238, 101, 84, 204, 176, 198, 25, 139, 151, 60, 84, 51, 126, 192, 192})
err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 68, 52, 33, 210, 160, 189, 217, 255, 78, 37, 196, 217, 94, 247, 166, 169, 224, 199, 102, 110, 85, 213, 45, 13, 173, 106, 4, 103, 151, 195, 38, 86, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 208, 12, 132, 83, 48, 38, 206, 128, 160, 65, 147, 32, 128, 177, 198, 131, 57, 57, 68, 135, 65, 198, 178, 138, 43, 25, 135, 92, 174, 208, 119, 103, 225, 26, 207, 243, 31, 225, 29, 173, 119, 192, 192})
return err
}
func (tm *TestManager) CreateChain2() error {
err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 40, 35, 128, 160, 162, 214, 119, 207, 212, 186, 64, 47, 14, 186, 98, 118, 203, 79, 172, 205, 33, 206, 225, 177, 225, 194, 98, 188, 63, 219, 13, 151, 47, 32, 204, 27, 192, 192})
err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 0, 210, 76, 6, 13, 18, 219, 190, 18, 250, 23, 178, 198, 117, 254, 85, 14, 74, 104, 116, 56, 144, 116, 172, 14, 3, 236, 99, 248, 228, 142, 91, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 255, 252, 132, 83, 48, 40, 74, 128, 160, 185, 20, 138, 2, 210, 15, 71, 144, 89, 167, 94, 155, 148, 118, 170, 157, 122, 70, 70, 114, 50, 221, 231, 8, 132, 167, 115, 239, 44, 245, 41, 226, 192, 192})
return err
}
func TestNegativeBlockChainReorg(t *testing.T) {
// We are resetting the database between creation so we need to cache our information
testManager2 := NewTestManager()
testManager2.CreateChain2()
tm2Blocks := testManager2.Blocks
testManager := NewTestManager()
testManager.CreateChain1()
oldState := testManager.BlockChain().CurrentBlock.State()
if testManager.BlockChain().FindCanonicalChain(tm2Blocks, testManager.BlockChain().GenesisBlock().Hash()) != true {
t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.")
}
if testManager.BlockChain().CurrentBlock.State() != oldState {
t.Error("I expected the top state to be the same as it was as before the reorg")
}
}
func TestPositiveBlockChainReorg(t *testing.T) {
testManager := NewTestManager()
testManager.CreateChain1()
tm1Blocks := testManager.Blocks
testManager2 := NewTestManager()
testManager2.CreateChain2()
oldState := testManager2.BlockChain().CurrentBlock.State()
if testManager2.BlockChain().FindCanonicalChain(tm1Blocks, testManager.BlockChain().GenesisBlock().Hash()) == true {
t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.")
}
if testManager2.BlockChain().CurrentBlock.State() == oldState {
t.Error("I expected the top state to have been modified but it was not")
}
}
...@@ -7,33 +7,39 @@ import ( ...@@ -7,33 +7,39 @@ import (
"math/big" "math/big"
) )
type Callee interface { type ClosureRef interface {
ReturnGas(*big.Int, *State) ReturnGas(*big.Int, *big.Int, *State)
Address() []byte Address() []byte
}
type ClosureBody interface {
Callee
ethutil.RlpEncodable
GetMem(*big.Int) *ethutil.Value GetMem(*big.Int) *ethutil.Value
SetMem(*big.Int, *ethutil.Value) SetMem(*big.Int, *ethutil.Value)
N() *big.Int
} }
// Basic inline closure object which implement the 'closure' interface // Basic inline closure object which implement the 'closure' interface
type Closure struct { type Closure struct {
callee Callee callee *StateObject
object ClosureBody object *StateObject
Script []byte
State *State State *State
Gas *big.Int Gas *big.Int
Price *big.Int
Value *big.Int Value *big.Int
Args []byte Args []byte
} }
// Create a new closure for the given data items // Create a new closure for the given data items
func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure { func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price, val *big.Int) *Closure {
return &Closure{callee, object, state, gas, val, nil} c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil}
// In most cases gas, price and value are pointers to transaction objects
// and we don't want the transaction's values to change.
c.Gas = new(big.Int).Set(gas)
c.Price = new(big.Int).Set(price)
c.Value = new(big.Int).Set(val)
return c
} }
// Retuns the x element in data slice // Retuns the x element in data slice
...@@ -46,6 +52,20 @@ func (c *Closure) GetMem(x *big.Int) *ethutil.Value { ...@@ -46,6 +52,20 @@ func (c *Closure) GetMem(x *big.Int) *ethutil.Value {
return m return m
} }
func (c *Closure) Get(x *big.Int) *ethutil.Value {
return c.Gets(x, big.NewInt(1))
}
func (c *Closure) Gets(x, y *big.Int) *ethutil.Value {
if x.Int64() >= int64(len(c.Script)) || y.Int64() >= int64(len(c.Script)) {
return ethutil.NewValue(0)
}
partial := c.Script[x.Int64() : x.Int64()+y.Int64()]
return ethutil.NewValue(partial)
}
func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) {
c.object.SetMem(x, val) c.object.SetMem(x, val)
} }
...@@ -54,10 +74,12 @@ func (c *Closure) Address() []byte { ...@@ -54,10 +74,12 @@ func (c *Closure) Address() []byte {
return c.object.Address() return c.object.Address()
} }
func (c *Closure) Call(vm *Vm, args []byte) []byte { type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack)
func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) {
c.Args = args c.Args = args
return vm.RunClosure(c) return vm.RunClosure(c, hook)
} }
func (c *Closure) Return(ret []byte) []byte { func (c *Closure) Return(ret []byte) []byte {
...@@ -65,26 +87,28 @@ func (c *Closure) Return(ret []byte) []byte { ...@@ -65,26 +87,28 @@ func (c *Closure) Return(ret []byte) []byte {
// If no callee is present return it to // If no callee is present return it to
// the origin (i.e. contract or tx) // the origin (i.e. contract or tx)
if c.callee != nil { if c.callee != nil {
c.callee.ReturnGas(c.Gas, c.State) c.callee.ReturnGas(c.Gas, c.Price, c.State)
} else { } else {
c.object.ReturnGas(c.Gas, c.State) c.object.ReturnGas(c.Gas, c.Price, c.State)
// TODO incase it's a POST contract we gotta serialise the contract again.
// But it's not yet defined
} }
return ret return ret
} }
// Implement the Callee interface // Implement the Callee interface
func (c *Closure) ReturnGas(gas *big.Int, state *State) { func (c *Closure) ReturnGas(gas, price *big.Int, state *State) {
// Return the gas to the closure // Return the gas to the closure
c.Gas.Add(c.Gas, gas) c.Gas.Add(c.Gas, gas)
} }
func (c *Closure) Object() ClosureBody { func (c *Closure) Object() *StateObject {
return c.object return c.object
} }
func (c *Closure) Callee() Callee { func (c *Closure) Callee() *StateObject {
return c.callee return c.callee
} }
func (c *Closure) N() *big.Int {
return c.object.N()
}
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type Contract struct {
Amount *big.Int
Nonce uint64
//state *ethutil.Trie
state *State
address []byte
}
func NewContract(address []byte, Amount *big.Int, root []byte) *Contract {
contract := &Contract{address: address, Amount: Amount, Nonce: 0}
contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root)))
return contract
}
func NewContractFromBytes(address, data []byte) *Contract {
contract := &Contract{address: address}
contract.RlpDecode(data)
return contract
}
func (c *Contract) Addr(addr []byte) *ethutil.Value {
return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr))))
}
func (c *Contract) SetAddr(addr []byte, value interface{}) {
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
}
func (c *Contract) State() *State {
return c.state
}
func (c *Contract) GetMem(num *big.Int) *ethutil.Value {
nb := ethutil.BigToBytes(num, 256)
return c.Addr(nb)
}
func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) {
addr := ethutil.BigToBytes(num, 256)
c.state.trie.Update(string(addr), string(val.Encode()))
}
// Return the gas back to the origin. Used by the Virtual machine or Closures
func (c *Contract) ReturnGas(val *big.Int, state *State) {
c.Amount.Add(c.Amount, val)
}
func (c *Contract) Address() []byte {
return c.address
}
func (c *Contract) RlpEncode() []byte {
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root})
}
func (c *Contract) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
c.Amount = decoder.Get(0).BigInt()
c.Nonce = decoder.Get(1).Uint()
c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
}
func MakeContract(tx *Transaction, state *State) *Contract {
// Create contract if there's no recipient
if tx.IsContract() {
addr := tx.Hash()[12:]
value := tx.Value
contract := NewContract(addr, value, []byte(""))
state.trie.Update(string(addr), string(contract.RlpEncode()))
for i, val := range tx.Data {
if len(val) > 0 {
bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256)
contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val)))
}
}
state.trie.Update(string(addr), string(contract.RlpEncode()))
return contract
}
return nil
}
...@@ -11,7 +11,7 @@ import ( ...@@ -11,7 +11,7 @@ import (
) )
type PoW interface { type PoW interface {
Search(block *Block) []byte Search(block *Block, reactChan chan ethutil.React) []byte
Verify(hash []byte, diff *big.Int, nonce []byte) bool Verify(hash []byte, diff *big.Int, nonce []byte) bool
} }
...@@ -19,15 +19,30 @@ type EasyPow struct { ...@@ -19,15 +19,30 @@ type EasyPow struct {
hash *big.Int hash *big.Int
} }
func (pow *EasyPow) Search(block *Block) []byte { func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte {
r := rand.New(rand.NewSource(time.Now().UnixNano())) r := rand.New(rand.NewSource(time.Now().UnixNano()))
hash := block.HashNoNonce() hash := block.HashNoNonce()
diff := block.Difficulty diff := block.Difficulty
i := int64(0)
start := time.Now().UnixNano()
for { for {
sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) select {
if pow.Verify(hash, diff, sha) { case <-reactChan:
return sha log.Println("[POW] Received reactor event; breaking out.")
return nil
default:
i++
if i%1234567 == 0 {
elapsed := time.Now().UnixNano() - start
hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000
log.Println("[POW] Hashing @", int64(hashes), "khash")
}
sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes())
if pow.Verify(hash, diff, sha) {
return sha
}
} }
} }
...@@ -98,9 +113,9 @@ func (dag *Dagger) Search(hash, diff *big.Int) *big.Int { ...@@ -98,9 +113,9 @@ func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
for k := 0; k < amountOfRoutines; k++ { for k := 0; k < amountOfRoutines; k++ {
go dag.Find(obj, resChan) go dag.Find(obj, resChan)
}
// Wait for each go routine to finish // Wait for each go routine to finish
}
for k := 0; k < amountOfRoutines; k++ { for k := 0; k < amountOfRoutines; k++ {
// Get the result from the channel. 0 = quit // Get the result from the channel. 0 = quit
if r := <-resChan; r != 0 { if r := <-resChan; r != 0 {
......
package ethchain package ethchain
import "fmt" import (
"fmt"
)
// Parent error. In case a parent is unknown this error will be thrown // Parent error. In case a parent is unknown this error will be thrown
// by the block manager // by the block manager
...@@ -40,3 +42,22 @@ func IsValidationErr(err error) bool { ...@@ -40,3 +42,22 @@ func IsValidationErr(err error) bool {
return ok return ok
} }
type NonceErr struct {
Message string
Is, Exp uint64
}
func (err *NonceErr) Error() string {
return err.Message
}
func NonceError(is, exp uint64) *NonceErr {
return &NonceErr{Message: fmt.Sprintf("Nonce err. Is %d, expected %d", is, exp), Is: is, Exp: exp}
}
func IsNonceErr(err error) bool {
_, ok := err.(*NonceErr)
return ok
}
...@@ -2,6 +2,7 @@ package ethchain ...@@ -2,6 +2,7 @@ package ethchain
import ( import (
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
"math/big" "math/big"
) )
...@@ -10,10 +11,19 @@ type KeyPair struct { ...@@ -10,10 +11,19 @@ type KeyPair struct {
PublicKey []byte PublicKey []byte
// The associated account // The associated account
account *Account account *StateObject
state *State state *State
} }
func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) {
pubkey, err := secp256k1.GeneratePubKey(seckey)
if err != nil {
return nil, err
}
return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil
}
func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { func NewKeyPairFromValue(val *ethutil.Value) *KeyPair {
keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()}
...@@ -24,7 +34,7 @@ func (k *KeyPair) Address() []byte { ...@@ -24,7 +34,7 @@ func (k *KeyPair) Address() []byte {
return ethutil.Sha3Bin(k.PublicKey[1:])[12:] return ethutil.Sha3Bin(k.PublicKey[1:])[12:]
} }
func (k *KeyPair) Account() *Account { func (k *KeyPair) Account() *StateObject {
if k.account == nil { if k.account == nil {
k.account = k.state.GetAccount(k.Address()) k.account = k.state.GetAccount(k.Address())
} }
...@@ -34,6 +44,7 @@ func (k *KeyPair) Account() *Account { ...@@ -34,6 +44,7 @@ func (k *KeyPair) Account() *Account {
// Create transaction, creates a new and signed transaction, ready for processing // Create transaction, creates a new and signed transaction, ready for processing
func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction {
/* TODO
tx := NewTransaction(receiver, value, data) tx := NewTransaction(receiver, value, data)
tx.Nonce = k.account.Nonce tx.Nonce = k.account.Nonce
...@@ -41,6 +52,8 @@ func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Tran ...@@ -41,6 +52,8 @@ func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Tran
tx.Sign(k.PrivateKey) tx.Sign(k.PrivateKey)
return tx return tx
*/
return nil
} }
func (k *KeyPair) RlpEncode() []byte { func (k *KeyPair) RlpEncode() []byte {
......
...@@ -6,152 +6,6 @@ import ( ...@@ -6,152 +6,6 @@ import (
"math/big" "math/big"
) )
type OpCode int
// Op codes
const (
// 0x0 range - arithmetic ops
oSTOP = 0x00
oADD = 0x01
oMUL = 0x02
oSUB = 0x03
oDIV = 0x04
oSDIV = 0x05
oMOD = 0x06
oSMOD = 0x07
oEXP = 0x08
oNEG = 0x09
oLT = 0x0a
oGT = 0x0b
oEQ = 0x0c
oNOT = 0x0d
// 0x10 range - bit ops
oAND = 0x10
oOR = 0x11
oXOR = 0x12
oBYTE = 0x13
// 0x20 range - crypto
oSHA3 = 0x20
// 0x30 range - closure state
oADDRESS = 0x30
oBALANCE = 0x31
oORIGIN = 0x32
oCALLER = 0x33
oCALLVALUE = 0x34
oCALLDATA = 0x35
oCALLDATASIZE = 0x36
oGASPRICE = 0x37
// 0x40 range - block operations
oPREVHASH = 0x40
oCOINBASE = 0x41
oTIMESTAMP = 0x42
oNUMBER = 0x43
oDIFFICULTY = 0x44
oGASLIMIT = 0x45
// 0x50 range - 'storage' and execution
oPUSH = 0x50
oPOP = 0x51
oDUP = 0x52
oSWAP = 0x53
oMLOAD = 0x54
oMSTORE = 0x55
oMSTORE8 = 0x56
oSLOAD = 0x57
oSSTORE = 0x58
oJUMP = 0x59
oJUMPI = 0x5a
oPC = 0x5b
oMSIZE = 0x5c
// 0x60 range - closures
oCREATE = 0x60
oCALL = 0x61
oRETURN = 0x62
// 0x70 range - other
oLOG = 0x70 // XXX Unofficial
oSUICIDE = 0x7f
)
// Since the opcodes aren't all in order we can't use a regular slice
var opCodeToString = map[OpCode]string{
// 0x0 range - arithmetic ops
oSTOP: "STOP",
oADD: "ADD",
oMUL: "MUL",
oSUB: "SUB",
oDIV: "DIV",
oSDIV: "SDIV",
oMOD: "MOD",
oSMOD: "SMOD",
oEXP: "EXP",
oNEG: "NEG",
oLT: "LT",
oGT: "GT",
oEQ: "EQ",
oNOT: "NOT",
// 0x10 range - bit ops
oAND: "AND",
oOR: "OR",
oXOR: "XOR",
oBYTE: "BYTE",
// 0x20 range - crypto
oSHA3: "SHA3",
// 0x30 range - closure state
oADDRESS: "ADDRESS",
oBALANCE: "BALANCE",
oORIGIN: "ORIGIN",
oCALLER: "CALLER",
oCALLVALUE: "CALLVALUE",
oCALLDATA: "CALLDATA",
oCALLDATASIZE: "CALLDATASIZE",
oGASPRICE: "TXGASPRICE",
// 0x40 range - block operations
oPREVHASH: "PREVHASH",
oCOINBASE: "COINBASE",
oTIMESTAMP: "TIMESTAMP",
oNUMBER: "NUMBER",
oDIFFICULTY: "DIFFICULTY",
oGASLIMIT: "GASLIMIT",
// 0x50 range - 'storage' and execution
oPUSH: "PUSH",
oPOP: "POP",
oDUP: "DUP",
oSWAP: "SWAP",
oMLOAD: "MLOAD",
oMSTORE: "MSTORE",
oMSTORE8: "MSTORE8",
oSLOAD: "SLOAD",
oSSTORE: "SSTORE",
oJUMP: "JUMP",
oJUMPI: "JUMPI",
oPC: "PC",
oMSIZE: "MSIZE",
// 0x60 range - closures
oCREATE: "CREATE",
oCALL: "CALL",
oRETURN: "RETURN",
// 0x70 range - other
oLOG: "LOG",
oSUICIDE: "SUICIDE",
}
func (o OpCode) String() string {
return opCodeToString[o]
}
type OpType int type OpType int
const ( const (
...@@ -172,22 +26,34 @@ func NewStack() *Stack { ...@@ -172,22 +26,34 @@ func NewStack() *Stack {
return &Stack{} return &Stack{}
} }
func (st *Stack) Data() []*big.Int {
return st.data
}
func (st *Stack) Len() int {
return len(st.data)
}
func (st *Stack) Pop() *big.Int { func (st *Stack) Pop() *big.Int {
str := st.data[0] str := st.data[len(st.data)-1]
st.data = st.data[1:]
copy(st.data[:len(st.data)-1], st.data[:len(st.data)-1])
st.data = st.data[:len(st.data)-1]
return str return str
} }
func (st *Stack) Popn() (*big.Int, *big.Int) { func (st *Stack) Popn() (*big.Int, *big.Int) {
ints := st.data[:2] ints := st.data[len(st.data)-2:]
st.data = st.data[2:]
copy(st.data[:len(st.data)-2], st.data[:len(st.data)-2])
st.data = st.data[:len(st.data)-2]
return ints[0], ints[1] return ints[0], ints[1]
} }
func (st *Stack) Peek() *big.Int { func (st *Stack) Peek() *big.Int {
str := st.data[0] str := st.data[len(st.data)-1]
return str return str
} }
...@@ -201,8 +67,20 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) { ...@@ -201,8 +67,20 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) {
func (st *Stack) Push(d *big.Int) { func (st *Stack) Push(d *big.Int) {
st.data = append(st.data, d) st.data = append(st.data, d)
} }
func (st *Stack) Get(amount *big.Int) []*big.Int {
// offset + size <= len(data)
length := big.NewInt(int64(len(st.data)))
if amount.Cmp(length) <= 0 {
start := new(big.Int).Sub(length, amount)
return st.data[start.Int64():length.Int64()]
}
return nil
}
func (st *Stack) Print() { func (st *Stack) Print() {
fmt.Println("### STACK ###") fmt.Println("### stack ###")
if len(st.data) > 0 { if len(st.data) > 0 {
for i, val := range st.data { for i, val := range st.data {
fmt.Printf("%-3d %v\n", i, val) fmt.Printf("%-3d %v\n", i, val)
...@@ -241,16 +119,20 @@ func (m *Memory) Len() int { ...@@ -241,16 +119,20 @@ func (m *Memory) Len() int {
return len(m.store) return len(m.store)
} }
func (m *Memory) Data() []byte {
return m.store
}
func (m *Memory) Print() { func (m *Memory) Print() {
fmt.Println("### MEM ###") fmt.Printf("### mem %d bytes ###\n", len(m.store))
if len(m.store) > 0 { if len(m.store) > 0 {
addr := 0 addr := 0
for i := 0; i+32 < len(m.store); i += 32 { for i := 0; i+32 <= len(m.store); i += 32 {
fmt.Printf("%03d %v\n", addr, m.store[i:i+32]) fmt.Printf("%03d: % x\n", addr, m.store[i:i+32])
addr++ addr++
} }
} else { } else {
fmt.Println("-- empty --") fmt.Println("-- empty --")
} }
fmt.Println("###########") fmt.Println("####################")
} }
...@@ -34,12 +34,12 @@ func (s *State) Reset() { ...@@ -34,12 +34,12 @@ func (s *State) Reset() {
// Syncs the trie and all siblings // Syncs the trie and all siblings
func (s *State) Sync() { func (s *State) Sync() {
s.trie.Sync()
// Sync all nested states // Sync all nested states
for _, state := range s.states { for _, state := range s.states {
state.Sync() state.Sync()
} }
s.trie.Sync()
} }
// Purges the current trie. // Purges the current trie.
...@@ -47,23 +47,15 @@ func (s *State) Purge() int { ...@@ -47,23 +47,15 @@ func (s *State) Purge() int {
return s.trie.NewIterator().Purge() return s.trie.NewIterator().Purge()
} }
func (s *State) GetContract(addr []byte) *Contract { // XXX Deprecated
func (s *State) GetContract(addr []byte) *StateObject {
data := s.trie.Get(string(addr)) data := s.trie.Get(string(addr))
if data == "" { if data == "" {
return nil return nil
} }
// Whet get contract is called the retrieved value might
// be an account. The StateManager uses this to check
// to see if the address a tx was sent to is a contract
// or an account
value := ethutil.NewValueFromBytes([]byte(data))
if value.Len() == 2 {
return nil
}
// build contract // build contract
contract := NewContractFromBytes(addr, []byte(data)) contract := NewStateObjectFromBytes(addr, []byte(data))
// Check if there's a cached state for this contract // Check if there's a cached state for this contract
cachedState := s.states[string(addr)] cachedState := s.states[string(addr)]
...@@ -77,28 +69,43 @@ func (s *State) GetContract(addr []byte) *Contract { ...@@ -77,28 +69,43 @@ func (s *State) GetContract(addr []byte) *Contract {
return contract return contract
} }
func (s *State) UpdateContract(contract *Contract) { func (s *State) GetStateObject(addr []byte) *StateObject {
addr := contract.Address() data := s.trie.Get(string(addr))
if data == "" {
return nil
}
stateObject := NewStateObjectFromBytes(addr, []byte(data))
// Check if there's a cached state for this contract
cachedStateObject := s.states[string(addr)]
if cachedStateObject != nil {
stateObject.state = cachedStateObject
} else {
// If it isn't cached, cache the state
s.states[string(addr)] = stateObject.state
}
return stateObject
}
func (s *State) SetStateObject(stateObject *StateObject) {
s.states[string(stateObject.address)] = stateObject.state
s.states[string(addr)] = contract.state s.UpdateStateObject(stateObject)
s.trie.Update(string(addr), string(contract.RlpEncode()))
} }
func (s *State) GetAccount(addr []byte) (account *Account) { func (s *State) GetAccount(addr []byte) (account *StateObject) {
data := s.trie.Get(string(addr)) data := s.trie.Get(string(addr))
if data == "" { if data == "" {
account = NewAccount(addr, big.NewInt(0)) account = NewAccount(addr, big.NewInt(0))
} else { } else {
account = NewAccountFromData(addr, []byte(data)) account = NewStateObjectFromBytes(addr, []byte(data))
} }
return return
} }
func (s *State) UpdateAccount(addr []byte, account *Account) {
s.trie.Update(string(addr), string(account.RlpEncode()))
}
func (s *State) Cmp(other *State) bool { func (s *State) Cmp(other *State) bool {
return s.trie.Cmp(other.trie) return s.trie.Cmp(other.trie)
} }
...@@ -117,9 +124,10 @@ const ( ...@@ -117,9 +124,10 @@ const (
UnknownTy UnknownTy
) )
/*
// Returns the object stored at key and the type stored at key // Returns the object stored at key and the type stored at key
// Returns nil if nothing is stored // Returns nil if nothing is stored
func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) {
// Fetch data from the trie // Fetch data from the trie
data := s.trie.Get(string(key)) data := s.trie.Get(string(key))
// Returns the nil type, indicating nothing could be retrieved. // Returns the nil type, indicating nothing could be retrieved.
...@@ -144,35 +152,23 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { ...@@ -144,35 +152,23 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) {
return val, typ return val, typ
} }
*/
func (s *State) Put(key, object []byte) { // Updates any given state object
s.trie.Update(string(key), string(object)) func (s *State) UpdateStateObject(object *StateObject) {
} addr := object.Address()
func (s *State) Root() interface{} {
return s.trie.Root
}
// Script compilation functions
// Compiles strings to machine code
func Compile(code []string) (script []string) {
script = make([]string, len(code))
for i, val := range code {
instr, _ := ethutil.CompileInstr(val)
script[i] = string(instr) if object.state != nil {
s.states[string(addr)] = object.state
} }
return s.trie.Update(string(addr), string(object.RlpEncode()))
} }
func CompileToValues(code []string) (script []*ethutil.Value) { func (s *State) Put(key, object []byte) {
script = make([]*ethutil.Value, len(code)) s.trie.Update(string(key), string(object))
for i, val := range code { }
instr, _ := ethutil.CompileInstr(val)
script[i] = ethutil.NewValue(instr)
}
return func (s *State) Root() interface{} {
return s.trie.Root
} }
This diff is collapsed.
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type StateObject struct {
// Address of the object
address []byte
// Shared attributes
Amount *big.Int
Nonce uint64
// Contract related attributes
state *State
script []byte
initScript []byte
}
// Converts an transaction in to a state object
func MakeContract(tx *Transaction, state *State) *StateObject {
// Create contract if there's no recipient
if tx.IsContract() {
// FIXME
addr := tx.Hash()[12:]
value := tx.Value
contract := NewContract(addr, value, []byte(""))
state.UpdateStateObject(contract)
contract.script = tx.Data
contract.initScript = tx.Init
state.UpdateStateObject(contract)
return contract
}
return nil
}
func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject {
contract := &StateObject{address: address, Amount: Amount, Nonce: 0}
contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root)))
return contract
}
// Returns a newly created account
func NewAccount(address []byte, amount *big.Int) *StateObject {
account := &StateObject{address: address, Amount: amount, Nonce: 0}
return account
}
func NewStateObjectFromBytes(address, data []byte) *StateObject {
object := &StateObject{address: address}
object.RlpDecode(data)
return object
}
func (c *StateObject) State() *State {
return c.state
}
func (c *StateObject) N() *big.Int {
return big.NewInt(int64(c.Nonce))
}
func (c *StateObject) Addr(addr []byte) *ethutil.Value {
return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr))))
}
func (c *StateObject) SetAddr(addr []byte, value interface{}) {
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
}
func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) {
addr := ethutil.BigToBytes(num, 256)
c.SetAddr(addr, val)
}
func (c *StateObject) GetMem(num *big.Int) *ethutil.Value {
nb := ethutil.BigToBytes(num, 256)
return c.Addr(nb)
}
func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
if int64(len(c.script)-1) < pc.Int64() {
return ethutil.NewValue(0)
}
return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]})
}
// Return the gas back to the origin. Used by the Virtual machine or Closures
func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) {
remainder := new(big.Int).Mul(gas, price)
c.AddAmount(remainder)
}
func (c *StateObject) AddAmount(amount *big.Int) {
c.SetAmount(new(big.Int).Add(c.Amount, amount))
}
func (c *StateObject) SubAmount(amount *big.Int) {
c.SetAmount(new(big.Int).Sub(c.Amount, amount))
}
func (c *StateObject) SetAmount(amount *big.Int) {
c.Amount = amount
}
func (c *StateObject) ConvertGas(gas, price *big.Int) error {
total := new(big.Int).Mul(gas, price)
if total.Cmp(c.Amount) > 0 {
return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total)
}
c.SubAmount(total)
return nil
}
// Returns the address of the contract/account
func (c *StateObject) Address() []byte {
return c.address
}
// Returns the main script body
func (c *StateObject) Script() []byte {
return c.script
}
// Returns the initialization script
func (c *StateObject) Init() []byte {
return c.initScript
}
// State object encoding methods
func (c *StateObject) RlpEncode() []byte {
var root interface{}
if c.state != nil {
root = c.state.trie.Root
} else {
root = nil
}
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, c.script})
}
func (c *StateObject) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
c.Amount = decoder.Get(0).BigInt()
c.Nonce = decoder.Get(1).Uint()
c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
c.script = decoder.Get(3).Bytes()
}
// The cached state and state object cache are helpers which will give you somewhat
// control over the nonce. When creating new transactions you're interested in the 'next'
// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions.
type StateObjectCache struct {
cachedObjects map[string]*CachedStateObject
}
func NewStateObjectCache() *StateObjectCache {
return &StateObjectCache{cachedObjects: make(map[string]*CachedStateObject)}
}
func (s *StateObjectCache) Add(addr []byte, object *StateObject) *CachedStateObject {
state := &CachedStateObject{Nonce: object.Nonce, Object: object}
s.cachedObjects[string(addr)] = state
return state
}
func (s *StateObjectCache) Get(addr []byte) *CachedStateObject {
return s.cachedObjects[string(addr)]
}
type CachedStateObject struct {
Nonce uint64
Object *StateObject
}
type StorageState struct {
StateAddress []byte
Address []byte
Value *big.Int
}
package ethchain package ethchain
import ( import (
"bytes"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go" "github.com/obscuren/secp256k1-go"
"math/big" "math/big"
...@@ -14,33 +13,22 @@ type Transaction struct { ...@@ -14,33 +13,22 @@ type Transaction struct {
Recipient []byte Recipient []byte
Value *big.Int Value *big.Int
Gas *big.Int Gas *big.Int
Gasprice *big.Int GasPrice *big.Int
Data []string Data []byte
Init []byte
v byte v byte
r, s []byte r, s []byte
}
func NewTransaction(to []byte, value *big.Int, data []string) *Transaction {
tx := Transaction{Recipient: to, Value: value, Nonce: 0, Data: data}
return &tx
}
func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { // Indicates whether this tx is a contract creation transaction
return &Transaction{Value: value, Gasprice: gasprice, Data: data} contractCreation bool
} }
func NewContractMessageTx(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte, init []byte) *Transaction {
return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, Init: init, contractCreation: true}
} }
func NewTx(to []byte, value *big.Int, data []string) *Transaction { func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction {
return &Transaction{Recipient: to, Value: value, Gasprice: big.NewInt(0), Gas: big.NewInt(0), Nonce: 0, Data: data} return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data}
}
// XXX Deprecated
func NewTransactionFromData(data []byte) *Transaction {
return NewTransactionFromBytes(data)
} }
func NewTransactionFromBytes(data []byte) *Transaction { func NewTransactionFromBytes(data []byte) *Transaction {
...@@ -58,23 +46,21 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { ...@@ -58,23 +46,21 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
} }
func (tx *Transaction) Hash() []byte { func (tx *Transaction) Hash() []byte {
data := make([]interface{}, len(tx.Data)) data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data}
for i, val := range tx.Data {
data[i] = val
}
preEnc := []interface{}{ if tx.contractCreation {
tx.Nonce, data = append(data, tx.Init)
tx.Recipient,
tx.Value,
data,
} }
return ethutil.Sha3Bin(ethutil.Encode(preEnc)) return ethutil.Sha3Bin(ethutil.NewValue(data).Encode())
} }
func (tx *Transaction) IsContract() bool { func (tx *Transaction) IsContract() bool {
return bytes.Compare(tx.Recipient, ContractAddr) == 0 return tx.contractCreation
}
func (tx *Transaction) CreationAddress() []byte {
return tx.Hash()[12:]
} }
func (tx *Transaction) Signature(key []byte) []byte { func (tx *Transaction) Signature(key []byte) []byte {
...@@ -123,17 +109,16 @@ func (tx *Transaction) Sign(privk []byte) error { ...@@ -123,17 +109,16 @@ func (tx *Transaction) Sign(privk []byte) error {
return nil return nil
} }
// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ]
// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ]
func (tx *Transaction) RlpData() interface{} { func (tx *Transaction) RlpData() interface{} {
// Prepare the transaction for serialization data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data}
return []interface{}{
tx.Nonce, if tx.contractCreation {
tx.Recipient, data = append(data, tx.Init)
tx.Value,
ethutil.NewSliceValue(tx.Data).Slice(),
tx.v,
tx.r,
tx.s,
} }
return append(data, tx.v, tx.r, tx.s)
} }
func (tx *Transaction) RlpValue() *ethutil.Value { func (tx *Transaction) RlpValue() *ethutil.Value {
...@@ -150,17 +135,23 @@ func (tx *Transaction) RlpDecode(data []byte) { ...@@ -150,17 +135,23 @@ func (tx *Transaction) RlpDecode(data []byte) {
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
tx.Nonce = decoder.Get(0).Uint() tx.Nonce = decoder.Get(0).Uint()
tx.Recipient = decoder.Get(1).Bytes() tx.Value = decoder.Get(1).BigInt()
tx.Value = decoder.Get(2).BigInt() tx.GasPrice = decoder.Get(2).BigInt()
tx.Gas = decoder.Get(3).BigInt()
d := decoder.Get(3) tx.Recipient = decoder.Get(4).Bytes()
tx.Data = make([]string, d.Len()) tx.Data = decoder.Get(5).Bytes()
for i := 0; i < d.Len(); i++ {
tx.Data[i] = d.Get(i).Str() // If the list is of length 10 it's a contract creation tx
if decoder.Len() == 10 {
tx.contractCreation = true
tx.Init = decoder.Get(6).Bytes()
tx.v = byte(decoder.Get(7).Uint())
tx.r = decoder.Get(8).Bytes()
tx.s = decoder.Get(9).Bytes()
} else {
tx.v = byte(decoder.Get(6).Uint())
tx.r = decoder.Get(7).Bytes()
tx.s = decoder.Get(8).Bytes()
} }
// TODO something going wrong here
tx.v = byte(decoder.Get(4).Uint())
tx.r = decoder.Get(5).Bytes()
tx.s = decoder.Get(6).Bytes()
} }
...@@ -90,7 +90,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { ...@@ -90,7 +90,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) {
// Process transaction validates the Tx and processes funds from the // Process transaction validates the Tx and processes funds from the
// sender to the recipient. // sender to the recipient.
func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) { func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
log.Println(r) log.Println(r)
...@@ -100,19 +100,15 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error ...@@ -100,19 +100,15 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error
// Get the sender // Get the sender
sender := block.state.GetAccount(tx.Sender()) sender := block.state.GetAccount(tx.Sender())
if sender.Nonce != tx.Nonce {
return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce)
}
// Make sure there's enough in the sender's account. Having insufficient // Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it. // funds won't invalidate this transaction but simple ignores it.
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
if sender.Amount.Cmp(totAmount) < 0 { if sender.Amount.Cmp(totAmount) < 0 {
return errors.New("Insufficient amount in sender's account") return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
}
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)
}
} }
// Get the receiver // Get the receiver
...@@ -122,22 +118,21 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error ...@@ -122,22 +118,21 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error
// Send Tx to self // Send Tx to self
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
// Subtract the fee // Subtract the fee
sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat)) sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat))
} else { } else {
// Subtract the amount from the senders account // Subtract the amount from the senders account
sender.Amount.Sub(sender.Amount, totAmount) sender.SubAmount(totAmount)
// Add the amount to receivers account which should conclude this transaction // Add the amount to receivers account which should conclude this transaction
receiver.Amount.Add(receiver.Amount, tx.Value) receiver.AddAmount(tx.Value)
block.state.UpdateAccount(tx.Recipient, receiver) block.state.UpdateStateObject(receiver)
} }
block.state.UpdateAccount(tx.Sender(), sender) block.state.UpdateStateObject(sender)
log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash())
// Notify the subscribers
pool.notifySubscribers(TxPost, tx) pool.notifySubscribers(TxPost, tx)
return return
...@@ -149,18 +144,18 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { ...@@ -149,18 +144,18 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
block := pool.Ethereum.BlockChain().CurrentBlock block := pool.Ethereum.BlockChain().CurrentBlock
// Something has gone horribly wrong if this happens // Something has gone horribly wrong if this happens
if block == nil { if block == nil {
return errors.New("No last block on the block chain") return errors.New("[TXPL] No last block on the block chain")
} }
// Get the sender // Get the sender
accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender())
sender := accountState.Account sender := accountState.Object
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) 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 // Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it. // funds won't invalidate this transaction but simple ignores it.
if sender.Amount.Cmp(totAmount) < 0 { if sender.Amount.Cmp(totAmount) < 0 {
return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender()) return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
} }
// Increment the nonce making each tx valid only once to prevent replay // Increment the nonce making each tx valid only once to prevent replay
...@@ -190,10 +185,12 @@ out: ...@@ -190,10 +185,12 @@ out:
log.Println("Validating Tx failed", err) log.Println("Validating Tx failed", err)
} }
} else { } else {
// Call blocking version. At this point it // Call blocking version.
// doesn't matter since this is a goroutine
pool.addTransaction(tx) pool.addTransaction(tx)
// Notify the subscribers
pool.Ethereum.Reactor().Post("newTx", tx)
// Notify the subscribers // Notify the subscribers
pool.notifySubscribers(TxPre, tx) pool.notifySubscribers(TxPre, tx)
} }
...@@ -207,7 +204,7 @@ func (pool *TxPool) QueueTransaction(tx *Transaction) { ...@@ -207,7 +204,7 @@ func (pool *TxPool) QueueTransaction(tx *Transaction) {
pool.queueChan <- tx pool.queueChan <- tx
} }
func (pool *TxPool) Flush() []*Transaction { func (pool *TxPool) CurrentTransactions() []*Transaction {
pool.mutex.Lock() pool.mutex.Lock()
defer pool.mutex.Unlock() defer pool.mutex.Unlock()
...@@ -221,6 +218,12 @@ func (pool *TxPool) Flush() []*Transaction { ...@@ -221,6 +218,12 @@ func (pool *TxPool) Flush() []*Transaction {
i++ i++
} }
return txList
}
func (pool *TxPool) Flush() []*Transaction {
txList := pool.CurrentTransactions()
// Recreate a new list all together // Recreate a new list all together
// XXX Is this the fastest way? // XXX Is this the fastest way?
pool.pool = list.New() pool.pool = list.New()
......
package ethchain package ethchain
import (
"encoding/hex"
"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())
*/
}
package ethutil package ethchain
import ( type OpCode int
"math/big"
"strconv"
)
// Op codes // Op codes
const (
// 0x0 range - arithmetic ops
oSTOP = 0x00
oADD = 0x01
oMUL = 0x02
oSUB = 0x03
oDIV = 0x04
oSDIV = 0x05
oMOD = 0x06
oSMOD = 0x07
oEXP = 0x08
oNEG = 0x09
oLT = 0x0a
oGT = 0x0b
oEQ = 0x0c
oNOT = 0x0d
// 0x10 range - bit ops
oAND = 0x10
oOR = 0x11
oXOR = 0x12
oBYTE = 0x13
// 0x20 range - crypto
oSHA3 = 0x20
// 0x30 range - closure state
oADDRESS = 0x30
oBALANCE = 0x31
oORIGIN = 0x32
oCALLER = 0x33
oCALLVALUE = 0x34
oCALLDATALOAD = 0x35
oCALLDATASIZE = 0x36
oGASPRICE = 0x37
// 0x40 range - block operations
oPREVHASH = 0x40
oCOINBASE = 0x41
oTIMESTAMP = 0x42
oNUMBER = 0x43
oDIFFICULTY = 0x44
oGASLIMIT = 0x45
// 0x50 range - 'storage' and execution
oPUSH = 0x50
oPUSH20 = 0x80
oPOP = 0x51
oDUP = 0x52
oSWAP = 0x53
oMLOAD = 0x54
oMSTORE = 0x55
oMSTORE8 = 0x56
oSLOAD = 0x57
oSSTORE = 0x58
oJUMP = 0x59
oJUMPI = 0x5a
oPC = 0x5b
oMSIZE = 0x5c
// 0x60 range - closures
oCREATE = 0x60
oCALL = 0x61
oRETURN = 0x62
// 0x70 range - other
oLOG = 0x70 // XXX Unofficial
oSUICIDE = 0x7f
)
// Since the opcodes aren't all in order we can't use a regular slice
var opCodeToString = map[OpCode]string{
// 0x0 range - arithmetic ops
oSTOP: "STOP",
oADD: "ADD",
oMUL: "MUL",
oSUB: "SUB",
oDIV: "DIV",
oSDIV: "SDIV",
oMOD: "MOD",
oSMOD: "SMOD",
oEXP: "EXP",
oNEG: "NEG",
oLT: "LT",
oGT: "GT",
oEQ: "EQ",
oNOT: "NOT",
// 0x10 range - bit ops
oAND: "AND",
oOR: "OR",
oXOR: "XOR",
oBYTE: "BYTE",
// 0x20 range - crypto
oSHA3: "SHA3",
// 0x30 range - closure state
oADDRESS: "ADDRESS",
oBALANCE: "BALANCE",
oORIGIN: "ORIGIN",
oCALLER: "CALLER",
oCALLVALUE: "CALLVALUE",
oCALLDATALOAD: "CALLDATALOAD",
oCALLDATASIZE: "CALLDATASIZE",
oGASPRICE: "TXGASPRICE",
// 0x40 range - block operations
oPREVHASH: "PREVHASH",
oCOINBASE: "COINBASE",
oTIMESTAMP: "TIMESTAMP",
oNUMBER: "NUMBER",
oDIFFICULTY: "DIFFICULTY",
oGASLIMIT: "GASLIMIT",
// 0x50 range - 'storage' and execution
oPUSH: "PUSH",
oPOP: "POP",
oDUP: "DUP",
oSWAP: "SWAP",
oMLOAD: "MLOAD",
oMSTORE: "MSTORE",
oMSTORE8: "MSTORE8",
oSLOAD: "SLOAD",
oSSTORE: "SSTORE",
oJUMP: "JUMP",
oJUMPI: "JUMPI",
oPC: "PC",
oMSIZE: "MSIZE",
// 0x60 range - closures
oCREATE: "CREATE",
oCALL: "CALL",
oRETURN: "RETURN",
// 0x70 range - other
oLOG: "LOG",
oSUICIDE: "SUICIDE",
}
func (o OpCode) String() string {
return opCodeToString[o]
}
// Op codes for assembling
var OpCodes = map[string]byte{ var OpCodes = map[string]byte{
// 0x0 range - arithmetic ops // 0x0 range - arithmetic ops
"STOP": 0x00, "STOP": 0x00,
...@@ -38,7 +180,7 @@ var OpCodes = map[string]byte{ ...@@ -38,7 +180,7 @@ var OpCodes = map[string]byte{
"ORIGIN": 0x32, "ORIGIN": 0x32,
"CALLER": 0x33, "CALLER": 0x33,
"CALLVALUE": 0x34, "CALLVALUE": 0x34,
"CALLDATA": 0x35, "CALLDATALOAD": 0x35,
"CALLDATASIZE": 0x36, "CALLDATASIZE": 0x36,
"GASPRICE": 0x38, "GASPRICE": 0x38,
...@@ -51,7 +193,10 @@ var OpCodes = map[string]byte{ ...@@ -51,7 +193,10 @@ var OpCodes = map[string]byte{
"GASLIMIT": 0x45, "GASLIMIT": 0x45,
// 0x50 range - 'storage' and execution // 0x50 range - 'storage' and execution
"PUSH": 0x50, "PUSH": 0x50,
"PUSH20": 0x80,
"POP": 0x51, "POP": 0x51,
"DUP": 0x52, "DUP": 0x52,
"SWAP": 0x53, "SWAP": 0x53,
...@@ -83,62 +228,3 @@ func IsOpCode(s string) bool { ...@@ -83,62 +228,3 @@ func IsOpCode(s string) bool {
} }
return false return false
} }
func CompileInstr(s interface{}) ([]byte, error) {
switch s.(type) {
case string:
str := s.(string)
isOp := IsOpCode(str)
if isOp {
return []byte{OpCodes[str]}, nil
}
num := new(big.Int)
_, success := num.SetString(str, 0)
// Assume regular bytes during compilation
if !success {
num.SetBytes([]byte(str))
}
return num.Bytes(), nil
case int:
return big.NewInt(int64(s.(int))).Bytes(), nil
case []byte:
return BigD(s.([]byte)).Bytes(), nil
}
return nil, nil
}
func Instr(instr string) (int, []string, error) {
base := new(big.Int)
base.SetString(instr, 0)
args := make([]string, 7)
for i := 0; i < 7; i++ {
// int(int(val) / int(math.Pow(256,float64(i)))) % 256
exp := BigPow(256, i)
num := new(big.Int)
num.Div(base, exp)
args[i] = num.Mod(num, big.NewInt(256)).String()
}
op, _ := strconv.Atoi(args[0])
return op, args[1:7], nil
}
// Script compilation functions
// Compiles strings to machine code
func Compile(instructions ...interface{}) (script []string) {
script = make([]string, len(instructions))
for i, val := range instructions {
instr, _ := CompileInstr(val)
script[i] = string(instr)
}
return
}
This diff is collapsed.
package ethchain package ethchain
import ( import (
"bytes" _ "bytes"
"fmt"
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/mutan"
"math/big" "math/big"
"strings"
"testing" "testing"
) )
/* /*
func TestRun(t *testing.T) {
InitFees()
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script := Compile([]string{
"TXSENDER",
"SUICIDE",
})
tx := NewTransaction(ContractAddr, big.NewInt(1e17), script)
fmt.Printf("contract addr %x\n", tx.Hash()[12:])
contract := MakeContract(tx, state)
vm := &Vm{}
vm.Process(contract, state, RuntimeVars{
address: tx.Hash()[12:],
blockNumber: 1,
sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"),
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
txValue: tx.Value,
txData: tx.Data,
})
}
func TestRun1(t *testing.T) {
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script := Compile([]string{
"PUSH", "0",
"PUSH", "0",
"TXSENDER",
"PUSH", "10000000",
"MKTX",
})
fmt.Println(ethutil.NewValue(script))
tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script)
fmt.Printf("contract addr %x\n", tx.Hash()[12:])
contract := MakeContract(tx, state)
vm := &Vm{}
vm.Process(contract, state, RuntimeVars{
address: tx.Hash()[12:],
blockNumber: 1,
sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"),
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
txValue: tx.Value,
txData: tx.Data,
})
}
func TestRun2(t *testing.T) {
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script := Compile([]string{
"PUSH", "0",
"PUSH", "0",
"TXSENDER",
"PUSH", "10000000",
"MKTX",
})
fmt.Println(ethutil.NewValue(script))
tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script)
fmt.Printf("contract addr %x\n", tx.Hash()[12:])
contract := MakeContract(tx, state)
vm := &Vm{}
vm.Process(contract, state, RuntimeVars{
address: tx.Hash()[12:],
blockNumber: 1,
sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"),
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
txValue: tx.Value,
txData: tx.Data,
})
}
*/
// XXX Full stack test
func TestRun3(t *testing.T) { func TestRun3(t *testing.T) {
ethutil.ReadConfig("") ethutil.ReadConfig("")
...@@ -127,12 +30,12 @@ func TestRun3(t *testing.T) { ...@@ -127,12 +30,12 @@ func TestRun3(t *testing.T) {
"PUSH", "0", "PUSH", "0",
"RETURN", "RETURN",
}) })
tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script)
addr := tx.Hash()[12:] addr := tx.Hash()[12:]
contract := MakeContract(tx, state) contract := MakeContract(tx, state)
state.UpdateContract(contract) state.UpdateContract(contract)
callerScript := ethutil.Compile( callerScript := ethutil.Assemble(
"PUSH", 1337, // Argument "PUSH", 1337, // Argument
"PUSH", 65, // argument mem offset "PUSH", 65, // argument mem offset
"MSTORE", "MSTORE",
...@@ -149,7 +52,7 @@ func TestRun3(t *testing.T) { ...@@ -149,7 +52,7 @@ func TestRun3(t *testing.T) {
"PUSH", 0, "PUSH", 0,
"RETURN", "RETURN",
) )
callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript)
// Contract addr as test address // Contract addr as test address
account := NewAccount(ContractAddr, big.NewInt(10000000)) account := NewAccount(ContractAddr, big.NewInt(10000000))
...@@ -171,4 +74,87 @@ func TestRun3(t *testing.T) { ...@@ -171,4 +74,87 @@ func TestRun3(t *testing.T) {
if bytes.Compare(ret, exp) != 0 { if bytes.Compare(ret, exp) != 0 {
t.Errorf("expected return value to be %v, got %v", exp, ret) t.Errorf("expected return value to be %v, got %v", exp, ret)
} }
}*/
func TestRun4(t *testing.T) {
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script, err := mutan.Compile(strings.NewReader(`
int32 a = 10
int32 b = 20
if a > b {
int32 c = this.Caller()
}
Exit()
`), false)
tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil)
addr := tx.Hash()[12:]
contract := MakeContract(tx, state)
state.UpdateStateObject(contract)
fmt.Printf("%x\n", addr)
callerScript, err := mutan.Compile(strings.NewReader(`
// Check if there's any cash in the initial store
if store[1000] == 0 {
store[1000] = 10^20
}
store[1001] = this.Value() * 20
store[this.Origin()] = store[this.Origin()] + 1000
if store[1001] > 20 {
store[1001] = 10^50
}
int8 ret = 0
int8 arg = 10
Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret)
big t
for int8 i = 0; i < 10; i++ {
t = i
}
if 10 > 20 {
int8 shouldnt = 2
} else {
int8 should = 1
}
`), false)
if err != nil {
fmt.Println(err)
}
callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil)
// Contract addr as test address
gas := big.NewInt(1000)
gasPrice := big.NewInt(10)
account := NewAccount(ContractAddr, big.NewInt(10000000))
fmt.Println("account.Amount =", account.Amount)
c := MakeContract(callerTx, state)
e := account.ConvertGas(gas, gasPrice)
if e != nil {
fmt.Println(err)
}
fmt.Println("account.Amount =", account.Amount)
callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0))
vm := NewVm(state, nil, RuntimeVars{
Origin: account.Address(),
BlockNumber: 1,
PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
Time: 1,
Diff: big.NewInt(256),
})
_, e = callerClosure.Call(vm, nil, nil)
if e != nil {
fmt.Println("error", e)
}
fmt.Println("account.Amount =", account.Amount)
} }
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"container/list" "container/list"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethrpc"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire" "github.com/ethereum/eth-go/ethwire"
"io/ioutil" "io/ioutil"
...@@ -60,6 +61,10 @@ type Ethereum struct { ...@@ -60,6 +61,10 @@ type Ethereum struct {
// Specifies the desired amount of maximum peers // Specifies the desired amount of maximum peers
MaxPeers int MaxPeers int
reactor *ethutil.ReactorEngine
RpcServer *ethrpc.JsonRpcServer
} }
func New(caps Caps, usePnp bool) (*Ethereum, error) { func New(caps Caps, usePnp bool) (*Ethereum, error) {
...@@ -89,6 +94,8 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { ...@@ -89,6 +94,8 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) {
serverCaps: caps, serverCaps: caps,
nat: nat, nat: nat,
} }
ethereum.reactor = ethutil.NewReactorEngine()
ethereum.txPool = ethchain.NewTxPool(ethereum) ethereum.txPool = ethchain.NewTxPool(ethereum)
ethereum.blockChain = ethchain.NewBlockChain(ethereum) ethereum.blockChain = ethchain.NewBlockChain(ethereum)
ethereum.stateManager = ethchain.NewStateManager(ethereum) ethereum.stateManager = ethchain.NewStateManager(ethereum)
...@@ -99,6 +106,10 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { ...@@ -99,6 +106,10 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) {
return ethereum, nil return ethereum, nil
} }
func (s *Ethereum) Reactor() *ethutil.ReactorEngine {
return s.reactor
}
func (s *Ethereum) BlockChain() *ethchain.BlockChain { func (s *Ethereum) BlockChain() *ethchain.BlockChain {
return s.blockChain return s.blockChain
} }
...@@ -328,6 +339,7 @@ func (s *Ethereum) Stop() { ...@@ -328,6 +339,7 @@ func (s *Ethereum) Stop() {
close(s.quit) close(s.quit)
s.RpcServer.Stop()
s.txPool.Stop() s.txPool.Stop()
s.stateManager.Stop() s.stateManager.Stop()
...@@ -342,7 +354,7 @@ func (s *Ethereum) WaitForShutdown() { ...@@ -342,7 +354,7 @@ func (s *Ethereum) WaitForShutdown() {
func (s *Ethereum) upnpUpdateThread() { func (s *Ethereum) upnpUpdateThread() {
// Go off immediately to prevent code duplication, thereafter we renew // Go off immediately to prevent code duplication, thereafter we renew
// lease every 15 minutes. // lease every 15 minutes.
timer := time.NewTimer(0 * time.Second) timer := time.NewTimer(5 * time.Minute)
lport, _ := strconv.ParseInt(s.Port, 10, 16) lport, _ := strconv.ParseInt(s.Port, 10, 16)
first := true first := true
out: out:
......
package ethminer
import (
"bytes"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"log"
)
type Miner struct {
pow ethchain.PoW
ethereum ethchain.EthManager
coinbase []byte
reactChan chan ethutil.React
txs []*ethchain.Transaction
uncles []*ethchain.Block
block *ethchain.Block
powChan chan []byte
quitChan chan ethutil.React
}
func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread
ethereum.Reactor().Subscribe("newBlock", reactChan)
ethereum.Reactor().Subscribe("newTx", reactChan)
// We need the quit chan to be a Reactor event.
// The POW search method is actually blocking and if we don't
// listen to the reactor events inside of the pow itself
// The miner overseer will never get the reactor events themselves
// Only after the miner will find the sha
ethereum.Reactor().Subscribe("newBlock", quitChan)
ethereum.Reactor().Subscribe("newTx", quitChan)
miner := Miner{
pow: &ethchain.EasyPow{},
ethereum: ethereum,
coinbase: coinbase,
reactChan: reactChan,
powChan: powChan,
quitChan: quitChan,
}
// Insert initial TXs in our little miner 'pool'
miner.txs = ethereum.TxPool().Flush()
miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
return miner
}
func (miner *Miner) Start() {
// Prepare inital block
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
go func() { miner.listener() }()
}
func (miner *Miner) listener() {
for {
select {
case chanMessage := <-miner.reactChan:
if block, ok := chanMessage.Resource.(*ethchain.Block); ok {
log.Println("[MINER] Got new block via Reactor")
if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 {
// TODO: Perhaps continue mining to get some uncle rewards
log.Println("[MINER] New top block found resetting state")
// Filter out which Transactions we have that were not in this block
var newtxs []*ethchain.Transaction
for _, tx := range miner.txs {
found := false
for _, othertx := range block.Transactions() {
if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 {
found = true
}
}
if found == false {
newtxs = append(newtxs, tx)
}
}
miner.txs = newtxs
// Setup a fresh state to mine on
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
} else {
if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
log.Println("[MINER] Adding uncle block")
miner.uncles = append(miner.uncles, block)
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
}
}
}
if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok {
//log.Println("[MINER] Got new transaction from Reactor", tx)
found := false
for _, ctx := range miner.txs {
if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found {
break
}
}
if found == false {
//log.Println("[MINER] We did not know about this transaction, adding")
miner.txs = append(miner.txs, tx)
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
miner.block.SetTransactions(miner.txs)
} else {
//log.Println("[MINER] We already had this transaction, ignoring")
}
}
default:
log.Println("[MINER] Mining on block. Includes", len(miner.txs), "transactions")
// Apply uncles
if len(miner.uncles) > 0 {
miner.block.SetUncles(miner.uncles)
}
// FIXME @ maranh, first block doesn't need this. Everything after the first block does.
// Please check and fix
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
// Apply all transactions to the block
miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions())
miner.ethereum.StateManager().AccumelateRewards(miner.block)
// Search the nonce
//log.Println("[MINER] Initialision complete, starting mining")
miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan)
if miner.block.Nonce != nil {
miner.ethereum.StateManager().PrepareDefault(miner.block)
err := miner.ethereum.StateManager().ProcessBlock(miner.block, true)
if err != nil {
log.Println(err)
miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
} else {
/*
// XXX @maranh This is already done in the state manager, why a 2nd time?
if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) {
log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce))
}
*/
miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val})
log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash())
miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
}
}
}
}
}
package ethpub
import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
)
type PEthereum struct {
stateManager *ethchain.StateManager
blockChain *ethchain.BlockChain
txPool *ethchain.TxPool
}
func NewPEthereum(sm *ethchain.StateManager, bc *ethchain.BlockChain, txp *ethchain.TxPool) *PEthereum {
return &PEthereum{
sm,
bc,
txp,
}
}
func (lib *PEthereum) GetBlock(hexHash string) *PBlock {
hash := ethutil.FromHex(hexHash)
block := lib.blockChain.GetBlock(hash)
var blockInfo *PBlock
if block != nil {
blockInfo = &PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())}
} else {
blockInfo = &PBlock{Number: -1, Hash: ""}
}
return blockInfo
}
func (lib *PEthereum) GetKey() *PKey {
keyPair, err := ethchain.NewKeyPairFromSec(ethutil.Config.Db.GetKeys()[0].PrivateKey)
if err != nil {
return nil
}
return NewPKey(keyPair)
}
func (lib *PEthereum) GetStateObject(address string) *PStateObject {
stateObject := lib.stateManager.ProcState().GetContract(ethutil.FromHex(address))
if stateObject != nil {
return NewPStateObject(stateObject)
}
// See GetStorage for explanation on "nil"
return NewPStateObject(nil)
}
func (lib *PEthereum) GetStorage(address, storageAddress string) string {
return lib.GetStateObject(address).GetStorage(storageAddress)
}
func (lib *PEthereum) GetTxCount(address string) int {
return lib.GetStateObject(address).Nonce()
}
func (lib *PEthereum) IsContract(address string) bool {
return lib.GetStateObject(address).IsContract()
}
func (lib *PEthereum) SecretToAddress(key string) string {
pair, err := ethchain.NewKeyPairFromSec(ethutil.FromHex(key))
if err != nil {
return ""
}
return ethutil.Hex(pair.Address())
}
func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) {
return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr, "")
}
func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, initStr, bodyStr string) (*PReceipt, error) {
return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, initStr, bodyStr)
}
func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, initStr, scriptStr string) (*PReceipt, error) {
var hash []byte
var contractCreation bool
if len(recipient) == 0 {
contractCreation = true
} else {
hash = ethutil.FromHex(recipient)
}
keyPair, err := ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key)))
if err != nil {
return nil, err
}
value := ethutil.Big(valueStr)
gas := ethutil.Big(gasStr)
gasPrice := ethutil.Big(gasPriceStr)
var tx *ethchain.Transaction
// Compile and assemble the given data
if contractCreation {
var initScript, mainScript []byte
var err error
if ethutil.IsHex(initStr) {
initScript = ethutil.FromHex(initStr[2:])
} else {
initScript, err = ethutil.Compile(initStr)
if err != nil {
return nil, err
}
}
if ethutil.IsHex(scriptStr) {
mainScript = ethutil.FromHex(scriptStr[2:])
} else {
mainScript, err = ethutil.Compile(scriptStr)
if err != nil {
return nil, err
}
}
tx = ethchain.NewContractCreationTx(value, gas, gasPrice, mainScript, initScript)
} else {
// Just in case it was submitted as a 0x prefixed string
if len(initStr) > 0 && initStr[0:2] == "0x" {
initStr = initStr[2:len(initStr)]
}
tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr))
}
acc := lib.stateManager.GetAddrState(keyPair.Address())
tx.Nonce = acc.Nonce
tx.Sign(keyPair.PrivateKey)
lib.txPool.QueueTransaction(tx)
if contractCreation {
ethutil.Config.Log.Infof("Contract addr %x", tx.CreationAddress())
} else {
ethutil.Config.Log.Infof("Tx hash %x", tx.Hash())
}
return NewPReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil
}
package ethpub
import (
"encoding/hex"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
)
// Block interface exposed to QML
type PBlock struct {
Number int `json:"number"`
Hash string `json:"hash"`
}
// Creates a new QML Block from a chain block
func NewPBlock(block *ethchain.Block) *PBlock {
info := block.BlockInfo()
hash := hex.EncodeToString(block.Hash())
return &PBlock{Number: int(info.Number), Hash: hash}
}
type PTx struct {
Value, Hash, Address string
Contract bool
}
func NewPTx(tx *ethchain.Transaction) *PTx {
hash := hex.EncodeToString(tx.Hash())
sender := hex.EncodeToString(tx.Recipient)
isContract := len(tx.Data) > 0
return &PTx{Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender, Contract: isContract}
}
type PKey struct {
Address string `json:"address"`
PrivateKey string `json:"privateKey"`
PublicKey string `json:"publicKey"`
}
func NewPKey(key *ethchain.KeyPair) *PKey {
return &PKey{ethutil.Hex(key.Address()), ethutil.Hex(key.PrivateKey), ethutil.Hex(key.PublicKey)}
}
type PReceipt struct {
CreatedContract bool `json:"createdContract"`
Address string `json:"address"`
Hash string `json:"hash"`
Sender string `json:"sender"`
}
func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt {
return &PReceipt{
contractCreation,
ethutil.Hex(creationAddress),
ethutil.Hex(hash),
ethutil.Hex(address),
}
}
type PStateObject struct {
object *ethchain.StateObject
}
func NewPStateObject(object *ethchain.StateObject) *PStateObject {
return &PStateObject{object: object}
}
func (c *PStateObject) GetStorage(address string) string {
// Because somehow, even if you return nil to QML it
// still has some magical object so we can't rely on
// undefined or null at the QML side
if c.object != nil {
val := c.object.GetMem(ethutil.Big("0x" + address))
return val.BigInt().String()
}
return ""
}
func (c *PStateObject) Value() string {
if c.object != nil {
return c.object.Amount.String()
}
return ""
}
func (c *PStateObject) Address() string {
if c.object != nil {
return ethutil.Hex(c.object.Address())
}
return ""
}
func (c *PStateObject) Nonce() int {
if c.object != nil {
return int(c.object.Nonce)
}
return 0
}
func (c *PStateObject) IsContract() bool {
if c.object != nil {
return len(c.object.Script()) > 0
}
return false
}
type PStorageState struct {
StateAddress string
Address string
Value string
}
func NewPStorageState(storageObject *ethchain.StorageState) *PStorageState {
return &PStorageState{ethutil.Hex(storageObject.StateAddress), ethutil.Hex(storageObject.Address), storageObject.Value.String()}
}
package ethrpc
import (
"encoding/json"
"errors"
"github.com/ethereum/eth-go/ethpub"
_ "log"
)
type EthereumApi struct {
ethp *ethpub.PEthereum
}
type JsonArgs interface {
requirements() error
}
type BlockResponse struct {
JsonResponse
}
type GetBlockArgs struct {
BlockNumber int
Hash string
}
type ErrorResponse struct {
Error bool `json:"error"`
ErrorText string `json:"errorText"`
}
type JsonResponse interface {
}
type SuccessRes struct {
Error bool `json:"error"`
Result JsonResponse `json:"result"`
}
func NewSuccessRes(object JsonResponse) string {
e := SuccessRes{Error: false, Result: object}
res, err := json.Marshal(e)
if err != nil {
// This should never happen
panic("Creating json error response failed, help")
}
success := string(res)
return success
}
func NewErrorResponse(msg string) error {
e := ErrorResponse{Error: true, ErrorText: msg}
res, err := json.Marshal(e)
if err != nil {
// This should never happen
panic("Creating json error response failed, help")
}
newErr := errors.New(string(res))
return newErr
}
func (b *GetBlockArgs) requirements() error {
if b.BlockNumber == 0 && b.Hash == "" {
return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument")
}
return nil
}
func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *string) error {
err := args.requirements()
if err != nil {
return err
}
// Do something
block := p.ethp.GetBlock(args.Hash)
*reply = NewSuccessRes(block)
return nil
}
type NewTxArgs struct {
Sec string
Recipient string
Value string
Gas string
GasPrice string
Init string
Body string
}
type TxResponse struct {
Hash string
}
func (a *NewTxArgs) requirements() error {
if a.Recipient == "" {
return NewErrorResponse("Transact requires a 'recipient' address as argument")
}
if a.Value == "" {
return NewErrorResponse("Transact requires a 'value' as argument")
}
if a.Gas == "" {
return NewErrorResponse("Transact requires a 'gas' value as argument")
}
if a.GasPrice == "" {
return NewErrorResponse("Transact requires a 'gasprice' value as argument")
}
return nil
}
func (a *NewTxArgs) requirementsContract() error {
if a.Value == "" {
return NewErrorResponse("Create requires a 'value' as argument")
}
if a.Gas == "" {
return NewErrorResponse("Create requires a 'gas' value as argument")
}
if a.GasPrice == "" {
return NewErrorResponse("Create requires a 'gasprice' value as argument")
}
if a.Body == "" {
return NewErrorResponse("Create requires a 'body' value as argument")
}
return nil
}
func (p *EthereumApi) Transact(args *NewTxArgs, reply *string) error {
err := args.requirements()
if err != nil {
return err
}
result, _ := p.ethp.Transact(p.ethp.GetKey().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body)
*reply = NewSuccessRes(result)
return nil
}
func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error {
err := args.requirementsContract()
if err != nil {
return err
}
result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Init, args.Body)
*reply = NewSuccessRes(result)
return nil
}
func (p *EthereumApi) GetKey(args interface{}, reply *string) error {
*reply = NewSuccessRes(p.ethp.GetKey())
return nil
}
type GetStorageArgs struct {
Address string
Key string
}
func (a *GetStorageArgs) requirements() error {
if a.Address == "" {
return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
}
if a.Key == "" {
return NewErrorResponse("GetStorageAt requires an 'key' value as argument")
}
return nil
}
type GetStorageAtRes struct {
Key string `json:"key"`
Value string `json:"value"`
Address string `json:"address"`
}
func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error {
err := args.requirements()
if err != nil {
return err
}
state := p.ethp.GetStateObject(args.Address)
value := state.GetStorage(args.Key)
*reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value})
return nil
}
type GetBalanceArgs struct {
Address string
}
func (a *GetBalanceArgs) requirements() error {
if a.Address == "" {
return NewErrorResponse("GetBalanceAt requires an 'address' value as argument")
}
return nil
}
type BalanceRes struct {
Balance string `json:"balance"`
Address string `json:"address"`
}
func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *string) error {
err := args.requirements()
if err != nil {
return err
}
state := p.ethp.GetStateObject(args.Address)
*reply = NewSuccessRes(BalanceRes{Balance: state.Value(), Address: args.Address})
return nil
}
type TestRes struct {
JsonResponse `json:"-"`
Answer int `json:"answer"`
}
func (p *EthereumApi) Test(args *GetBlockArgs, reply *string) error {
*reply = NewSuccessRes(TestRes{Answer: 15})
return nil
}
package ethrpc
import (
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
type JsonRpcServer struct {
quit chan bool
listener net.Listener
ethp *ethpub.PEthereum
}
func (s *JsonRpcServer) exitHandler() {
out:
for {
select {
case <-s.quit:
s.listener.Close()
break out
}
}
ethutil.Config.Log.Infoln("[JSON] Shutdown JSON-RPC server")
}
func (s *JsonRpcServer) Stop() {
close(s.quit)
}
func (s *JsonRpcServer) Start() {
ethutil.Config.Log.Infoln("[JSON] Starting JSON-RPC server")
go s.exitHandler()
rpc.Register(&EthereumApi{ethp: s.ethp})
rpc.HandleHTTP()
for {
conn, err := s.listener.Accept()
if err != nil {
ethutil.Config.Log.Infoln("[JSON] Error starting JSON-RPC:", err)
break
}
ethutil.Config.Log.Debugln("[JSON] Incoming request.")
go jsonrpc.ServeConn(conn)
}
}
func NewJsonRpcServer(ethp *ethpub.PEthereum) *JsonRpcServer {
l, err := net.Listen("tcp", ":30304")
if err != nil {
ethutil.Config.Log.Infoln("Error starting JSON-RPC")
}
return &JsonRpcServer{
listener: l,
quit: make(chan bool),
ethp: ethp,
}
}
...@@ -12,7 +12,9 @@ var BigTrue *big.Int = big.NewInt(1) ...@@ -12,7 +12,9 @@ var BigTrue *big.Int = big.NewInt(1)
// False // False
var BigFalse *big.Int = big.NewInt(0) var BigFalse *big.Int = big.NewInt(0)
// Returns the power of two integers // Big pow
//
// Returns the power of two big integers
func BigPow(a, b int) *big.Int { func BigPow(a, b int) *big.Int {
c := new(big.Int) c := new(big.Int)
c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0)) c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0))
...@@ -20,7 +22,9 @@ func BigPow(a, b int) *big.Int { ...@@ -20,7 +22,9 @@ func BigPow(a, b int) *big.Int {
return c return c
} }
// Like big.NewInt(uint64); this takes a string instead. // Big
//
// Shortcut for new(big.Int).SetString(..., 0)
func Big(num string) *big.Int { func Big(num string) *big.Int {
n := new(big.Int) n := new(big.Int)
n.SetString(num, 0) n.SetString(num, 0)
...@@ -28,7 +32,9 @@ func Big(num string) *big.Int { ...@@ -28,7 +32,9 @@ func Big(num string) *big.Int {
return n return n
} }
// Like big.NewInt(uint64); this takes a byte buffer instead. // BigD
//
// Shortcut for new(big.Int).SetBytes(...)
func BigD(data []byte) *big.Int { func BigD(data []byte) *big.Int {
n := new(big.Int) n := new(big.Int)
n.SetBytes(data) n.SetBytes(data)
...@@ -36,17 +42,30 @@ func BigD(data []byte) *big.Int { ...@@ -36,17 +42,30 @@ func BigD(data []byte) *big.Int {
return n return n
} }
// Big to bytes
//
// Returns the bytes of a big integer with the size specified by **base**
// Attempts to pad the byte array with zeros.
func BigToBytes(num *big.Int, base int) []byte { func BigToBytes(num *big.Int, base int) []byte {
ret := make([]byte, base/8) ret := make([]byte, base/8)
return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...)
} }
// Functions like the build in "copy" function // Big copy
// but works on big integers //
func BigCopy(src *big.Int) (ret *big.Int) { // Creates a copy of the given big integer
ret = new(big.Int) func BigCopy(src *big.Int) *big.Int {
ret.Add(ret, src) return new(big.Int).Set(src)
}
// Big max
//
// Returns the maximum size big integer
func BigMax(x, y *big.Int) *big.Int {
if x.Cmp(y) <= 0 {
return x
}
return return y
} }
...@@ -6,6 +6,9 @@ import ( ...@@ -6,6 +6,9 @@ import (
"fmt" "fmt"
) )
// Number to bytes
//
// Returns the number in bytes with the specified base
func NumberToBytes(num interface{}, bits int) []byte { func NumberToBytes(num interface{}, bits int) []byte {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := binary.Write(buf, binary.BigEndian, num) err := binary.Write(buf, binary.BigEndian, num)
...@@ -16,6 +19,9 @@ func NumberToBytes(num interface{}, bits int) []byte { ...@@ -16,6 +19,9 @@ func NumberToBytes(num interface{}, bits int) []byte {
return buf.Bytes()[buf.Len()-(bits/8):] return buf.Bytes()[buf.Len()-(bits/8):]
} }
// Bytes to number
//
// Attempts to cast a byte slice to a unsigned integer
func BytesToNumber(b []byte) uint64 { func BytesToNumber(b []byte) uint64 {
var number uint64 var number uint64
...@@ -32,7 +38,9 @@ func BytesToNumber(b []byte) uint64 { ...@@ -32,7 +38,9 @@ func BytesToNumber(b []byte) uint64 {
return number return number
} }
// Read variable integer in big endian // Read variable int
//
// Read a variable length number in big endian byte order
func ReadVarint(reader *bytes.Reader) (ret uint64) { func ReadVarint(reader *bytes.Reader) (ret uint64) {
if reader.Len() == 8 { if reader.Len() == 8 {
var num uint64 var num uint64
...@@ -55,6 +63,9 @@ func ReadVarint(reader *bytes.Reader) (ret uint64) { ...@@ -55,6 +63,9 @@ func ReadVarint(reader *bytes.Reader) (ret uint64) {
return ret return ret
} }
// Binary length
//
// Returns the true binary length of the given number
func BinaryLength(num int) int { func BinaryLength(num int) int {
if num == 0 { if num == 0 {
return 0 return 0
...@@ -62,3 +73,18 @@ func BinaryLength(num int) int { ...@@ -62,3 +73,18 @@ func BinaryLength(num int) int {
return 1 + BinaryLength(num>>8) return 1 + BinaryLength(num>>8)
} }
// Copy bytes
//
// Returns an exact copy of the provided bytes
func CopyBytes(b []byte) (copiedBytes []byte) {
copiedBytes = make([]byte, len(b))
copy(copiedBytes, b)
return
}
func IsHex(str string) bool {
l := len(str)
return l >= 4 && l%2 == 0 && str[0:2] == "0x"
}
...@@ -5,16 +5,20 @@ import ( ...@@ -5,16 +5,20 @@ import (
"math/big" "math/big"
) )
// The different number of units
var ( var (
Ether = BigPow(10, 18) Ether = BigPow(10, 18)
Finney = BigPow(10, 15) Finney = BigPow(10, 15)
Szabo = BigPow(10, 12) Szabo = BigPow(10, 12)
Vito = BigPow(10, 9) Vita = BigPow(10, 9)
Turing = BigPow(10, 6) Turing = BigPow(10, 6)
Eins = BigPow(10, 3) Eins = BigPow(10, 3)
Wei = big.NewInt(1) Wei = big.NewInt(1)
) )
// Currency to string
//
// Returns a string representing a human readable format
func CurrencyToString(num *big.Int) string { func CurrencyToString(num *big.Int) string {
switch { switch {
case num.Cmp(Ether) >= 0: case num.Cmp(Ether) >= 0:
...@@ -23,8 +27,8 @@ func CurrencyToString(num *big.Int) string { ...@@ -23,8 +27,8 @@ func CurrencyToString(num *big.Int) string {
return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney))
case num.Cmp(Szabo) >= 0: case num.Cmp(Szabo) >= 0:
return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo))
case num.Cmp(Vito) >= 0: case num.Cmp(Vita) >= 0:
return fmt.Sprintf("%v Vito", new(big.Int).Div(num, Vito)) return fmt.Sprintf("%v Vita", new(big.Int).Div(num, Vita))
case num.Cmp(Turing) >= 0: case num.Cmp(Turing) >= 0:
return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing)) return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing))
case num.Cmp(Eins) >= 0: case num.Cmp(Eins) >= 0:
...@@ -34,8 +38,18 @@ func CurrencyToString(num *big.Int) string { ...@@ -34,8 +38,18 @@ func CurrencyToString(num *big.Int) string {
return fmt.Sprintf("%v Wei", num) return fmt.Sprintf("%v Wei", num)
} }
// Common big integers often used
var ( var (
Big1 = big.NewInt(1) Big1 = big.NewInt(1)
Big2 = big.NewInt(1)
Big0 = big.NewInt(0) Big0 = big.NewInt(0)
Big32 = big.NewInt(32)
Big256 = big.NewInt(0xff) Big256 = big.NewInt(0xff)
) )
// Creates an ethereum address given the bytes and the nonce
func CreateAddress(b []byte, nonce *big.Int) []byte {
addrBytes := append(b, nonce.Bytes()...)
return Sha3Bin(addrBytes)[12:]
}
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"runtime" "runtime"
) )
// Log types available
type LogType byte type LogType byte
const ( const (
...@@ -16,7 +17,7 @@ const ( ...@@ -16,7 +17,7 @@ const (
LogTypeFile = 2 LogTypeFile = 2
) )
// Config struct isn't exposed // Config struct
type config struct { type config struct {
Db Database Db Database
...@@ -31,7 +32,9 @@ type config struct { ...@@ -31,7 +32,9 @@ type config struct {
var Config *config var Config *config
// Read config doesn't read anything yet. // Read config
//
// Initialize the global Config variable with default settings
func ReadConfig(base string) *config { func ReadConfig(base string) *config {
if Config == nil { if Config == nil {
usr, _ := user.Current() usr, _ := user.Current()
...@@ -48,7 +51,7 @@ func ReadConfig(base string) *config { ...@@ -48,7 +51,7 @@ func ReadConfig(base string) *config {
} }
} }
Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} Config = &config{ExecPath: path, Debug: true, Ver: "0.5 RC1"}
Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug)
Config.SetClientString("/Ethereum(G)") Config.SetClientString("/Ethereum(G)")
} }
...@@ -56,6 +59,8 @@ func ReadConfig(base string) *config { ...@@ -56,6 +59,8 @@ func ReadConfig(base string) *config {
return Config return Config
} }
// Set client string
//
func (c *config) SetClientString(str string) { func (c *config) SetClientString(str string) {
Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS) Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS)
} }
...@@ -134,7 +139,7 @@ func (log *Logger) Infoln(v ...interface{}) { ...@@ -134,7 +139,7 @@ func (log *Logger) Infoln(v ...interface{}) {
return return
} }
fmt.Println(len(log.logSys)) //fmt.Println(len(log.logSys))
for _, logger := range log.logSys { for _, logger := range log.logSys {
logger.Println(v...) logger.Println(v...)
} }
......
This diff is collapsed.
package ethutil
import (
"testing"
)
func TestMnDecode(t *testing.T) {
words := []string{
"ink",
"balance",
"gain",
"fear",
"happen",
"melt",
"mom",
"surface",
"stir",
"bottle",
"unseen",
"expression",
"important",
"curl",
"grant",
"fairy",
"across",
"back",
"figure",
"breast",
"nobody",
"scratch",
"worry",
"yesterday",
}
encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338"
result := MnemonicDecode(words)
if encode != result {
t.Error("We expected", encode, "got", result, "instead")
}
}
func TestMnEncode(t *testing.T) {
encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338"
result := []string{
"ink",
"balance",
"gain",
"fear",
"happen",
"melt",
"mom",
"surface",
"stir",
"bottle",
"unseen",
"expression",
"important",
"curl",
"grant",
"fairy",
"across",
"back",
"figure",
"breast",
"nobody",
"scratch",
"worry",
"yesterday",
}
words := MnemonicEncode(encode)
for i, word := range words {
if word != result[i] {
t.Error("Mnenonic does not match:", words, result)
}
}
}
package ethutil
import (
"archive/zip"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"strings"
)
// Manifest object
//
// The manifest object holds all the relevant information supplied with the
// the manifest specified in the package
type Manifest struct {
Entry string
Height, Width int
}
// External package
//
// External package contains the main html file and manifest
type ExtPackage struct {
EntryHtml string
Manifest *Manifest
}
// Read file
//
// Read a given compressed file and returns the read bytes.
// Returns an error otherwise
func ReadFile(f *zip.File) ([]byte, error) {
rc, err := f.Open()
if err != nil {
return nil, err
}
defer rc.Close()
content, err := ioutil.ReadAll(rc)
if err != nil {
return nil, err
}
return content, nil
}
// Reads manifest
//
// Reads and returns a manifest object. Returns error otherwise
func ReadManifest(m []byte) (*Manifest, error) {
var manifest Manifest
dec := json.NewDecoder(strings.NewReader(string(m)))
if err := dec.Decode(&manifest); err == io.EOF {
} else if err != nil {
return nil, err
}
return &manifest, nil
}
// Find file in archive
//
// Returns the index of the given file name if it exists. -1 if file not found
func FindFileInArchive(fn string, files []*zip.File) (index int) {
index = -1
// Find the manifest first
for i, f := range files {
if f.Name == fn {
index = i
}
}
return
}
// Open package
//
// Opens a prepared ethereum package
// Reads the manifest file and determines file contents and returns and
// the external package.
func OpenPackage(fn string) (*ExtPackage, error) {
r, err := zip.OpenReader(fn)
if err != nil {
return nil, err
}
defer r.Close()
manifestIndex := FindFileInArchive("manifest.json", r.File)
if manifestIndex < 0 {
return nil, fmt.Errorf("No manifest file found in archive")
}
f, err := ReadFile(r.File[manifestIndex])
if err != nil {
return nil, err
}
manifest, err := ReadManifest(f)
if err != nil {
return nil, err
}
if manifest.Entry == "" {
return nil, fmt.Errorf("Entry file specified but appears to be empty: %s", manifest.Entry)
}
entryIndex := FindFileInArchive(manifest.Entry, r.File)
if entryIndex < 0 {
return nil, fmt.Errorf("Entry file not found: '%s'", manifest.Entry)
}
f, err = ReadFile(r.File[entryIndex])
if err != nil {
return nil, err
}
extPackage := &ExtPackage{string(f), manifest}
return extPackage, nil
}
package ethutil
/*
import (
"math"
"testing"
)
func TestCompile(t *testing.T) {
instr, err := CompileInstr("PUSH")
if err != nil {
t.Error("Failed compiling instruction")
}
calc := (48 + 0*256 + 0*int64(math.Pow(256, 2)))
if BigD(instr).Int64() != calc {
t.Error("Expected", calc, ", got:", instr)
}
}
func TestValidInstr(t *testing.T) {
op, args, err := Instr("68163")
if err != nil {
t.Error("Error decoding instruction")
}
}
func TestInvalidInstr(t *testing.T) {
}
*/
...@@ -26,16 +26,6 @@ func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { ...@@ -26,16 +26,6 @@ func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte {
return Encode(rlpData) return Encode(rlpData)
} }
/*
func FromBin(data []byte) uint64 {
if len(data) == 0 {
return 0
}
return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1])
}
*/
const ( const (
RlpEmptyList = 0x80 RlpEmptyList = 0x80
RlpEmptyStr = 0x40 RlpEmptyStr = 0x40
...@@ -57,7 +47,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { ...@@ -57,7 +47,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} {
switch { switch {
case char == 0: case char == 0:
return nil return nil
case char <= 0x7c: case char <= 0x7f:
return char return char
case char <= 0xb7: case char <= 0xb7:
...@@ -186,7 +176,12 @@ func Encode(object interface{}) []byte { ...@@ -186,7 +176,12 @@ func Encode(object interface{}) []byte {
case byte: case byte:
buff.Write(Encode(big.NewInt(int64(t)))) buff.Write(Encode(big.NewInt(int64(t))))
case *big.Int: case *big.Int:
buff.Write(Encode(t.Bytes())) // Not sure how this is possible while we check for
if t == nil {
buff.WriteByte(0xc0)
} else {
buff.Write(Encode(t.Bytes()))
}
case []byte: case []byte:
if len(t) == 1 && t[0] <= 0x7f { if len(t) == 1 && t[0] <= 0x7f {
buff.Write(t) buff.Write(t)
......
...@@ -2,6 +2,7 @@ package ethutil ...@@ -2,6 +2,7 @@ package ethutil
import ( import (
"bytes" "bytes"
"fmt"
"math/big" "math/big"
"reflect" "reflect"
"testing" "testing"
...@@ -55,6 +56,15 @@ func TestValue(t *testing.T) { ...@@ -55,6 +56,15 @@ func TestValue(t *testing.T) {
} }
} }
func TestEncodeDecodeMaran(t *testing.T) {
b := NewValue([]interface{}{"dog", 15, []interface{}{"cat", "cat", []interface{}{}}, 1024, "tachikoma"})
a := b.Encode()
fmt.Println("voor maran", a)
f, i := Decode(a, 0)
fmt.Println("voor maran 2", f)
fmt.Println(i)
}
func TestEncode(t *testing.T) { func TestEncode(t *testing.T) {
strRes := "\x83dog" strRes := "\x83dog"
bytes := Encode("dog") bytes := Encode("dog")
...@@ -119,6 +129,11 @@ func TestEncodeDecodeBytes(t *testing.T) { ...@@ -119,6 +129,11 @@ func TestEncodeDecodeBytes(t *testing.T) {
} }
} }
func TestEncodeZero(t *testing.T) {
b := NewValue(0).Encode()
fmt.Println(b)
}
func BenchmarkEncodeDecode(b *testing.B) { func BenchmarkEncodeDecode(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
bytes := Encode([]interface{}{"dog", "god", "cat"}) bytes := Encode([]interface{}{"dog", "god", "cat"})
......
package ethutil
import (
"fmt"
"github.com/obscuren/mutan"
"strings"
)
// General compile function
func Compile(script string) ([]byte, error) {
byteCode, errors := mutan.Compile(strings.NewReader(script), false)
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
}
func CompileScript(script string) ([]byte, []byte, error) {
// Preprocess
mainInput, initInput := mutan.PreProcess(script)
// Compile main script
mainScript, err := Compile(mainInput)
if err != nil {
return nil, nil, err
}
// Compile init script
initScript, err := Compile(initInput)
if err != nil {
return nil, nil, err
}
return mainScript, initScript, nil
}
...@@ -119,14 +119,29 @@ type Trie struct { ...@@ -119,14 +119,29 @@ type Trie struct {
cache *Cache cache *Cache
} }
func copyRoot(root interface{}) interface{} {
var prevRootCopy interface{}
if b, ok := root.([]byte); ok {
prevRootCopy = CopyBytes(b)
} else {
prevRootCopy = root
}
return prevRootCopy
}
func NewTrie(db Database, Root interface{}) *Trie { func NewTrie(db Database, Root interface{}) *Trie {
return &Trie{cache: NewCache(db), Root: Root, prevRoot: Root} // Make absolute sure the root is copied
r := copyRoot(Root)
p := copyRoot(Root)
return &Trie{cache: NewCache(db), Root: r, prevRoot: p}
} }
// Save the cached value to the database. // Save the cached value to the database.
func (t *Trie) Sync() { func (t *Trie) Sync() {
t.cache.Commit() t.cache.Commit()
t.prevRoot = t.Root t.prevRoot = copyRoot(t.Root)
} }
func (t *Trie) Undo() { func (t *Trie) Undo() {
......
package ethutil package ethutil
import ( import (
"fmt" _ "fmt"
"reflect" "reflect"
"testing" "testing"
) )
......
...@@ -20,7 +20,12 @@ func (val *Value) String() string { ...@@ -20,7 +20,12 @@ func (val *Value) String() string {
} }
func NewValue(val interface{}) *Value { func NewValue(val interface{}) *Value {
return &Value{Val: val} t := val
if v, ok := val.(*Value); ok {
t = v.Val
}
return &Value{Val: t}
} }
func (val *Value) Type() reflect.Kind { func (val *Value) Type() reflect.Kind {
...@@ -149,6 +154,15 @@ func (val *Value) IsStr() bool { ...@@ -149,6 +154,15 @@ func (val *Value) IsStr() bool {
return val.Type() == reflect.String return val.Type() == reflect.String
} }
// Special list checking function. Something is considered
// a list if it's of type []interface{}. The list is usually
// used in conjunction with rlp decoded streams.
func (val *Value) IsList() bool {
_, ok := val.Val.([]interface{})
return ok
}
func (val *Value) IsEmpty() bool { func (val *Value) IsEmpty() bool {
return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0) return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0)
} }
......
...@@ -32,6 +32,7 @@ const ( ...@@ -32,6 +32,7 @@ const (
MsgBlockTy = 0x13 MsgBlockTy = 0x13
MsgGetChainTy = 0x14 MsgGetChainTy = 0x14
MsgNotInChainTy = 0x15 MsgNotInChainTy = 0x15
MsgGetTxsTy = 0x16
MsgTalkTy = 0xff MsgTalkTy = 0xff
) )
...@@ -46,6 +47,7 @@ var msgTypeToString = map[MsgType]string{ ...@@ -46,6 +47,7 @@ var msgTypeToString = map[MsgType]string{
MsgTxTy: "Transactions", MsgTxTy: "Transactions",
MsgBlockTy: "Blocks", MsgBlockTy: "Blocks",
MsgGetChainTy: "Get chain", MsgGetChainTy: "Get chain",
MsgGetTxsTy: "Get Txs",
MsgNotInChainTy: "Not in chain", MsgNotInChainTy: "Not in chain",
} }
......
...@@ -246,6 +246,10 @@ func soapRequest(url, function, message string) (r *http.Response, err error) { ...@@ -246,6 +246,10 @@ func soapRequest(url, function, message string) (r *http.Response, err error) {
//fmt.Println(fullMessage) //fmt.Println(fullMessage)
r, err = http.DefaultClient.Do(req) r, err = http.DefaultClient.Do(req)
if err != nil {
return
}
if r.Body != nil { if r.Body != nil {
defer r.Body.Close() defer r.Body.Close()
} }
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment