The great merge

This commit is contained in:
obscuren
2014-02-14 23:56:09 +01:00
parent c2fb9f06ad
commit f6d1bfe45b
43 changed files with 4547 additions and 12 deletions

12
ethchain/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore_global
/tmp
*/**/*un~
*un~
.DS_Store
*/**/.DS_Store

363
ethchain/block.go Normal file
View File

@ -0,0 +1,363 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"time"
)
type BlockInfo struct {
Number uint64
Hash []byte
Parent []byte
}
func (bi *BlockInfo) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
bi.Number = decoder.Get(0).Uint()
bi.Hash = decoder.Get(1).Bytes()
bi.Parent = decoder.Get(2).Bytes()
}
func (bi *BlockInfo) RlpEncode() []byte {
return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent})
}
type Block struct {
// Hash to the previous block
PrevHash []byte
// Uncles of this block
Uncles []*Block
UncleSha []byte
// The coin base address
Coinbase []byte
// Block Trie state
state *ethutil.Trie
// Difficulty for the current block
Difficulty *big.Int
// Creation time
Time int64
// Extra data
Extra string
// Block Nonce for verification
Nonce []byte
// List of transactions and/or contracts
transactions []*Transaction
TxSha []byte
}
// New block takes a raw encoded string
// XXX DEPRICATED
func NewBlockFromData(raw []byte) *Block {
return NewBlockFromBytes(raw)
}
func NewBlockFromBytes(raw []byte) *Block {
block := &Block{}
block.RlpDecode(raw)
return block
}
// New block takes a raw encoded string
func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block {
block := &Block{}
block.RlpValueDecode(rlpValue)
return block
}
func CreateBlock(root interface{},
prevHash []byte,
base []byte,
Difficulty *big.Int,
Nonce []byte,
extra string,
txes []*Transaction) *Block {
block := &Block{
// Slice of transactions to include in this block
transactions: txes,
PrevHash: prevHash,
Coinbase: base,
Difficulty: Difficulty,
Nonce: Nonce,
Time: time.Now().Unix(),
Extra: extra,
UncleSha: EmptyShaList,
}
block.SetTransactions(txes)
block.SetUncles([]*Block{})
block.state = ethutil.NewTrie(ethutil.Config.Db, root)
for _, tx := range txes {
block.MakeContract(tx)
}
return block
}
// Returns a hash of the block
func (block *Block) Hash() []byte {
return ethutil.Sha3Bin(block.RlpValue().Encode())
}
func (block *Block) HashNoNonce() []byte {
return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra}))
}
func (block *Block) PrintHash() {
fmt.Println(block)
fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce})))
}
func (block *Block) State() *ethutil.Trie {
return block.state
}
func (block *Block) Transactions() []*Transaction {
return block.transactions
}
func (block *Block) GetContract(addr []byte) *Contract {
data := block.state.Get(string(addr))
if data == "" {
return nil
}
contract := &Contract{}
contract.RlpDecode([]byte(data))
return contract
}
func (block *Block) UpdateContract(addr []byte, contract *Contract) {
// Make sure the state is synced
contract.State().Sync()
block.state.Update(string(addr), string(contract.RlpEncode()))
}
func (block *Block) GetAddr(addr []byte) *Address {
var address *Address
data := block.State().Get(string(addr))
if data == "" {
address = NewAddress(big.NewInt(0))
} else {
address = NewAddressFromData([]byte(data))
}
return address
}
func (block *Block) UpdateAddr(addr []byte, address *Address) {
block.state.Update(string(addr), string(address.RlpEncode()))
}
func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
contract := block.GetContract(addr)
// If we can't pay the fee return
if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ {
fmt.Println("Contract has insufficient funds", contract.Amount, fee)
return false
}
base := new(big.Int)
contract.Amount = base.Sub(contract.Amount, fee)
block.state.Update(string(addr), string(contract.RlpEncode()))
data := block.state.Get(string(block.Coinbase))
// Get the ether (Coinbase) and add the fee (gief fee to miner)
ether := NewAddressFromData([]byte(data))
base = new(big.Int)
ether.Amount = base.Add(ether.Amount, fee)
block.state.Update(string(block.Coinbase), string(ether.RlpEncode()))
return true
}
func (block *Block) BlockInfo() BlockInfo {
bi := BlockInfo{}
data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
bi.RlpDecode(data)
return bi
}
func (block *Block) MakeContract(tx *Transaction) {
// Create contract if there's no recipient
if tx.IsContract() {
addr := tx.Hash()
value := tx.Value
contract := NewContract(value, []byte(""))
block.state.Update(string(addr), string(contract.RlpEncode()))
for i, val := range tx.Data {
contract.state.Update(string(ethutil.NumberToBytes(uint64(i), 32)), val)
}
block.UpdateContract(addr, contract)
}
}
/////// Block Encoding
func (block *Block) encodedUncles() interface{} {
uncles := make([]interface{}, len(block.Uncles))
for i, uncle := range block.Uncles {
uncles[i] = uncle.RlpEncode()
}
return uncles
}
func (block *Block) encodedTxs() interface{} {
// Marshal the transactions of this block
encTx := make([]interface{}, len(block.transactions))
for i, tx := range block.transactions {
// Cast it to a string (safe)
encTx[i] = tx.RlpData()
}
return encTx
}
func (block *Block) rlpTxs() interface{} {
// Marshal the transactions of this block
encTx := make([]interface{}, len(block.transactions))
for i, tx := range block.transactions {
// Cast it to a string (safe)
encTx[i] = tx.RlpData()
}
return encTx
}
func (block *Block) rlpUncles() interface{} {
// Marshal the transactions of this block
uncles := make([]interface{}, len(block.Uncles))
for i, uncle := range block.Uncles {
// Cast it to a string (safe)
uncles[i] = uncle.header()
}
return uncles
}
func (block *Block) SetUncles(uncles []*Block) {
block.Uncles = uncles
// Sha of the concatenated uncles
block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles()))
}
func (block *Block) SetTransactions(txs []*Transaction) {
block.transactions = txs
block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs()))
}
func (block *Block) RlpValue() *ethutil.RlpValue {
return ethutil.NewRlpValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()})
}
func (block *Block) RlpEncode() []byte {
// Encode a slice interface which contains the header and the list of
// transactions.
return block.RlpValue().Encode()
}
func (block *Block) RlpDecode(data []byte) {
rlpValue := ethutil.NewValueFromBytes(data)
block.RlpValueDecode(rlpValue)
}
func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
header := decoder.Get(0)
block.PrevHash = header.Get(0).Bytes()
block.UncleSha = header.Get(1).Bytes()
block.Coinbase = header.Get(2).Bytes()
block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
block.TxSha = header.Get(4).Bytes()
block.Difficulty = header.Get(5).BigInt()
block.Time = int64(header.Get(6).BigInt().Uint64())
block.Extra = header.Get(7).Str()
block.Nonce = header.Get(8).Bytes()
// Tx list might be empty if this is an uncle. Uncles only have their
// header set.
if decoder.Get(1).IsNil() == false { // Yes explicitness
txes := decoder.Get(1)
block.transactions = make([]*Transaction, txes.Len())
for i := 0; i < txes.Len(); i++ {
tx := NewTransactionFromValue(txes.Get(i))
block.transactions[i] = tx
/*
if ethutil.Config.Debug {
ethutil.Config.Db.Put(tx.Hash(), ethutil.Encode(tx))
}
*/
}
}
if decoder.Get(2).IsNil() == false { // Yes explicitness
uncles := decoder.Get(2)
block.Uncles = make([]*Block, uncles.Len())
for i := 0; i < uncles.Len(); i++ {
block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i))
}
}
}
func NewUncleBlockFromValue(header *ethutil.Value) *Block {
block := &Block{}
block.PrevHash = header.Get(0).Bytes()
block.UncleSha = header.Get(1).Bytes()
block.Coinbase = header.Get(2).Bytes()
block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
block.TxSha = header.Get(4).Bytes()
block.Difficulty = header.Get(5).BigInt()
block.Time = int64(header.Get(6).BigInt().Uint64())
block.Extra = header.Get(7).Str()
block.Nonce = header.Get(8).Bytes()
return block
}
func (block *Block) String() string {
return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce)
}
//////////// UNEXPORTED /////////////////
func (block *Block) header() []interface{} {
return []interface{}{
// Sha of the previous block
block.PrevHash,
// Sha of uncles
block.UncleSha,
// Coinbase address
block.Coinbase,
// root state
block.state.Root,
// Sha of tx
block.TxSha,
// Current block Difficulty
block.Difficulty,
// Time the block was found?
block.Time,
// Extra data
block.Extra,
// Block's Nonce for validation
block.Nonce,
}
}

184
ethchain/block_chain.go Normal file
View File

@ -0,0 +1,184 @@
package ethchain
import (
"bytes"
"github.com/ethereum/eth-go/ethutil"
"log"
"math"
"math/big"
)
type BlockChain struct {
// The famous, the fabulous Mister GENESIIIIIIS (block)
genesisBlock *Block
// Last known total difficulty
TD *big.Int
LastBlockNumber uint64
CurrentBlock *Block
LastBlockHash []byte
}
func NewBlockChain() *BlockChain {
bc := &BlockChain{}
bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis))
bc.setLastBlock()
return bc
}
func (bc *BlockChain) Genesis() *Block {
return bc.genesisBlock
}
func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
var root interface{}
var lastBlockTime int64
hash := ZeroHash256
if bc.CurrentBlock != nil {
root = bc.CurrentBlock.State().Root
hash = bc.LastBlockHash
lastBlockTime = bc.CurrentBlock.Time
}
block := CreateBlock(
root,
hash,
coinbase,
ethutil.BigPow(2, 32),
nil,
"",
txs)
if bc.CurrentBlock != nil {
var mul *big.Int
if block.Time < lastBlockTime+42 {
mul = big.NewInt(1)
} else {
mul = big.NewInt(-1)
}
diff := new(big.Int)
diff.Add(diff, bc.CurrentBlock.Difficulty)
diff.Div(diff, big.NewInt(1024))
diff.Mul(diff, mul)
diff.Add(diff, bc.CurrentBlock.Difficulty)
block.Difficulty = diff
}
return block
}
func (bc *BlockChain) HasBlock(hash []byte) bool {
data, _ := ethutil.Config.Db.Get(hash)
return len(data) != 0
}
func (bc *BlockChain) GenesisBlock() *Block {
return bc.genesisBlock
}
// Get chain return blocks from hash up to max in RLP format
func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} {
var chain []interface{}
// Get the current hash to start with
currentHash := bc.CurrentBlock.Hash()
// Get the last number on the block chain
lastNumber := bc.BlockInfo(bc.CurrentBlock).Number
// Get the parents number
parentNumber := bc.BlockInfoByHash(hash).Number
// Get the min amount. We might not have max amount of blocks
count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max)))
startNumber := parentNumber + count
num := lastNumber
for ; num > startNumber; currentHash = bc.GetBlock(currentHash).PrevHash {
num--
}
for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ {
// Get the block of the chain
block := bc.GetBlock(currentHash)
currentHash = block.PrevHash
chain = append(chain, block.RlpValue().Value)
//chain = append([]interface{}{block.RlpValue().Value}, chain...)
num--
}
return chain
}
func (bc *BlockChain) setLastBlock() {
data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
if len(data) != 0 {
block := NewBlockFromBytes(data)
info := bc.BlockInfo(block)
bc.CurrentBlock = block
bc.LastBlockHash = block.Hash()
bc.LastBlockNumber = info.Number
log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber)
}
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
}
func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes())
bc.TD = td
}
// Add a block to the chain and record addition information
func (bc *BlockChain) Add(block *Block) {
bc.writeBlockInfo(block)
// Prepare the genesis block
bc.CurrentBlock = block
bc.LastBlockHash = block.Hash()
ethutil.Config.Db.Put(block.Hash(), block.RlpEncode())
}
func (bc *BlockChain) GetBlock(hash []byte) *Block {
data, _ := ethutil.Config.Db.Get(hash)
return NewBlockFromData(data)
}
func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo {
bi := BlockInfo{}
data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...))
bi.RlpDecode(data)
return bi
}
func (bc *BlockChain) BlockInfo(block *Block) BlockInfo {
bi := BlockInfo{}
data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
bi.RlpDecode(data)
return bi
}
// Unexported method for writing extra non-essential block info to the db
func (bc *BlockChain) writeBlockInfo(block *Block) {
bc.LastBlockNumber++
bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash}
// For now we use the block hash with the words "info" appended as key
ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode())
}
func (bc *BlockChain) Stop() {
if bc.CurrentBlock != nil {
ethutil.Config.Db.Put([]byte("LastBlock"), bc.CurrentBlock.RlpEncode())
log.Println("[CHAIN] Stopped")
}
}

627
ethchain/block_manager.go Normal file
View File

@ -0,0 +1,627 @@
package ethchain
import (
"bytes"
"encoding/hex"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
"log"
"math"
"math/big"
"strconv"
"sync"
"time"
)
type BlockProcessor interface {
ProcessBlock(block *Block)
}
func CalculateBlockReward(block *Block, uncleLength int) *big.Int {
return BlockReward
}
type BlockManager struct {
// Mutex for locking the block processor. Blocks can only be handled one at a time
mutex sync.Mutex
// The block chain :)
bc *BlockChain
// Stack for processing contracts
stack *Stack
// non-persistent key/value memory storage
mem map[string]*big.Int
TransactionPool *TxPool
Pow PoW
Speaker PublicSpeaker
SecondaryBlockProcessor BlockProcessor
}
func AddTestNetFunds(block *Block) {
for _, addr := range []string{
"8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin
"93658b04240e4bd4046fd2d6d417d20f146f4b43", // Jeffrey
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit
"80c01a26338f0d905e295fccb71fa9ea849ffa12", // Alex
} {
//log.Println("2^200 Wei to", addr)
codedAddr, _ := hex.DecodeString(addr)
addr := block.GetAddr(codedAddr)
addr.Amount = ethutil.BigPow(2, 200)
block.UpdateAddr(codedAddr, addr)
}
}
func NewBlockManager(speaker PublicSpeaker) *BlockManager {
bm := &BlockManager{
//server: s,
bc: NewBlockChain(),
stack: NewStack(),
mem: make(map[string]*big.Int),
Pow: &EasyPow{},
Speaker: speaker,
}
if bm.bc.CurrentBlock == nil {
AddTestNetFunds(bm.bc.genesisBlock)
// Prepare the genesis block
//bm.bc.genesisBlock.State().Sync()
bm.bc.Add(bm.bc.genesisBlock)
log.Println(bm.bc.genesisBlock)
log.Printf("Genesis: %x\n", bm.bc.genesisBlock.Hash())
//log.Printf("root %x\n", bm.bc.genesisBlock.State().Root)
//bm.bc.genesisBlock.PrintHash()
}
return bm
}
func (bm *BlockManager) BlockChain() *BlockChain {
return bm.bc
}
func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) {
// Process each transaction/contract
for _, tx := range txs {
// If there's no recipient, it's a contract
if tx.IsContract() {
block.MakeContract(tx)
bm.ProcessContract(tx, block)
} else {
bm.TransactionPool.ProcessTransaction(tx, block)
}
}
}
// Block processing and validating with a given (temporarily) state
func (bm *BlockManager) ProcessBlock(block *Block) error {
// Processing a blocks may never happen simultaneously
bm.mutex.Lock()
defer bm.mutex.Unlock()
hash := block.Hash()
if bm.bc.HasBlock(hash) {
return nil
}
/*
if ethutil.Config.Debug {
log.Printf("[BMGR] Processing block(%x)\n", hash)
}
*/
// Check if we have the parent hash, if it isn't known we discard it
// Reasons might be catching up or simply an invalid block
if !bm.bc.HasBlock(block.PrevHash) && bm.bc.CurrentBlock != nil {
return ParentError(block.PrevHash)
}
// Process the transactions on to current block
bm.ApplyTransactions(bm.bc.CurrentBlock, block.Transactions())
// Block validation
if err := bm.ValidateBlock(block); err != nil {
return err
}
// I'm not sure, but I don't know if there should be thrown
// any errors at this time.
if err := bm.AccumelateRewards(bm.bc.CurrentBlock, block); err != nil {
return err
}
if !block.State().Cmp(bm.bc.CurrentBlock.State()) {
//if block.State().Root != state.Root {
return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().Root, bm.bc.CurrentBlock.State().Root)
}
// Calculate the new total difficulty and sync back to the db
if bm.CalculateTD(block) {
// Sync the current block's state to the database
bm.bc.CurrentBlock.State().Sync()
// Add the block to the chain
bm.bc.Add(block)
/*
ethutil.Config.Db.Put(block.Hash(), block.RlpEncode())
bm.bc.CurrentBlock = block
bm.LastBlockHash = block.Hash()
bm.writeBlockInfo(block)
*/
/*
txs := bm.TransactionPool.Flush()
var coded = []interface{}{}
for _, tx := range txs {
err := bm.TransactionPool.ValidateTransaction(tx)
if err == nil {
coded = append(coded, tx.RlpEncode())
}
}
*/
// Broadcast the valid block back to the wire
//bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.RlpValue().Value})
// If there's a block processor present, pass in the block for further
// processing
if bm.SecondaryBlockProcessor != nil {
bm.SecondaryBlockProcessor.ProcessBlock(block)
}
log.Printf("[BMGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash())
} else {
fmt.Println("total diff failed")
}
return nil
}
func (bm *BlockManager) CalculateTD(block *Block) bool {
uncleDiff := new(big.Int)
for _, uncle := range block.Uncles {
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
}
// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
td := new(big.Int)
td = td.Add(bm.bc.TD, uncleDiff)
td = td.Add(td, block.Difficulty)
// The new TD will only be accepted if the new difficulty is
// is greater than the previous.
if td.Cmp(bm.bc.TD) > 0 {
// Set the new total difficulty back to the block chain
bm.bc.SetTotalDifficulty(td)
/*
if ethutil.Config.Debug {
log.Println("[BMGR] TD(block) =", td)
}
*/
return true
}
return false
}
// Validates the current block. Returns an error if the block was invalid,
// an uncle or anything that isn't on the current block chain.
// Validation validates easy over difficult (dagger takes longer time = difficult)
func (bm *BlockManager) ValidateBlock(block *Block) error {
// TODO
// 2. Check if the difficulty is correct
// Check each uncle's previous hash. In order for it to be valid
// is if it has the same block hash as the current
previousBlock := bm.bc.GetBlock(block.PrevHash)
for _, uncle := range block.Uncles {
if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 {
return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash)
}
}
diff := block.Time - bm.bc.CurrentBlock.Time
if diff < 0 {
return ValidationError("Block timestamp less then prev block %v", diff)
}
// New blocks must be within the 15 minute range of the last block.
if diff > int64(15*time.Minute) {
return ValidationError("Block is too far in the future of last block (> 15 minutes)")
}
// Verify the nonce of the block. Return an error if it's not valid
if !bm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) {
return ValidationError("Block's nonce is invalid (= %v)", block.Nonce)
}
return nil
}
func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error {
// Get the coinbase rlp data
addr := processor.GetAddr(block.Coinbase)
// Reward amount of ether to the coinbase address
addr.AddFee(CalculateBlockReward(block, len(block.Uncles)))
processor.UpdateAddr(block.Coinbase, addr)
// TODO Reward each uncle
return nil
}
func (bm *BlockManager) Stop() {
bm.bc.Stop()
}
func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) {
// Recovering function in case the VM had any errors
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from VM execution with err =", r)
}
}()
// Process contract
bm.ProcContract(tx, block, func(opType OpType) bool {
// TODO turn on once big ints are in place
//if !block.PayFee(tx.Hash(), StepFee.Uint64()) {
// return false
//}
return true // Continue
})
}
// Contract evaluation is done here.
func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallback) {
// Instruction pointer
pc := 0
blockInfo := bm.bc.BlockInfo(block)
contract := block.GetContract(tx.Hash())
if contract == nil {
fmt.Println("Contract not found")
return
}
Pow256 := ethutil.BigPow(2, 256)
if ethutil.Config.Debug {
fmt.Printf("# op arg\n")
}
out:
for {
// The base big int for all calculations. Use this for any results.
base := new(big.Int)
// XXX Should Instr return big int slice instead of string slice?
// Get the next instruction from the contract
//op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
nb := ethutil.NumberToBytes(uint64(pc), 32)
o, _, _ := ethutil.Instr(contract.State().Get(string(nb)))
op := OpCode(o)
if !cb(0) {
break
}
if ethutil.Config.Debug {
fmt.Printf("%-3d %-4s\n", pc, op.String())
}
switch op {
case oSTOP:
break out
case oADD:
x, y := bm.stack.Popn()
// (x + y) % 2 ** 256
base.Add(x, y)
base.Mod(base, Pow256)
// Pop result back on the stack
bm.stack.Push(base)
case oSUB:
x, y := bm.stack.Popn()
// (x - y) % 2 ** 256
base.Sub(x, y)
base.Mod(base, Pow256)
// Pop result back on the stack
bm.stack.Push(base)
case oMUL:
x, y := bm.stack.Popn()
// (x * y) % 2 ** 256
base.Mul(x, y)
base.Mod(base, Pow256)
// Pop result back on the stack
bm.stack.Push(base)
case oDIV:
x, y := bm.stack.Popn()
// floor(x / y)
base.Div(x, y)
// Pop result back on the stack
bm.stack.Push(base)
case oSDIV:
x, y := bm.stack.Popn()
// n > 2**255
if x.Cmp(Pow256) > 0 {
x.Sub(Pow256, x)
}
if y.Cmp(Pow256) > 0 {
y.Sub(Pow256, y)
}
z := new(big.Int)
z.Div(x, y)
if z.Cmp(Pow256) > 0 {
z.Sub(Pow256, z)
}
// Push result on to the stack
bm.stack.Push(z)
case oMOD:
x, y := bm.stack.Popn()
base.Mod(x, y)
bm.stack.Push(base)
case oSMOD:
x, y := bm.stack.Popn()
// n > 2**255
if x.Cmp(Pow256) > 0 {
x.Sub(Pow256, x)
}
if y.Cmp(Pow256) > 0 {
y.Sub(Pow256, y)
}
z := new(big.Int)
z.Mod(x, y)
if z.Cmp(Pow256) > 0 {
z.Sub(Pow256, z)
}
// Push result on to the stack
bm.stack.Push(z)
case oEXP:
x, y := bm.stack.Popn()
base.Exp(x, y, Pow256)
bm.stack.Push(base)
case oNEG:
base.Sub(Pow256, bm.stack.Pop())
bm.stack.Push(base)
case oLT:
x, y := bm.stack.Popn()
// x < y
if x.Cmp(y) < 0 {
bm.stack.Push(ethutil.BigTrue)
} else {
bm.stack.Push(ethutil.BigFalse)
}
case oLE:
x, y := bm.stack.Popn()
// x <= y
if x.Cmp(y) < 1 {
bm.stack.Push(ethutil.BigTrue)
} else {
bm.stack.Push(ethutil.BigFalse)
}
case oGT:
x, y := bm.stack.Popn()
// x > y
if x.Cmp(y) > 0 {
bm.stack.Push(ethutil.BigTrue)
} else {
bm.stack.Push(ethutil.BigFalse)
}
case oGE:
x, y := bm.stack.Popn()
// x >= y
if x.Cmp(y) > -1 {
bm.stack.Push(ethutil.BigTrue)
} else {
bm.stack.Push(ethutil.BigFalse)
}
case oNOT:
x, y := bm.stack.Popn()
// x != y
if x.Cmp(y) != 0 {
bm.stack.Push(ethutil.BigTrue)
} else {
bm.stack.Push(ethutil.BigFalse)
}
// Please note that the following code contains some
// ugly string casting. This will have to change to big
// ints. TODO :)
case oMYADDRESS:
bm.stack.Push(ethutil.BigD(tx.Hash()))
case oTXSENDER:
bm.stack.Push(ethutil.BigD(tx.Sender()))
case oTXVALUE:
bm.stack.Push(tx.Value)
case oTXDATAN:
bm.stack.Push(big.NewInt(int64(len(tx.Data))))
case oTXDATA:
v := bm.stack.Pop()
// v >= len(data)
if v.Cmp(big.NewInt(int64(len(tx.Data)))) >= 0 {
bm.stack.Push(ethutil.Big("0"))
} else {
bm.stack.Push(ethutil.Big(tx.Data[v.Uint64()]))
}
case oBLK_PREVHASH:
bm.stack.Push(ethutil.BigD(block.PrevHash))
case oBLK_COINBASE:
bm.stack.Push(ethutil.BigD(block.Coinbase))
case oBLK_TIMESTAMP:
bm.stack.Push(big.NewInt(block.Time))
case oBLK_NUMBER:
bm.stack.Push(big.NewInt(int64(blockInfo.Number)))
case oBLK_DIFFICULTY:
bm.stack.Push(block.Difficulty)
case oBASEFEE:
// e = 10^21
e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0))
d := new(big.Rat)
d.SetInt(block.Difficulty)
c := new(big.Rat)
c.SetFloat64(0.5)
// d = diff / 0.5
d.Quo(d, c)
// base = floor(d)
base.Div(d.Num(), d.Denom())
x := new(big.Int)
x.Div(e, base)
// x = floor(10^21 / floor(diff^0.5))
bm.stack.Push(x)
case oSHA256, oSHA3, oRIPEMD160:
// This is probably save
// ceil(pop / 32)
length := int(math.Ceil(float64(bm.stack.Pop().Uint64()) / 32.0))
// New buffer which will contain the concatenated popped items
data := new(bytes.Buffer)
for i := 0; i < length; i++ {
// Encode the number to bytes and have it 32bytes long
num := ethutil.NumberToBytes(bm.stack.Pop().Bytes(), 256)
data.WriteString(string(num))
}
if op == oSHA256 {
bm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes())))
} else if op == oSHA3 {
bm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes())))
} else {
bm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes())))
}
case oECMUL:
y := bm.stack.Pop()
x := bm.stack.Pop()
//n := bm.stack.Pop()
//if ethutil.Big(x).Cmp(ethutil.Big(y)) {
data := new(bytes.Buffer)
data.WriteString(x.String())
data.WriteString(y.String())
if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 {
// TODO
} else {
// Invalid, push infinity
bm.stack.Push(ethutil.Big("0"))
bm.stack.Push(ethutil.Big("0"))
}
//} else {
// // Invalid, push infinity
// bm.stack.Push("0")
// bm.stack.Push("0")
//}
case oECADD:
case oECSIGN:
case oECRECOVER:
case oECVALID:
case oPUSH:
pc++
bm.stack.Push(bm.mem[strconv.Itoa(pc)])
case oPOP:
// Pop current value of the stack
bm.stack.Pop()
case oDUP:
// Dup top stack
x := bm.stack.Pop()
bm.stack.Push(x)
bm.stack.Push(x)
case oSWAP:
// Swap two top most values
x, y := bm.stack.Popn()
bm.stack.Push(y)
bm.stack.Push(x)
case oMLOAD:
x := bm.stack.Pop()
bm.stack.Push(bm.mem[x.String()])
case oMSTORE:
x, y := bm.stack.Popn()
bm.mem[x.String()] = y
case oSLOAD:
// Load the value in storage and push it on the stack
x := bm.stack.Pop()
// decode the object as a big integer
decoder := ethutil.NewRlpValueFromBytes([]byte(contract.State().Get(x.String())))
if !decoder.IsNil() {
bm.stack.Push(decoder.AsBigInt())
} else {
bm.stack.Push(ethutil.BigFalse)
}
case oSSTORE:
// Store Y at index X
x, y := bm.stack.Popn()
contract.State().Update(x.String(), string(ethutil.Encode(y)))
case oJMP:
x := int(bm.stack.Pop().Uint64())
// Set pc to x - 1 (minus one so the incrementing at the end won't effect it)
pc = x
pc--
case oJMPI:
x := bm.stack.Pop()
// Set pc to x if it's non zero
if x.Cmp(ethutil.BigFalse) != 0 {
pc = int(x.Uint64())
pc--
}
case oIND:
bm.stack.Push(big.NewInt(int64(pc)))
case oEXTRO:
memAddr := bm.stack.Pop()
contractAddr := bm.stack.Pop().Bytes()
// Push the contract's memory on to the stack
bm.stack.Push(getContractMemory(block, contractAddr, memAddr))
case oBALANCE:
// Pushes the balance of the popped value on to the stack
d := block.State().Get(bm.stack.Pop().String())
ether := NewAddressFromData([]byte(d))
bm.stack.Push(ether.Amount)
case oMKTX:
value, addr := bm.stack.Popn()
from, length := bm.stack.Popn()
j := 0
dataItems := make([]string, int(length.Uint64()))
for i := from.Uint64(); i < length.Uint64(); i++ {
dataItems[j] = string(bm.mem[strconv.Itoa(int(i))].Bytes())
j++
}
// TODO sign it?
tx := NewTransaction(addr.Bytes(), value, dataItems)
// Add the transaction to the tx pool
bm.TransactionPool.QueueTransaction(tx)
case oSUICIDE:
//addr := bm.stack.Pop()
}
pc++
}
}
// Returns an address from the specified contract's address
func getContractMemory(block *Block, contractAddr []byte, memAddr *big.Int) *big.Int {
contract := block.GetContract(contractAddr)
if contract == nil {
log.Panicf("invalid contract addr %x", contractAddr)
}
val := contract.State().Get(memAddr.String())
// decode the object as a big integer
decoder := ethutil.NewRlpValueFromBytes([]byte(val))
if decoder.IsNil() {
return ethutil.BigFalse
}
return decoder.AsBigInt()
}

View File

@ -0,0 +1,75 @@
package ethchain
/*
import (
_ "fmt"
"testing"
)
func TestVm(t *testing.T) {
InitFees()
db, _ := NewMemDatabase()
Db = db
ctrct := NewTransaction("", 200000000, []string{
"PUSH", "1a2f2e",
"PUSH", "hallo",
"POP", // POP hallo
"PUSH", "3",
"LOAD", // Load hallo back on the stack
"PUSH", "1",
"PUSH", "2",
"ADD",
"PUSH", "2",
"PUSH", "1",
"SUB",
"PUSH", "100000000000000000000000",
"PUSH", "10000000000000",
"SDIV",
"PUSH", "105",
"PUSH", "200",
"MOD",
"PUSH", "100000000000000000000000",
"PUSH", "10000000000000",
"SMOD",
"PUSH", "5",
"PUSH", "10",
"LT",
"PUSH", "5",
"PUSH", "5",
"LE",
"PUSH", "50",
"PUSH", "5",
"GT",
"PUSH", "5",
"PUSH", "5",
"GE",
"PUSH", "10",
"PUSH", "10",
"NOT",
"MYADDRESS",
"TXSENDER",
"STOP",
})
tx := NewTransaction("1e8a42ea8cce13", 100, []string{})
block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx})
db.Put(block.Hash(), block.RlpEncode())
bm := NewBlockManager()
bm.ProcessBlock(block)
}
*/

66
ethchain/contract.go Normal file
View File

@ -0,0 +1,66 @@
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type Contract struct {
Amount *big.Int
Nonce uint64
state *ethutil.Trie
}
func NewContract(Amount *big.Int, root []byte) *Contract {
contract := &Contract{Amount: Amount, Nonce: 0}
contract.state = ethutil.NewTrie(ethutil.Config.Db, string(root))
return contract
}
func (c *Contract) RlpEncode() []byte {
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.Root})
}
func (c *Contract) RlpDecode(data []byte) {
decoder := ethutil.NewRlpValueFromBytes(data)
c.Amount = decoder.Get(0).AsBigInt()
c.Nonce = decoder.Get(1).AsUint()
c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).AsRaw())
}
func (c *Contract) State() *ethutil.Trie {
return c.state
}
type Address struct {
Amount *big.Int
Nonce uint64
}
func NewAddress(amount *big.Int) *Address {
return &Address{Amount: amount, Nonce: 0}
}
func NewAddressFromData(data []byte) *Address {
address := &Address{}
address.RlpDecode(data)
return address
}
func (a *Address) AddFee(fee *big.Int) {
a.Amount.Add(a.Amount, fee)
}
func (a *Address) RlpEncode() []byte {
return ethutil.Encode([]interface{}{a.Amount, a.Nonce})
}
func (a *Address) RlpDecode(data []byte) {
decoder := ethutil.NewRlpValueFromBytes(data)
a.Amount = decoder.Get(0).AsBigInt()
a.Nonce = decoder.Get(1).AsUint()
}

199
ethchain/dagger.go Normal file
View File

@ -0,0 +1,199 @@
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/sha3"
"hash"
"log"
"math/big"
"math/rand"
"time"
)
type PoW interface {
Search(block *Block) []byte
Verify(hash []byte, diff *big.Int, nonce []byte) bool
}
type EasyPow struct {
hash *big.Int
}
func (pow *EasyPow) Search(block *Block) []byte {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
hash := block.HashNoNonce()
diff := block.Difficulty
for {
sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes())
if pow.Verify(hash, diff, sha) {
return sha
}
}
return nil
}
func (pow *EasyPow) Verify(hash []byte, diff *big.Int, nonce []byte) bool {
sha := sha3.NewKeccak256()
d := append(hash, nonce...)
sha.Write(d)
v := ethutil.BigPow(2, 256)
ret := new(big.Int).Div(v, diff)
res := new(big.Int)
res.SetBytes(sha.Sum(nil))
return res.Cmp(ret) == -1
}
func (pow *EasyPow) SetHash(hash *big.Int) {
}
type Dagger struct {
hash *big.Int
xn *big.Int
}
var Found bool
func (dag *Dagger) Find(obj *big.Int, resChan chan int64) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 1000; i++ {
rnd := r.Int63()
res := dag.Eval(big.NewInt(rnd))
log.Printf("rnd %v\nres %v\nobj %v\n", rnd, res, obj)
if res.Cmp(obj) < 0 {
// Post back result on the channel
resChan <- rnd
// Notify other threads we've found a valid nonce
Found = true
}
// Break out if found
if Found {
break
}
}
resChan <- 0
}
func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
// TODO fix multi threading. Somehow it results in the wrong nonce
amountOfRoutines := 1
dag.hash = hash
obj := ethutil.BigPow(2, 256)
obj = obj.Div(obj, diff)
Found = false
resChan := make(chan int64, 3)
var res int64
for k := 0; k < amountOfRoutines; k++ {
go dag.Find(obj, resChan)
}
// Wait for each go routine to finish
for k := 0; k < amountOfRoutines; k++ {
// Get the result from the channel. 0 = quit
if r := <-resChan; r != 0 {
res = r
}
}
return big.NewInt(res)
}
func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool {
dag.hash = hash
obj := ethutil.BigPow(2, 256)
obj = obj.Div(obj, diff)
return dag.Eval(nonce).Cmp(obj) < 0
}
func DaggerVerify(hash, diff, nonce *big.Int) bool {
dagger := &Dagger{}
dagger.hash = hash
obj := ethutil.BigPow(2, 256)
obj = obj.Div(obj, diff)
return dagger.Eval(nonce).Cmp(obj) < 0
}
func (dag *Dagger) Node(L uint64, i uint64) *big.Int {
if L == i {
return dag.hash
}
var m *big.Int
if L == 9 {
m = big.NewInt(16)
} else {
m = big.NewInt(3)
}
sha := sha3.NewKeccak256()
sha.Reset()
d := sha3.NewKeccak256()
b := new(big.Int)
ret := new(big.Int)
for k := 0; k < int(m.Uint64()); k++ {
d.Reset()
d.Write(dag.hash.Bytes())
d.Write(dag.xn.Bytes())
d.Write(big.NewInt(int64(L)).Bytes())
d.Write(big.NewInt(int64(i)).Bytes())
d.Write(big.NewInt(int64(k)).Bytes())
b.SetBytes(Sum(d))
pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1)
sha.Write(dag.Node(L-1, pk).Bytes())
}
ret.SetBytes(Sum(sha))
return ret
}
func Sum(sha hash.Hash) []byte {
//in := make([]byte, 32)
return sha.Sum(nil)
}
func (dag *Dagger) Eval(N *big.Int) *big.Int {
pow := ethutil.BigPow(2, 26)
dag.xn = pow.Div(N, pow)
sha := sha3.NewKeccak256()
sha.Reset()
ret := new(big.Int)
for k := 0; k < 4; k++ {
d := sha3.NewKeccak256()
b := new(big.Int)
d.Reset()
d.Write(dag.hash.Bytes())
d.Write(dag.xn.Bytes())
d.Write(N.Bytes())
d.Write(big.NewInt(int64(k)).Bytes())
b.SetBytes(Sum(d))
pk := (b.Uint64() & 0x1ffffff)
sha.Write(dag.Node(9, pk).Bytes())
}
return ret.SetBytes(Sum(sha))
}

18
ethchain/dagger_test.go Normal file
View File

@ -0,0 +1,18 @@
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
func BenchmarkDaggerSearch(b *testing.B) {
hash := big.NewInt(0)
diff := ethutil.BigPow(2, 36)
o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity
// Reset timer so the big generation isn't included in the benchmark
b.ResetTimer()
// Validate
DaggerVerify(hash, diff, o)
}

42
ethchain/error.go Normal file
View File

@ -0,0 +1,42 @@
package ethchain
import "fmt"
// Parent error. In case a parent is unknown this error will be thrown
// by the block manager
type ParentErr struct {
Message string
}
func (err *ParentErr) Error() string {
return err.Message
}
func ParentError(hash []byte) error {
return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)}
}
func IsParentErr(err error) bool {
_, ok := err.(*ParentErr)
return ok
}
// Block validation error. If any validation fails, this error will be thrown
type ValidationErr struct {
Message string
}
func (err *ValidationErr) Error() string {
return err.Message
}
func ValidationError(format string, v ...interface{}) *ValidationErr {
return &ValidationErr{Message: fmt.Sprintf(format, v...)}
}
func IsValidationErr(err error) bool {
_, ok := err.(*ValidationErr)
return ok
}

65
ethchain/fees.go Normal file
View File

@ -0,0 +1,65 @@
package ethchain
import (
"math/big"
)
var StepFee *big.Int = new(big.Int)
var TxFeeRat *big.Int = big.NewInt(100000000000000)
var TxFee *big.Int = big.NewInt(100)
var ContractFee *big.Int = new(big.Int)
var MemFee *big.Int = new(big.Int)
var DataFee *big.Int = new(big.Int)
var CryptoFee *big.Int = new(big.Int)
var ExtroFee *big.Int = new(big.Int)
var BlockReward *big.Int = big.NewInt(1500000000000000000)
var Period1Reward *big.Int = new(big.Int)
var Period2Reward *big.Int = new(big.Int)
var Period3Reward *big.Int = new(big.Int)
var Period4Reward *big.Int = new(big.Int)
func InitFees() {
/*
// Base for 2**64
b60 := new(big.Int)
b60.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
// Base for 2**80
b80 := new(big.Int)
b80.Exp(big.NewInt(2), big.NewInt(80), big.NewInt(0))
StepFee.Exp(big.NewInt(10), big.NewInt(16), big.NewInt(0))
//StepFee.Div(b60, big.NewInt(64))
//fmt.Println("StepFee:", StepFee)
TxFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
//fmt.Println("TxFee:", TxFee)
ContractFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0))
//fmt.Println("ContractFee:", ContractFee)
MemFee.Div(b60, big.NewInt(4))
//fmt.Println("MemFee:", MemFee)
DataFee.Div(b60, big.NewInt(16))
//fmt.Println("DataFee:", DataFee)
CryptoFee.Div(b60, big.NewInt(16))
//fmt.Println("CrytoFee:", CryptoFee)
ExtroFee.Div(b60, big.NewInt(16))
//fmt.Println("ExtroFee:", ExtroFee)
Period1Reward.Mul(b80, big.NewInt(1024))
//fmt.Println("Period1Reward:", Period1Reward)
Period2Reward.Mul(b80, big.NewInt(512))
//fmt.Println("Period2Reward:", Period2Reward)
Period3Reward.Mul(b80, big.NewInt(256))
//fmt.Println("Period3Reward:", Period3Reward)
Period4Reward.Mul(b80, big.NewInt(128))
//fmt.Println("Period4Reward:", Period4Reward)
*/
}

39
ethchain/genesis.go Normal file
View File

@ -0,0 +1,39 @@
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
/*
* This is the special genesis block.
*/
var ZeroHash256 = make([]byte, 32)
var ZeroHash160 = make([]byte, 20)
var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{}))
var GenisisHeader = []interface{}{
// Previous hash (none)
//"",
ZeroHash256,
// Sha of uncles
ethutil.Sha3Bin(ethutil.Encode([]interface{}{})),
// Coinbase
ZeroHash160,
// Root state
"",
// Sha of transactions
//EmptyShaList,
ethutil.Sha3Bin(ethutil.Encode([]interface{}{})),
// Difficulty
ethutil.BigPow(2, 22),
// Time
int64(0),
// Extra
"",
// Nonce
ethutil.Sha3Bin(big.NewInt(42).Bytes()),
}
var Genesis = []interface{}{GenisisHeader, []interface{}{}, []interface{}{}}

167
ethchain/stack.go Normal file
View File

@ -0,0 +1,167 @@
package ethchain
import (
"fmt"
"math/big"
)
type OpCode int
// Op codes
const (
oSTOP OpCode = iota
oADD
oMUL
oSUB
oDIV
oSDIV
oMOD
oSMOD
oEXP
oNEG
oLT
oLE
oGT
oGE
oEQ
oNOT
oMYADDRESS
oTXSENDER
oTXVALUE
oTXFEE
oTXDATAN
oTXDATA
oBLK_PREVHASH
oBLK_COINBASE
oBLK_TIMESTAMP
oBLK_NUMBER
oBLK_DIFFICULTY
oBASEFEE
oSHA256 OpCode = 32
oRIPEMD160 OpCode = 33
oECMUL OpCode = 34
oECADD OpCode = 35
oECSIGN OpCode = 36
oECRECOVER OpCode = 37
oECVALID OpCode = 38
oSHA3 OpCode = 39
oPUSH OpCode = 48
oPOP OpCode = 49
oDUP OpCode = 50
oSWAP OpCode = 51
oMLOAD OpCode = 52
oMSTORE OpCode = 53
oSLOAD OpCode = 54
oSSTORE OpCode = 55
oJMP OpCode = 56
oJMPI OpCode = 57
oIND OpCode = 58
oEXTRO OpCode = 59
oBALANCE OpCode = 60
oMKTX OpCode = 61
oSUICIDE OpCode = 62
)
// Since the opcodes aren't all in order we can't use a regular slice
var opCodeToString = map[OpCode]string{
oSTOP: "STOP",
oADD: "ADD",
oMUL: "MUL",
oSUB: "SUB",
oDIV: "DIV",
oSDIV: "SDIV",
oMOD: "MOD",
oSMOD: "SMOD",
oEXP: "EXP",
oNEG: "NEG",
oLT: "LT",
oLE: "LE",
oGT: "GT",
oGE: "GE",
oEQ: "EQ",
oNOT: "NOT",
oMYADDRESS: "MYADDRESS",
oTXSENDER: "TXSENDER",
oTXVALUE: "TXVALUE",
oTXFEE: "TXFEE",
oTXDATAN: "TXDATAN",
oTXDATA: "TXDATA",
oBLK_PREVHASH: "BLK_PREVHASH",
oBLK_COINBASE: "BLK_COINBASE",
oBLK_TIMESTAMP: "BLK_TIMESTAMP",
oBLK_NUMBER: "BLK_NUMBER",
oBLK_DIFFICULTY: "BLK_DIFFICULTY",
oBASEFEE: "BASEFEE",
oSHA256: "SHA256",
oRIPEMD160: "RIPEMD160",
oECMUL: "ECMUL",
oECADD: "ECADD",
oECSIGN: "ECSIGN",
oECRECOVER: "ECRECOVER",
oECVALID: "ECVALID",
oSHA3: "SHA3",
oPUSH: "PUSH",
oPOP: "POP",
oDUP: "DUP",
oSWAP: "SWAP",
oMLOAD: "MLOAD",
oMSTORE: "MSTORE",
oSLOAD: "SLOAD",
oSSTORE: "SSTORE",
oJMP: "JMP",
oJMPI: "JMPI",
oIND: "IND",
oEXTRO: "EXTRO",
oBALANCE: "BALANCE",
oMKTX: "MKTX",
oSUICIDE: "SUICIDE",
}
func (o OpCode) String() string {
return opCodeToString[o]
}
type OpType int
const (
tNorm = iota
tData
tExtro
tCrypto
)
type TxCallback func(opType OpType) bool
// Simple push/pop stack mechanism
type Stack struct {
data []*big.Int
}
func NewStack() *Stack {
return &Stack{}
}
func (st *Stack) Pop() *big.Int {
s := len(st.data)
str := st.data[s-1]
st.data = st.data[:s-1]
return str
}
func (st *Stack) Popn() (*big.Int, *big.Int) {
s := len(st.data)
ints := st.data[s-2:]
st.data = st.data[:s-2]
return ints[0], ints[1]
}
func (st *Stack) Push(d *big.Int) {
st.data = append(st.data, d)
}
func (st *Stack) Print() {
fmt.Println(st.data)
}

157
ethchain/transaction.go Normal file
View File

@ -0,0 +1,157 @@
package ethchain
import (
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
"math/big"
)
type Transaction struct {
Nonce uint64
Recipient []byte
Value *big.Int
Data []string
Memory []int
v byte
r, s []byte
}
func NewTransaction(to []byte, value *big.Int, data []string) *Transaction {
tx := Transaction{Recipient: to, Value: value}
tx.Nonce = 0
// Serialize the data
tx.Data = make([]string, len(data))
for i, val := range data {
instr, err := ethutil.CompileInstr(val)
if err != nil {
//fmt.Printf("compile error:%d %v\n", i+1, err)
}
tx.Data[i] = instr
}
return &tx
}
func NewTransactionFromData(data []byte) *Transaction {
tx := &Transaction{}
tx.RlpDecode(data)
return tx
}
func NewTransactionFromValue(val *ethutil.Value) *Transaction {
tx := &Transaction{}
tx.RlpValueDecode(val)
return tx
}
func (tx *Transaction) Hash() []byte {
data := make([]interface{}, len(tx.Data))
for i, val := range tx.Data {
data[i] = val
}
preEnc := []interface{}{
tx.Nonce,
tx.Recipient,
tx.Value,
data,
}
return ethutil.Sha3Bin(ethutil.Encode(preEnc))
}
func (tx *Transaction) IsContract() bool {
return len(tx.Recipient) == 0
}
func (tx *Transaction) Signature(key []byte) []byte {
hash := tx.Hash()
sig, _ := secp256k1.Sign(hash, key)
return sig
}
func (tx *Transaction) PublicKey() []byte {
hash := tx.Hash()
// If we don't make a copy we will overwrite the existing underlying array
dst := make([]byte, len(tx.r))
copy(dst, tx.r)
sig := append(dst, tx.s...)
sig = append(sig, tx.v-27)
pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
return pubkey
}
func (tx *Transaction) Sender() []byte {
pubkey := tx.PublicKey()
// Validate the returned key.
// Return nil if public key isn't in full format
if pubkey[0] != 4 {
return nil
}
return ethutil.Sha3Bin(pubkey[1:])[12:]
}
func (tx *Transaction) Sign(privk []byte) error {
sig := tx.Signature(privk)
tx.r = sig[:32]
tx.s = sig[32:64]
tx.v = sig[64] + 27
return nil
}
func (tx *Transaction) RlpData() interface{} {
// Prepare the transaction for serialization
return []interface{}{
tx.Nonce,
tx.Recipient,
tx.Value,
ethutil.NewSliceValue(tx.Data).Slice(),
tx.v,
tx.r,
tx.s,
}
}
func (tx *Transaction) RlpValue() *ethutil.Value {
return ethutil.NewValue(tx.RlpData())
}
func (tx *Transaction) RlpEncode() []byte {
return tx.RlpValue().Encode()
}
func (tx *Transaction) RlpDecode(data []byte) {
tx.RlpValueDecode(ethutil.NewValueFromBytes(data))
}
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
tx.Nonce = decoder.Get(0).Uint()
tx.Recipient = decoder.Get(1).Bytes()
tx.Value = decoder.Get(2).BigInt()
d := decoder.Get(3)
tx.Data = make([]string, d.Len())
for i := 0; i < d.Len(); i++ {
tx.Data[i] = d.Get(i).Str()
}
// TODO something going wrong here
tx.v = byte(decoder.Get(4).Uint())
tx.r = decoder.Get(5).Bytes()
tx.s = decoder.Get(6).Bytes()
}

View File

@ -0,0 +1,219 @@
package ethchain
import (
"bytes"
"container/list"
"errors"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"log"
"math/big"
"sync"
)
const (
txPoolQueueSize = 50
)
type TxPoolHook chan *Transaction
func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction {
for e := pool.Front(); e != nil; e = e.Next() {
if tx, ok := e.Value.(*Transaction); ok {
if finder(tx, e) {
return tx
}
}
}
return nil
}
type PublicSpeaker interface {
Broadcast(msgType ethwire.MsgType, data []interface{})
}
// The tx pool a thread safe transaction pool handler. In order to
// guarantee a non blocking pool we use a queue channel which can be
// independently read without needing access to the actual pool. If the
// pool is being drained or synced for whatever reason the transactions
// will simple queue up and handled when the mutex is freed.
type TxPool struct {
//server *Server
Speaker PublicSpeaker
// The mutex for accessing the Tx pool.
mutex sync.Mutex
// Queueing channel for reading and writing incoming
// transactions to
queueChan chan *Transaction
// Quiting channel
quit chan bool
// The actual pool
pool *list.List
BlockManager *BlockManager
Hook TxPoolHook
}
func NewTxPool() *TxPool {
return &TxPool{
//server: s,
mutex: sync.Mutex{},
pool: list.New(),
queueChan: make(chan *Transaction, txPoolQueueSize),
quit: make(chan bool),
}
}
// Blocking function. Don't use directly. Use QueueTransaction instead
func (pool *TxPool) addTransaction(tx *Transaction) {
pool.mutex.Lock()
pool.pool.PushBack(tx)
pool.mutex.Unlock()
// Broadcast the transaction to the rest of the peers
pool.Speaker.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()})
}
// Process transaction validates the Tx and processes funds from the
// sender to the recipient.
func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) {
log.Printf("[TXPL] Processing Tx %x\n", tx.Hash())
defer func() {
if r := recover(); r != nil {
log.Println(r)
err = fmt.Errorf("%v", r)
}
}()
// Get the sender
sender := block.GetAddr(tx.Sender())
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
if sender.Amount.Cmp(totAmount) < 0 {
return errors.New("Insufficient amount in sender's account")
}
if sender.Nonce != tx.Nonce {
if ethutil.Config.Debug {
return fmt.Errorf("Invalid nonce %d(%d) continueing anyway", tx.Nonce, sender.Nonce)
} else {
return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce)
}
}
// Subtract the amount from the senders account
sender.Amount.Sub(sender.Amount, totAmount)
sender.Nonce += 1
// Get the receiver
receiver := block.GetAddr(tx.Recipient)
// Add the amount to receivers account which should conclude this transaction
receiver.Amount.Add(receiver.Amount, tx.Value)
block.UpdateAddr(tx.Sender(), sender)
block.UpdateAddr(tx.Recipient, receiver)
return
}
func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
// Get the last block so we can retrieve the sender and receiver from
// the merkle trie
block := pool.BlockManager.BlockChain().CurrentBlock
// Something has gone horribly wrong if this happens
if block == nil {
return errors.New("No last block on the block chain")
}
// Get the sender
sender := block.GetAddr(tx.Sender())
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
if sender.Amount.Cmp(totAmount) < 0 {
return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender())
}
// Increment the nonce making each tx valid only once to prevent replay
// attacks
return nil
}
func (pool *TxPool) queueHandler() {
out:
for {
select {
case tx := <-pool.queueChan:
hash := tx.Hash()
foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool {
return bytes.Compare(tx.Hash(), hash) == 0
})
if foundTx != nil {
break
}
// Validate the transaction
err := pool.ValidateTransaction(tx)
if err != nil {
if ethutil.Config.Debug {
log.Println("Validating Tx failed", err)
}
} else {
// Call blocking version. At this point it
// doesn't matter since this is a goroutine
pool.addTransaction(tx)
if pool.Hook != nil {
pool.Hook <- tx
}
}
case <-pool.quit:
break out
}
}
}
func (pool *TxPool) QueueTransaction(tx *Transaction) {
pool.queueChan <- tx
}
func (pool *TxPool) Flush() []*Transaction {
pool.mutex.Lock()
defer pool.mutex.Unlock()
txList := make([]*Transaction, pool.pool.Len())
i := 0
for e := pool.pool.Front(); e != nil; e = e.Next() {
if tx, ok := e.Value.(*Transaction); ok {
txList[i] = tx
}
i++
}
// Recreate a new list all together
// XXX Is this the fastest way?
pool.pool = list.New()
return txList
}
func (pool *TxPool) Start() {
go pool.queueHandler()
}
func (pool *TxPool) Stop() {
log.Println("[TXP] Stopping...")
close(pool.quit)
pool.Flush()
}

View File

@ -0,0 +1,54 @@
package ethchain
import (
"encoding/hex"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
func TestAddressRetrieval(t *testing.T) {
// TODO
// 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f
key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")
tx := &Transaction{
Nonce: 0,
Recipient: ZeroHash160,
Value: big.NewInt(0),
Data: nil,
}
//fmt.Printf("rlp %x\n", tx.RlpEncode())
//fmt.Printf("sha rlp %x\n", tx.Hash())
tx.Sign(key)
//fmt.Printf("hex tx key %x\n", tx.PublicKey())
//fmt.Printf("seder %x\n", tx.Sender())
}
func TestAddressRetrieval2(t *testing.T) {
// TODO
// 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f
key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4")
addr, _ := hex.DecodeString("944400f4b88ac9589a0f17ed4671da26bddb668b")
tx := &Transaction{
Nonce: 0,
Recipient: addr,
Value: big.NewInt(1000),
Data: nil,
}
tx.Sign(key)
//data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7")
//tx := NewTransactionFromData(data)
fmt.Println(tx.RlpValue())
fmt.Printf("rlp %x\n", tx.RlpEncode())
fmt.Printf("sha rlp %x\n", tx.Hash())
//tx.Sign(key)
fmt.Printf("hex tx key %x\n", tx.PublicKey())
fmt.Printf("seder %x\n", tx.Sender())
}