From 066940f134170ab4b0901887b69f824418c322fc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:30:21 +0100 Subject: Defer undo on the current block's state --- ethchain/block_manager.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 8b237a29a..d9cdcd2d9 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -103,6 +103,11 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { // Processing a blocks may never happen simultaneously bm.mutex.Lock() defer bm.mutex.Unlock() + // Defer the Undo on the Trie. If the block processing happened + // we don't want to undo but since undo only happens on dirty + // nodes this won't happen because Commit would have been called + // before that. + defer bm.bc.CurrentBlock.State().Undo() hash := block.Hash() -- cgit v1.2.3 From a5b7279cb507de93fde39d86c414e417f2d0b3e3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:31:31 +0100 Subject: Changed uncle block fee as to what it should be --- ethchain/fees.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/fees.go b/ethchain/fees.go index 8f1646ab4..57017cdc9 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -13,7 +13,13 @@ 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 BlockReward *big.Int = big.NewInt(1.5e+18) + +var UncleReward *big.Int = big.NewInt(1.125e+18) + +//var UncleReward *big.Int = big.NewInt(2e18) +var UncleInclusionReward *big.Int = big.NewInt(1.875e+17) + var Period1Reward *big.Int = new(big.Int) var Period2Reward *big.Int = new(big.Int) var Period3Reward *big.Int = new(big.Int) -- cgit v1.2.3 From bb3e28310ee3c2cfc5b3153510d4a1d220a22e81 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:31:51 +0100 Subject: If sender is receiver only subtract the fee --- ethchain/transaction_pool.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index c2d65a2a7..75a8aa5d1 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -106,17 +106,25 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } } - // Subtract the amount from the senders account - sender.Amount.Sub(sender.Amount, totAmount) - sender.Nonce += 1 - // Get the receiver receiver := block.GetAddr(tx.Recipient) - // Add the amount to receivers account which should conclude this transaction - receiver.Amount.Add(receiver.Amount, tx.Value) + sender.Nonce += 1 + + // Send Tx to self + if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + // Subtract the fee + sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat)) + } else { + // Subtract the amount from the senders account + sender.Amount.Sub(sender.Amount, totAmount) + + // Add the amount to receivers account which should conclude this transaction + receiver.Amount.Add(receiver.Amount, tx.Value) + + block.UpdateAddr(tx.Recipient, receiver) + } block.UpdateAddr(tx.Sender(), sender) - block.UpdateAddr(tx.Recipient, receiver) return } -- cgit v1.2.3 From 8629d9a4187c2027e565a50d763f949993ab169c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:33:15 +0100 Subject: String changed and removed some debugging code --- ethchain/block.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 0678f64e2..34ddf9fec 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -135,7 +135,7 @@ func (block *Block) GetContract(addr []byte) *Contract { } func (block *Block) UpdateContract(addr []byte, contract *Contract) { // Make sure the state is synced - contract.State().Sync() + //contract.State().Sync() block.state.Update(string(addr), string(contract.RlpEncode())) } @@ -298,12 +298,6 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { tx := NewTransactionFromValue(txes.Get(i)) block.transactions[i] = tx - - /* - if ethutil.Config.Debug { - ethutil.Config.Db.Put(tx.Hash(), ethutil.Encode(tx)) - } - */ } } @@ -335,7 +329,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { } func (block *Block) String() string { - return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce) + return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) } //////////// UNEXPORTED ///////////////// -- cgit v1.2.3 From 68028f492f092f0546c2c084c1694ee6bf43b34e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:33:26 +0100 Subject: Fixed block handling --- ethchain/block_chain.go | 7 +++---- ethchain/block_manager.go | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 20 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 54f48bc60..5b55782a9 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -104,7 +104,6 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { currentHash = block.PrevHash chain = append(chain, block.Value().Val) - //chain = append([]interface{}{block.RlpValue().Value}, chain...) num-- } @@ -141,7 +140,9 @@ func (bc *BlockChain) Add(block *Block) { bc.CurrentBlock = block bc.LastBlockHash = block.Hash() - ethutil.Config.Db.Put(block.Hash(), block.RlpEncode()) + encodedBlock := block.RlpEncode() + ethutil.Config.Db.Put(block.Hash(), encodedBlock) + ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) } func (bc *BlockChain) GetBlock(hash []byte) *Block { @@ -177,8 +178,6 @@ func (bc *BlockChain) writeBlockInfo(block *Block) { func (bc *BlockChain) Stop() { if bc.CurrentBlock != nil { - ethutil.Config.Db.Put([]byte("LastBlock"), bc.CurrentBlock.RlpEncode()) - log.Println("[CHAIN] Stopped") } } diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index d9cdcd2d9..092e3dea5 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" "github.com/obscuren/secp256k1-go" "log" "math" @@ -18,10 +19,6 @@ 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 @@ -48,7 +45,7 @@ func AddTestNetFunds(block *Block) { "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin "93658b04240e4bd4046fd2d6d417d20f146f4b43", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit - "80c01a26338f0d905e295fccb71fa9ea849ffa12", // Alex + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex } { //log.Println("2^200 Wei to", addr) codedAddr, _ := hex.DecodeString(addr) @@ -70,14 +67,17 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { if bm.bc.CurrentBlock == nil { AddTestNetFunds(bm.bc.genesisBlock) + + bm.bc.genesisBlock.State().Sync() // Prepare the genesis block bm.bc.Add(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() } + log.Printf("Last block: %x\n", bm.bc.CurrentBlock.Hash()) + return bm } @@ -115,12 +115,6 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { 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 { @@ -142,13 +136,12 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { } 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 + // Sync the current block's state to the database and cancelling out the deferred Undo bm.bc.CurrentBlock.State().Sync() // Add the block to the chain bm.bc.Add(block) @@ -172,7 +165,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { */ // Broadcast the valid block back to the wire - //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.RlpValue().Value}) + bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) // If there's a block processor present, pass in the block for further // processing @@ -251,6 +244,18 @@ func (bm *BlockManager) ValidateBlock(block *Block) error { return nil } +func CalculateBlockReward(block *Block, uncleLength int) *big.Int { + base := new(big.Int) + for i := 0; i < uncleLength; i++ { + base.Add(base, UncleInclusionReward) + } + return base.Add(base, BlockReward) +} + +func CalculateUncleReward(block *Block) *big.Int { + return UncleReward +} + func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { // Get the coinbase rlp data addr := processor.GetAddr(block.Coinbase) @@ -259,7 +264,12 @@ func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error processor.UpdateAddr(block.Coinbase, addr) - // TODO Reward each uncle + for _, uncle := range block.Uncles { + uncleAddr := processor.GetAddr(uncle.Coinbase) + uncleAddr.AddFee(CalculateUncleReward(uncle)) + + processor.UpdateAddr(uncle.Coinbase, uncleAddr) + } return nil } -- cgit v1.2.3 From c866fcc5b37b53e0d11c1fd7e6cb971859537f2c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 12:10:21 +0100 Subject: Added new address --- ethchain/block_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 092e3dea5..4e72f51ba 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -43,7 +43,7 @@ type BlockManager struct { func AddTestNetFunds(block *Block) { for _, addr := range []string{ "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin - "93658b04240e4bd4046fd2d6d417d20f146f4b43", // Jeffrey + "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex } { -- cgit v1.2.3 From 4d405f665480fc9d0a0133161909856230f2f7a9 Mon Sep 17 00:00:00 2001 From: Sam Boyer Date: Tue, 18 Feb 2014 10:40:58 -0500 Subject: s/GenisisHeader/GenesisHeader/ --- ethchain/genesis.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 060d347e4..935978a69 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -13,7 +13,7 @@ var ZeroHash256 = make([]byte, 32) var ZeroHash160 = make([]byte, 20) var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) -var GenisisHeader = []interface{}{ +var GenesisHeader = []interface{}{ // Previous hash (none) //"", ZeroHash256, @@ -36,4 +36,4 @@ var GenisisHeader = []interface{}{ ethutil.Sha3Bin(big.NewInt(42).Bytes()), } -var Genesis = []interface{}{GenisisHeader, []interface{}{}, []interface{}{}} +var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}} -- cgit v1.2.3 From 24f2b2afc3a848190822c382e6aa31c8ab120f07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 11:35:17 +0100 Subject: Running contracts fixed --- ethchain/block.go | 53 +++++++++++++++++++++++++----- ethchain/block_manager.go | 35 +++++++++++++------- ethchain/block_manager_test.go | 74 ++++++++---------------------------------- ethchain/stack.go | 9 ++++- ethchain/transaction.go | 5 ++- ethchain/transaction_test.go | 16 ++++----- 6 files changed, 101 insertions(+), 91 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 34ddf9fec..ae654b7d8 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -46,6 +46,8 @@ type Block struct { // List of transactions and/or contracts transactions []*Transaction TxSha []byte + + contractStates map[string]*ethutil.Trie } // New block takes a raw encoded string @@ -79,14 +81,15 @@ func CreateBlock(root interface{}, block := &Block{ // Slice of transactions to include in this block - transactions: txes, - PrevHash: prevHash, - Coinbase: base, - Difficulty: Difficulty, - Nonce: Nonce, - Time: time.Now().Unix(), - Extra: extra, - UncleSha: EmptyShaList, + transactions: txes, + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + contractStates: make(map[string]*ethutil.Trie), } block.SetTransactions(txes) block.SetUncles([]*Block{}) @@ -131,6 +134,13 @@ func (block *Block) GetContract(addr []byte) *Contract { contract := &Contract{} contract.RlpDecode([]byte(data)) + cachedState := block.contractStates[string(addr)] + if cachedState != nil { + contract.state = cachedState + } else { + block.contractStates[string(addr)] = contract.state + } + return contract } func (block *Block) UpdateContract(addr []byte, contract *Contract) { @@ -190,6 +200,25 @@ func (block *Block) BlockInfo() BlockInfo { return bi } +// Sync the block's state and contract respectively +func (block *Block) Sync() { + // Sync all contracts currently in cache + for _, val := range block.contractStates { + val.Sync() + } + // Sync the block state itself + block.state.Sync() +} + +func (block *Block) Undo() { + // Sync all contracts currently in cache + for _, val := range block.contractStates { + val.Undo() + } + // Sync the block state itself + block.state.Undo() +} + func (block *Block) MakeContract(tx *Transaction) { // Create contract if there's no recipient if tx.IsContract() { @@ -199,9 +228,14 @@ func (block *Block) MakeContract(tx *Transaction) { 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) + if len(val) > 0 { + bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) + contract.state.Update(string(bytNum), val) + } } block.UpdateContract(addr, contract) + + block.contractStates[string(addr)] = contract.state } } @@ -288,6 +322,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.Time = int64(header.Get(6).BigInt().Uint64()) block.Extra = header.Get(7).Str() block.Nonce = header.Get(8).Bytes() + block.contractStates = make(map[string]*ethutil.Trie) // Tx list might be empty if this is an uncle. Uncles only have their // header set. diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 4e72f51ba..33df338ff 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -107,7 +107,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { // we don't want to undo but since undo only happens on dirty // nodes this won't happen because Commit would have been called // before that. - defer bm.bc.CurrentBlock.State().Undo() + defer bm.bc.CurrentBlock.Undo() hash := block.Hash() @@ -142,7 +142,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { // Calculate the new total difficulty and sync back to the db if bm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - bm.bc.CurrentBlock.State().Sync() + bm.bc.CurrentBlock.Sync() // Add the block to the chain bm.bc.Add(block) @@ -280,11 +280,13 @@ func (bm *BlockManager) 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) - } - }() + /* + 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 { @@ -305,6 +307,7 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac blockInfo := bm.bc.BlockInfo(block) contract := block.GetContract(tx.Hash()) + if contract == nil { fmt.Println("Contract not found") return @@ -313,7 +316,7 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac Pow256 := ethutil.BigPow(2, 256) if ethutil.Config.Debug { - fmt.Printf("# op arg\n") + fmt.Printf("# op\n") } out: for { @@ -321,9 +324,11 @@ out: 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))) + nb := ethutil.BigToBytes(big.NewInt(int64(pc)), 256) + r := contract.State().Get(string(nb)) + v := ethutil.NewValueFromBytes([]byte(r)) + //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) + o := v.Uint() op := OpCode(o) if !cb(0) { @@ -575,7 +580,10 @@ out: case oSSTORE: // Store Y at index X x, y := bm.stack.Popn() - contract.State().Update(x.String(), string(ethutil.Encode(y))) + idx := ethutil.BigToBytes(x, 256) + val := ethutil.NewValue(y) + //fmt.Printf("STORING VALUE: %v @ %v\n", val.BigInt(), ethutil.BigD(idx)) + contract.State().Update(string(idx), string(val.Encode())) 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) @@ -617,7 +625,10 @@ out: bm.TransactionPool.QueueTransaction(tx) case oSUICIDE: //addr := bm.stack.Pop() + default: + fmt.Println("Invalid OPCODE", op) } + //bm.stack.Print() pc++ } } diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index 502c50b97..ae29e2e25 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -1,75 +1,29 @@ package ethchain -/* import ( _ "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "math/big" "testing" ) func TestVm(t *testing.T) { InitFees() + ethutil.ReadConfig("") - db, _ := NewMemDatabase() - Db = db + db, _ := ethdb.NewMemDatabase() + ethutil.Config.Db = db + bm := NewBlockManager(nil) - 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", + block := bm.bc.genesisBlock + ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), []string{ + "PUSH", + "1", + "PUSH", + "2", "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) + bm.ApplyTransactions(block, []*Transaction{ctrct}) } -*/ diff --git a/ethchain/stack.go b/ethchain/stack.go index c80d01e5c..02834bd78 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -163,5 +163,12 @@ func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } func (st *Stack) Print() { - fmt.Println(st.data) + fmt.Println("# val (STACK)") + if len(st.data) > 0 { + for i, val := range st.data { + fmt.Printf("%-3d %v\n", i, val) + } + } else { + fmt.Println("-- empty --") + } } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 1a9258201..46f5e7e4c 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,11 +1,14 @@ package ethchain import ( + "bytes" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" ) +var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + type Transaction struct { Nonce uint64 Recipient []byte @@ -65,7 +68,7 @@ func (tx *Transaction) Hash() []byte { } func (tx *Transaction) IsContract() bool { - return len(tx.Recipient) == 0 + return bytes.Compare(tx.Recipient, ContractAddr) == 0 } func (tx *Transaction) Signature(key []byte) []byte { diff --git a/ethchain/transaction_test.go b/ethchain/transaction_test.go index c9090b83d..a49768aea 100644 --- a/ethchain/transaction_test.go +++ b/ethchain/transaction_test.go @@ -2,8 +2,6 @@ package ethchain import ( "encoding/hex" - "fmt" - "github.com/ethereum/eth-go/ethutil" "math/big" "testing" ) @@ -42,13 +40,15 @@ func TestAddressRetrieval2(t *testing.T) { tx.Sign(key) //data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7") //tx := NewTransactionFromData(data) - fmt.Println(tx.RlpValue()) + /* + fmt.Println(tx.RlpValue()) - fmt.Printf("rlp %x\n", tx.RlpEncode()) - fmt.Printf("sha rlp %x\n", tx.Hash()) + fmt.Printf("rlp %x\n", tx.RlpEncode()) + fmt.Printf("sha rlp %x\n", tx.Hash()) - //tx.Sign(key) + //tx.Sign(key) - fmt.Printf("hex tx key %x\n", tx.PublicKey()) - fmt.Printf("seder %x\n", tx.Sender()) + fmt.Printf("hex tx key %x\n", tx.PublicKey()) + fmt.Printf("seder %x\n", tx.Sender()) + */ } -- cgit v1.2.3 From b3da104e569e15c710e6b95ac00c9c2fc80bc9ae Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:26:35 +0100 Subject: Corrected contract addresses --- ethchain/block.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index ae654b7d8..0b4f93e8c 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -222,7 +222,7 @@ func (block *Block) Undo() { func (block *Block) MakeContract(tx *Transaction) { // Create contract if there's no recipient if tx.IsContract() { - addr := tx.Hash() + addr := tx.Hash()[12:] value := tx.Value contract := NewContract(value, []byte("")) -- cgit v1.2.3 From 8e7daec886aed591436be111f2b199932b35ddba Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:26:55 +0100 Subject: Added fees and debugging --- ethchain/block_manager.go | 54 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 33df338ff..1fcc06be4 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -301,12 +301,12 @@ func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { // Contract evaluation is done here. func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallback) { - + addr := tx.Hash()[12:] // Instruction pointer pc := 0 blockInfo := bm.bc.BlockInfo(block) - contract := block.GetContract(tx.Hash()) + contract := block.GetContract(addr) if contract == nil { fmt.Println("Contract not found") @@ -318,8 +318,12 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac if ethutil.Config.Debug { fmt.Printf("# op\n") } + + stepcount := 0 + totalFee := new(big.Int) out: for { + stepcount++ // 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? @@ -331,12 +335,40 @@ out: o := v.Uint() op := OpCode(o) + var fee *big.Int = new(big.Int) + if stepcount > 16 { + fee.Add(fee, StepFee) + } + + // Calculate the fees + switch op { + /* + FIXME (testnet requires no funds yet) + case oSSTORE: + fee.Add(fee, StoreFee) + case oSLOAD: + fee.Add(fee, StoreFee) + */ + case oEXTRO, oBALANCE: + fee.Add(fee, ExtroFee) + case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: + fee.Add(fee, CryptoFee) + case oMKTX: + fee.Add(fee, ContractFee) + } + + if contract.Amount.Cmp(fee) < 0 { + break + } + // Add the fee to the total fee. It's subtracted when we're done looping + totalFee.Add(totalFee, fee) + if !cb(0) { break } if ethutil.Config.Debug { - fmt.Printf("%-3d %-4s\n", pc, op.String()) + fmt.Printf("%-3d %-4s", pc, op.String()) } switch op { @@ -453,10 +485,6 @@ out: } 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: @@ -579,11 +607,10 @@ out: } case oSSTORE: // Store Y at index X - x, y := bm.stack.Popn() + y, x := bm.stack.Popn() idx := ethutil.BigToBytes(x, 256) - val := ethutil.NewValue(y) - //fmt.Printf("STORING VALUE: %v @ %v\n", val.BigInt(), ethutil.BigD(idx)) - contract.State().Update(string(idx), string(val.Encode())) + fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(idx)) + contract.State().Update(string(idx), string(y.Bytes())) 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) @@ -628,9 +655,12 @@ out: default: fmt.Println("Invalid OPCODE", op) } - //bm.stack.Print() + fmt.Println("") + bm.stack.Print() pc++ } + + block.UpdateContract(addr, contract) } // Returns an address from the specified contract's address -- cgit v1.2.3 From dc994b35189950a15fc5397b7f17cda2ba62e0c3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:27:08 +0100 Subject: Changed fee structure --- ethchain/fees.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/fees.go b/ethchain/fees.go index 57017cdc9..0096871d1 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -4,20 +4,18 @@ import ( "math/big" ) -var StepFee *big.Int = new(big.Int) var TxFeeRat *big.Int = big.NewInt(100000000000000) + var TxFee *big.Int = big.NewInt(100) -var ContractFee *big.Int = new(big.Int) -var MemFee *big.Int = new(big.Int) -var DataFee *big.Int = new(big.Int) -var CryptoFee *big.Int = new(big.Int) -var ExtroFee *big.Int = new(big.Int) +var StepFee *big.Int = big.NewInt(1) +var StoreFee *big.Int = big.NewInt(0) +var DataFee *big.Int = big.NewInt(20) +var ExtroFee *big.Int = big.NewInt(40) +var CryptoFee *big.Int = big.NewInt(20) +var ContractFee *big.Int = big.NewInt(100) var BlockReward *big.Int = big.NewInt(1.5e+18) - var UncleReward *big.Int = big.NewInt(1.125e+18) - -//var UncleReward *big.Int = big.NewInt(2e18) var UncleInclusionReward *big.Int = big.NewInt(1.875e+17) var Period1Reward *big.Int = new(big.Int) @@ -26,6 +24,12 @@ var Period3Reward *big.Int = new(big.Int) var Period4Reward *big.Int = new(big.Int) func InitFees() { + StepFee.Mul(StepFee, TxFeeRat) + StoreFee.Mul(StoreFee, TxFeeRat) + DataFee.Mul(DataFee, TxFeeRat) + ExtroFee.Mul(ExtroFee, TxFeeRat) + CryptoFee.Mul(CryptoFee, TxFeeRat) + ContractFee.Mul(ContractFee, TxFeeRat) /* // Base for 2**64 b60 := new(big.Int) -- cgit v1.2.3 From 39b6eaf51cc278feb817570e7fe02fc7ceefeb9e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:27:35 +0100 Subject: Debug logging functions --- ethchain/stack.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index 02834bd78..74f3d7ec9 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -163,7 +163,7 @@ func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } func (st *Stack) Print() { - fmt.Println("# val (STACK)") + fmt.Println("### STACK ###") if len(st.data) > 0 { for i, val := range st.data { fmt.Printf("%-3d %v\n", i, val) @@ -171,4 +171,5 @@ func (st *Stack) Print() { } else { fmt.Println("-- empty --") } + fmt.Println("#############") } -- cgit v1.2.3 From 504d356232e11e98a19f9f2b6fd5ee61a5226b1d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:10:16 +0100 Subject: Added peek(n) --- ethchain/stack.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index 74f3d7ec9..e08f84082 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -159,6 +159,22 @@ func (st *Stack) Popn() (*big.Int, *big.Int) { return ints[0], ints[1] } +func (st *Stack) Peek() *big.Int { + s := len(st.data) + + str := st.data[s-1] + + return str +} + +func (st *Stack) Peekn() (*big.Int, *big.Int) { + s := len(st.data) + + ints := st.data[s-2:] + + return ints[0], ints[1] +} + func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } -- cgit v1.2.3 From 8f69c2ac45a1109985ad8cc3b98dcd2e315dc8e9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:10:36 +0100 Subject: Added contract addr acessors --- ethchain/contract.go | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'ethchain') diff --git a/ethchain/contract.go b/ethchain/contract.go index 70189593b..5dccb8728 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -30,6 +30,14 @@ func (c *Contract) RlpDecode(data []byte) { c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()) } +func (c *Contract) Addr(addr []byte) *ethutil.Value { + return ethutil.NewValueFromBytes([]byte(c.state.Get(string(addr)))) +} + +func (c *Contract) SetAddr(addr []byte, value interface{}) { + c.state.Update(string(addr), string(ethutil.NewValue(value).Encode())) +} + func (c *Contract) State() *ethutil.Trie { return c.state } -- cgit v1.2.3 From ed05779adb27d715b52de99022b6d927e5fe4706 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:10:43 +0100 Subject: Updated fees --- ethchain/fees.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/fees.go b/ethchain/fees.go index 0096871d1..02f09fa04 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -8,7 +8,7 @@ var TxFeeRat *big.Int = big.NewInt(100000000000000) var TxFee *big.Int = big.NewInt(100) var StepFee *big.Int = big.NewInt(1) -var StoreFee *big.Int = big.NewInt(0) +var StoreFee *big.Int = big.NewInt(5) var DataFee *big.Int = big.NewInt(20) var ExtroFee *big.Int = big.NewInt(40) var CryptoFee *big.Int = big.NewInt(20) -- cgit v1.2.3 From 06ea7fc8308265e80b24352f676315ed4c826b6a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:11:17 +0100 Subject: re: Added contract fees --- ethchain/block_manager.go | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 1fcc06be4..1847ba2d4 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -336,19 +336,23 @@ out: op := OpCode(o) var fee *big.Int = new(big.Int) + var fee2 *big.Int = new(big.Int) if stepcount > 16 { fee.Add(fee, StepFee) } // Calculate the fees switch op { - /* - FIXME (testnet requires no funds yet) - case oSSTORE: - fee.Add(fee, StoreFee) - case oSLOAD: - fee.Add(fee, StoreFee) - */ + case oSSTORE: + y, x := bm.stack.Peekn() + val := contract.Addr(ethutil.BigToBytes(x, 256)) + if val.IsEmpty() && len(y.Bytes()) > 0 { + fee2.Add(DataFee, StoreFee) + } else { + fee2.Sub(DataFee, StoreFee) + } + case oSLOAD: + fee.Add(fee, StoreFee) case oEXTRO, oBALANCE: fee.Add(fee, ExtroFee) case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: @@ -357,11 +361,12 @@ out: fee.Add(fee, ContractFee) } - if contract.Amount.Cmp(fee) < 0 { + tf := new(big.Int).Add(fee, fee2) + if contract.Amount.Cmp(tf) < 0 { break } // Add the fee to the total fee. It's subtracted when we're done looping - totalFee.Add(totalFee, fee) + totalFee.Add(totalFee, tf) if !cb(0) { break @@ -608,9 +613,10 @@ out: case oSSTORE: // Store Y at index X y, x := bm.stack.Popn() - idx := ethutil.BigToBytes(x, 256) - fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(idx)) - contract.State().Update(string(idx), string(y.Bytes())) + addr := ethutil.BigToBytes(x, 256) + fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(addr)) + contract.SetAddr(addr, y) + //contract.State().Update(string(idx), string(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) -- cgit v1.2.3 From 681eacaa7fdda41fe168baba03095ee74708444f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:37:06 +0100 Subject: Removed old instruction code --- ethchain/transaction.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 46f5e7e4c..2417bbd7d 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -26,12 +26,9 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { // 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) - } + instr, _ := ethutil.CompileInstr(val) - tx.Data[i] = instr + tx.Data[i] = string(instr) } return &tx -- cgit v1.2.3 From 18cc35338afc8a3843716af0d96bd03d36e735ea Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:37:16 +0100 Subject: Fixed contract running --- ethchain/block_manager.go | 18 ++++++++++-------- ethchain/block_manager_test.go | 1 - 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 1847ba2d4..91bcaa468 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -321,19 +321,20 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac stepcount := 0 totalFee := new(big.Int) + + // helper function for getting a contract's memory address + getMem := func(num int) *ethutil.Value { + nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256) + return contract.Addr(nb) + } out: for { stepcount++ // 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 - nb := ethutil.BigToBytes(big.NewInt(int64(pc)), 256) - r := contract.State().Get(string(nb)) - v := ethutil.NewValueFromBytes([]byte(r)) + val := getMem(pc) //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) - o := v.Uint() - op := OpCode(o) + op := OpCode(val.Uint()) var fee *big.Int = new(big.Int) var fee2 *big.Int = new(big.Int) @@ -378,6 +379,7 @@ out: switch op { case oSTOP: + fmt.Println("") break out case oADD: x, y := bm.stack.Popn() @@ -580,7 +582,7 @@ out: case oECVALID: case oPUSH: pc++ - bm.stack.Push(bm.mem[strconv.Itoa(pc)]) + bm.stack.Push(getMem(pc).BigInt()) case oPOP: // Pop current value of the stack bm.stack.Pop() diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index ae29e2e25..853d459d8 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -22,7 +22,6 @@ func TestVm(t *testing.T) { "1", "PUSH", "2", - "STOP", }) bm.ApplyTransactions(block, []*Transaction{ctrct}) -- cgit v1.2.3 From cca8585554119a4dc02c6720948012bf876a1db8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 13:05:59 +0100 Subject: Get a chain of blocks made simple --- ethchain/block_chain.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 5b55782a9..21f540b96 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,6 +2,7 @@ package ethchain import ( "bytes" + "fmt" "github.com/ethereum/eth-go/ethutil" "log" "math" @@ -111,6 +112,25 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { return chain } +func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { + genHash := bc.genesisBlock.Hash() + + block := bc.GetBlock(hash) + var blocks []*Block + + for i := 0; i < amount && block != nil; block = bc.GetBlock(block.PrevHash) { + fmt.Println(block) + blocks = append([]*Block{block}, blocks...) + + if bytes.Compare(genHash, block.Hash()) == 0 { + break + } + i++ + } + + return blocks +} + func (bc *BlockChain) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { @@ -147,6 +167,9 @@ func (bc *BlockChain) Add(block *Block) { func (bc *BlockChain) GetBlock(hash []byte) *Block { data, _ := ethutil.Config.Db.Get(hash) + if len(data) == 0 { + return nil + } return NewBlockFromData(data) } -- cgit v1.2.3 From 73b9ae95797ce8c38d82cfcb7c793efea268f476 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 22 Feb 2014 01:53:25 +0100 Subject: Updated some of the log statements to use the ethutil logger --- ethchain/block_chain.go | 2 -- 1 file changed, 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 21f540b96..96d22366d 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,7 +2,6 @@ package ethchain import ( "bytes" - "fmt" "github.com/ethereum/eth-go/ethutil" "log" "math" @@ -119,7 +118,6 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { var blocks []*Block for i := 0; i < amount && block != nil; block = bc.GetBlock(block.PrevHash) { - fmt.Println(block) blocks = append([]*Block{block}, blocks...) if bytes.Compare(genHash, block.Hash()) == 0 { -- cgit v1.2.3 From c66cf95b4019eeaf49db0c02cc7cb73c78098f5e Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 23 Feb 2014 01:56:48 +0100 Subject: Added address states for storing a session based address --- ethchain/address.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++ ethchain/address_test.go | 8 +++++++ ethchain/block_manager.go | 36 ++++++++++++++++++++++------ 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 ethchain/address.go create mode 100644 ethchain/address_test.go (limited to 'ethchain') diff --git a/ethchain/address.go b/ethchain/address.go new file mode 100644 index 000000000..a228c7566 --- /dev/null +++ b/ethchain/address.go @@ -0,0 +1,60 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type Address struct { + Amount *big.Int + Nonce uint64 +} + +func NewAddress(amount *big.Int) *Address { + return &Address{Amount: amount, Nonce: 0} +} + +func NewAddressFromData(data []byte) *Address { + address := &Address{} + address.RlpDecode(data) + + return address +} + +func (a *Address) AddFee(fee *big.Int) { + a.Amount.Add(a.Amount, fee) +} + +func (a *Address) RlpEncode() []byte { + return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) +} + +func (a *Address) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + a.Amount = decoder.Get(0).BigInt() + a.Nonce = decoder.Get(1).Uint() +} + +type AddrStateStore struct { + states map[string]*AddressState +} + +func NewAddrStateStore() *AddrStateStore { + return &AddrStateStore{states: make(map[string]*AddressState)} +} + +func (s *AddrStateStore) Add(addr []byte, account *Address) *AddressState { + state := &AddressState{Nonce: account.Nonce, Account: account} + s.states[string(addr)] = state + return state +} + +func (s *AddrStateStore) Get(addr []byte) *AddressState { + return s.states[string(addr)] +} + +type AddressState struct { + Nonce uint64 + Account *Address +} diff --git a/ethchain/address_test.go b/ethchain/address_test.go new file mode 100644 index 000000000..161e1b251 --- /dev/null +++ b/ethchain/address_test.go @@ -0,0 +1,8 @@ +package ethchain + +import ( + "testing" +) + +func TestAddressState(t *testing.T) { +} diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 91bcaa468..b82e5a74a 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "fmt" "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" + _ "github.com/ethereum/eth-go/ethwire" "github.com/obscuren/secp256k1-go" "log" "math" @@ -19,6 +19,7 @@ type BlockProcessor interface { ProcessBlock(block *Block) } +// TODO rename to state manager type BlockManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex @@ -26,6 +27,10 @@ type BlockManager struct { // The block chain :) bc *BlockChain + // States for addresses. You can watch any address + // at any given time + addrStateStore *AddrStateStore + // Stack for processing contracts stack *Stack // non-persistent key/value memory storage @@ -58,11 +63,12 @@ func AddTestNetFunds(block *Block) { func NewBlockManager(speaker PublicSpeaker) *BlockManager { bm := &BlockManager{ //server: s, - bc: NewBlockChain(), - stack: NewStack(), - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Speaker: speaker, + bc: NewBlockChain(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Speaker: speaker, + addrStateStore: NewAddrStateStore(), } if bm.bc.CurrentBlock == nil { @@ -81,6 +87,22 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { return bm } +// Watches any given address and puts it in the address state store +func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { + account := bm.bc.CurrentBlock.GetAddr(addr) + + return bm.addrStateStore.Add(addr, account) +} + +func (bm *BlockManager) GetAddrState(addr []byte) *AddressState { + addrState := bm.addrStateStore.Get(addr) + if addrState == nil { + addrState = bm.WatchAddr(addr) + } + + return addrState +} + func (bm *BlockManager) BlockChain() *BlockChain { return bm.bc } @@ -165,7 +187,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { */ // Broadcast the valid block back to the wire - bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) // If there's a block processor present, pass in the block for further // processing -- cgit v1.2.3 From f5737b929a972102b16e4b206a52b1e36b508860 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 23 Feb 2014 01:57:04 +0100 Subject: Added a secondary processor --- ethchain/transaction_pool.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 75a8aa5d1..1278cc4dc 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -34,6 +34,10 @@ type PublicSpeaker interface { Broadcast(msgType ethwire.MsgType, data []interface{}) } +type TxProcessor interface { + ProcessTransaction(tx *Transaction) +} + // The tx pool a thread safe transaction pool handler. In order to // guarantee a non blocking pool we use a queue channel which can be // independently read without needing access to the actual pool. If the @@ -54,7 +58,7 @@ type TxPool struct { BlockManager *BlockManager - Hook TxPoolHook + SecondaryProcessor TxProcessor } func NewTxPool() *TxPool { @@ -69,12 +73,14 @@ func NewTxPool() *TxPool { // Blocking function. Don't use directly. Use QueueTransaction instead func (pool *TxPool) addTransaction(tx *Transaction) { + log.Println("Adding tx to pool") 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()}) + log.Println("broadcasting it") } // Process transaction validates the Tx and processes funds from the @@ -179,8 +185,8 @@ out: // doesn't matter since this is a goroutine pool.addTransaction(tx) - if pool.Hook != nil { - pool.Hook <- tx + if pool.SecondaryProcessor != nil { + pool.SecondaryProcessor.ProcessTransaction(tx) } } case <-pool.quit: -- cgit v1.2.3 From a4a4ffbeff2fd9082f2c96330ea0915ae1b6e6c1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 23 Feb 2014 01:57:22 +0100 Subject: Moved address --- ethchain/contract.go | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'ethchain') diff --git a/ethchain/contract.go b/ethchain/contract.go index 5dccb8728..68ec39f0b 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -41,34 +41,3 @@ func (c *Contract) SetAddr(addr []byte, value interface{}) { 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.NewValueFromBytes(data) - - a.Amount = decoder.Get(0).BigInt() - a.Nonce = decoder.Get(1).Uint() -} -- cgit v1.2.3 From 377c9951033d4f8d157221fd36d15c39ae17cddc Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:10:45 +0100 Subject: Separated the VM from the block manager and added states --- ethchain/state.go | 56 +++++++ ethchain/vm.go | 437 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ethchain/vm_test.go | 106 +++++++++++++ 3 files changed, 599 insertions(+) create mode 100644 ethchain/state.go create mode 100644 ethchain/vm.go create mode 100644 ethchain/vm_test.go (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go new file mode 100644 index 000000000..1a18ea1d7 --- /dev/null +++ b/ethchain/state.go @@ -0,0 +1,56 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type State struct { + trie *ethutil.Trie +} + +func NewState(trie *ethutil.Trie) *State { + return &State{trie: trie} +} + +func (s *State) GetContract(addr []byte) *Contract { + data := s.trie.Get(string(addr)) + if data == "" { + return nil + } + + contract := &Contract{} + contract.RlpDecode([]byte(data)) + + return contract +} + +func (s *State) UpdateContract(addr []byte, contract *Contract) { + s.trie.Update(string(addr), string(contract.RlpEncode())) +} + +func Compile(code []string) (script []string) { + script = make([]string, len(code)) + for i, val := range code { + instr, _ := ethutil.CompileInstr(val) + + script[i] = string(instr) + } + + return +} + +func (s *State) GetAccount(addr []byte) (account *Address) { + data := s.trie.Get(string(addr)) + if data == "" { + account = NewAddress(big.NewInt(0)) + } else { + account = NewAddressFromData([]byte(data)) + } + + return +} + +func (s *State) UpdateAccount(addr []byte, account *Address) { + s.trie.Update(string(addr), string(account.RlpEncode())) +} diff --git a/ethchain/vm.go b/ethchain/vm.go new file mode 100644 index 000000000..d5f4d7ad6 --- /dev/null +++ b/ethchain/vm.go @@ -0,0 +1,437 @@ +package ethchain + +import ( + "bytes" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" + "log" + "math" + "math/big" +) + +type Vm struct { + txPool *TxPool + // Stack for processing contracts + stack *Stack + // non-persistent key/value memory storage + mem map[string]*big.Int + + vars RuntimeVars +} + +type RuntimeVars struct { + address []byte + blockNumber uint64 + sender []byte + prevHash []byte + coinbase []byte + time int64 + diff *big.Int + txValue *big.Int + txData []string +} + +func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { + vm.mem = make(map[string]*big.Int) + vm.stack = NewStack() + + addr := vars.address // tx.Hash()[12:] + // Instruction pointer + pc := 0 + + if contract == nil { + fmt.Println("Contract not found") + return + } + + Pow256 := ethutil.BigPow(2, 256) + + if ethutil.Config.Debug { + fmt.Printf("# op\n") + } + + stepcount := 0 + totalFee := new(big.Int) + +out: + for { + stepcount++ + // The base big int for all calculations. Use this for any results. + base := new(big.Int) + val := contract.GetMem(pc) + //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) + op := OpCode(val.Uint()) + + var fee *big.Int = new(big.Int) + var fee2 *big.Int = new(big.Int) + if stepcount > 16 { + fee.Add(fee, StepFee) + } + + // Calculate the fees + switch op { + case oSSTORE: + y, x := vm.stack.Peekn() + val := contract.Addr(ethutil.BigToBytes(x, 256)) + if val.IsEmpty() && len(y.Bytes()) > 0 { + fee2.Add(DataFee, StoreFee) + } else { + fee2.Sub(DataFee, StoreFee) + } + case oSLOAD: + fee.Add(fee, StoreFee) + case oEXTRO, oBALANCE: + fee.Add(fee, ExtroFee) + case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: + fee.Add(fee, CryptoFee) + case oMKTX: + fee.Add(fee, ContractFee) + } + + tf := new(big.Int).Add(fee, fee2) + if contract.Amount.Cmp(tf) < 0 { + fmt.Println("Contract fee", ContractFee) + fmt.Println("Insufficient fees to continue running the contract", tf, contract.Amount) + break + } + // Add the fee to the total fee. It's subtracted when we're done looping + totalFee.Add(totalFee, tf) + + if ethutil.Config.Debug { + fmt.Printf("%-3d %-4s", pc, op.String()) + } + + switch op { + case oSTOP: + fmt.Println("") + break out + case oADD: + x, y := vm.stack.Popn() + // (x + y) % 2 ** 256 + base.Add(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base) + case oSUB: + x, y := vm.stack.Popn() + // (x - y) % 2 ** 256 + base.Sub(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base) + case oMUL: + x, y := vm.stack.Popn() + // (x * y) % 2 ** 256 + base.Mul(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base) + case oDIV: + x, y := vm.stack.Popn() + // floor(x / y) + base.Div(x, y) + // Pop result back on the stack + vm.stack.Push(base) + case oSDIV: + x, y := vm.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 + vm.stack.Push(z) + case oMOD: + x, y := vm.stack.Popn() + base.Mod(x, y) + vm.stack.Push(base) + case oSMOD: + x, y := vm.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 + vm.stack.Push(z) + case oEXP: + x, y := vm.stack.Popn() + base.Exp(x, y, Pow256) + + vm.stack.Push(base) + case oNEG: + base.Sub(Pow256, vm.stack.Pop()) + vm.stack.Push(base) + case oLT: + x, y := vm.stack.Popn() + // x < y + if x.Cmp(y) < 0 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oLE: + x, y := vm.stack.Popn() + // x <= y + if x.Cmp(y) < 1 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oGT: + x, y := vm.stack.Popn() + // x > y + if x.Cmp(y) > 0 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oGE: + x, y := vm.stack.Popn() + // x >= y + if x.Cmp(y) > -1 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oNOT: + x, y := vm.stack.Popn() + // x != y + if x.Cmp(y) != 0 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oMYADDRESS: + vm.stack.Push(ethutil.BigD(addr)) + case oTXSENDER: + vm.stack.Push(ethutil.BigD(vars.sender)) + case oTXVALUE: + vm.stack.Push(vars.txValue) + case oTXDATAN: + vm.stack.Push(big.NewInt(int64(len(vars.txData)))) + case oTXDATA: + v := vm.stack.Pop() + // v >= len(data) + if v.Cmp(big.NewInt(int64(len(vars.txData)))) >= 0 { + vm.stack.Push(ethutil.Big("0")) + } else { + vm.stack.Push(ethutil.Big(vars.txData[v.Uint64()])) + } + case oBLK_PREVHASH: + vm.stack.Push(ethutil.BigD(vars.prevHash)) + case oBLK_COINBASE: + vm.stack.Push(ethutil.BigD(vars.coinbase)) + case oBLK_TIMESTAMP: + vm.stack.Push(big.NewInt(vars.time)) + case oBLK_NUMBER: + vm.stack.Push(big.NewInt(int64(vars.blockNumber))) + case oBLK_DIFFICULTY: + vm.stack.Push(vars.diff) + 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(vars.diff) + 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)) + vm.stack.Push(x) + case oSHA256, oSHA3, oRIPEMD160: + // This is probably save + // ceil(pop / 32) + length := int(math.Ceil(float64(vm.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(vm.stack.Pop().Bytes(), 256) + data.WriteString(string(num)) + } + + if op == oSHA256 { + vm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes()))) + } else if op == oSHA3 { + vm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes()))) + } else { + vm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes()))) + } + case oECMUL: + y := vm.stack.Pop() + x := vm.stack.Pop() + //n := vm.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 + vm.stack.Push(ethutil.Big("0")) + vm.stack.Push(ethutil.Big("0")) + } + //} else { + // // Invalid, push infinity + // vm.stack.Push("0") + // vm.stack.Push("0") + //} + + case oECADD: + case oECSIGN: + case oECRECOVER: + case oECVALID: + case oPUSH: + pc++ + vm.stack.Push(contract.GetMem(pc).BigInt()) + case oPOP: + // Pop current value of the stack + vm.stack.Pop() + case oDUP: + // Dup top stack + x := vm.stack.Pop() + vm.stack.Push(x) + vm.stack.Push(x) + case oSWAP: + // Swap two top most values + x, y := vm.stack.Popn() + vm.stack.Push(y) + vm.stack.Push(x) + case oMLOAD: + x := vm.stack.Pop() + vm.stack.Push(vm.mem[x.String()]) + case oMSTORE: + x, y := vm.stack.Popn() + vm.mem[x.String()] = y + case oSLOAD: + // Load the value in storage and push it on the stack + x := vm.stack.Pop() + // decode the object as a big integer + decoder := ethutil.NewValueFromBytes([]byte(contract.State().Get(x.String()))) + if !decoder.IsNil() { + vm.stack.Push(decoder.BigInt()) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oSSTORE: + // Store Y at index X + y, x := vm.stack.Popn() + addr := ethutil.BigToBytes(x, 256) + fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(addr)) + contract.SetAddr(addr, y) + //contract.State().Update(string(idx), string(y)) + case oJMP: + x := int(vm.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 := vm.stack.Pop() + // Set pc to x if it's non zero + if x.Cmp(ethutil.BigFalse) != 0 { + pc = int(x.Uint64()) + pc-- + } + case oIND: + vm.stack.Push(big.NewInt(int64(pc))) + case oEXTRO: + memAddr := vm.stack.Pop() + contractAddr := vm.stack.Pop().Bytes() + + // Push the contract's memory on to the stack + vm.stack.Push(contractMemory(state, contractAddr, memAddr)) + case oBALANCE: + // Pushes the balance of the popped value on to the stack + account := state.GetAccount(vm.stack.Pop().Bytes()) + vm.stack.Push(account.Amount) + case oMKTX: + addr, value := vm.stack.Popn() + from, length := vm.stack.Popn() + + makeInlineTx(addr.Bytes(), value, from, length, contract, state) + case oSUICIDE: + recAddr := vm.stack.Pop().Bytes() + // Purge all memory + deletedMemory := contract.state.NewIterator().Purge() + // Add refunds to the pop'ed address + refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) + account := state.GetAccount(recAddr) + account.Amount.Add(account.Amount, refund) + // Update the refunding address + state.UpdateAccount(recAddr, account) + // Delete the contract + state.trie.Update(string(addr), "") + + fmt.Printf("(%d) => %x\n", deletedMemory, recAddr) + break out + default: + fmt.Printf("Invalid OPCODE: %x\n", op) + } + fmt.Println("") + vm.stack.Print() + pc++ + } + + state.UpdateContract(addr, contract) +} + +func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { + fmt.Printf(" => creating inline tx %x %v %v %v", addr, value, from, length) + j := 0 + dataItems := make([]string, int(length.Uint64())) + for i := from.Uint64(); i < length.Uint64(); i++ { + dataItems[j] = contract.GetMem(j).Str() + j++ + } + + tx := NewTransaction(addr, value, dataItems) + if tx.IsContract() { + contract := MakeContract(tx, state) + state.UpdateContract(tx.Hash()[12:], contract) + } else { + account := state.GetAccount(tx.Recipient) + account.Amount.Add(account.Amount, tx.Value) + state.UpdateAccount(tx.Recipient, account) + } +} + +// Returns an address from the specified contract's address +func contractMemory(state *State, contractAddr []byte, memAddr *big.Int) *big.Int { + contract := state.GetContract(contractAddr) + if contract == nil { + log.Panicf("invalid contract addr %x", contractAddr) + } + val := state.trie.Get(memAddr.String()) + + // decode the object as a big integer + decoder := ethutil.NewValueFromBytes([]byte(val)) + if decoder.IsNil() { + return ethutil.BigFalse + } + + return decoder.BigInt() +} diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go new file mode 100644 index 000000000..6ceb0ff15 --- /dev/null +++ b/ethchain/vm_test.go @@ -0,0 +1,106 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "math/big" + "testing" +) + +func TestRun(t *testing.T) { + InitFees() + + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + script := Compile([]string{ + "TXSENDER", + "SUICIDE", + }) + + tx := NewTransaction(ContractAddr, big.NewInt(1e17), script) + fmt.Printf("contract addr %x\n", tx.Hash()[12:]) + contract := MakeContract(tx, state) + vm := &Vm{} + + vm.Process(contract, state, RuntimeVars{ + address: tx.Hash()[12:], + blockNumber: 1, + sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + txValue: tx.Value, + txData: tx.Data, + }) +} + +func TestRun1(t *testing.T) { + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + script := Compile([]string{ + "PUSH", "0", + "PUSH", "0", + "TXSENDER", + "PUSH", "10000000", + "MKTX", + }) + fmt.Println(ethutil.NewValue(script)) + + tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) + fmt.Printf("contract addr %x\n", tx.Hash()[12:]) + contract := MakeContract(tx, state) + vm := &Vm{} + + vm.Process(contract, state, RuntimeVars{ + address: tx.Hash()[12:], + blockNumber: 1, + sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + txValue: tx.Value, + txData: tx.Data, + }) +} + +func TestRun2(t *testing.T) { + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + script := Compile([]string{ + "PUSH", "0", + "PUSH", "0", + "TXSENDER", + "PUSH", "10000000", + "MKTX", + }) + fmt.Println(ethutil.NewValue(script)) + + tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) + fmt.Printf("contract addr %x\n", tx.Hash()[12:]) + contract := MakeContract(tx, state) + vm := &Vm{} + + vm.Process(contract, state, RuntimeVars{ + address: tx.Hash()[12:], + blockNumber: 1, + sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + txValue: tx.Value, + txData: tx.Data, + }) +} -- cgit v1.2.3 From a3fb7008b2df860b01df71ef7da42b394570d1e2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:12:24 +0100 Subject: Added make contract --- ethchain/contract.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'ethchain') diff --git a/ethchain/contract.go b/ethchain/contract.go index 68ec39f0b..dbcbb3697 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -41,3 +41,31 @@ func (c *Contract) SetAddr(addr []byte, value interface{}) { func (c *Contract) State() *ethutil.Trie { return c.state } + +func (c *Contract) GetMem(num int) *ethutil.Value { + nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256) + + return c.Addr(nb) +} + +func MakeContract(tx *Transaction, state *State) *Contract { + // Create contract if there's no recipient + if tx.IsContract() { + addr := tx.Hash()[12:] + + value := tx.Value + contract := NewContract(value, []byte("")) + state.trie.Update(string(addr), string(contract.RlpEncode())) + for i, val := range tx.Data { + if len(val) > 0 { + bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) + contract.state.Update(string(bytNum), string(ethutil.Encode(val))) + } + } + state.trie.Update(string(addr), string(contract.RlpEncode())) + + return contract + } + + return nil +} -- cgit v1.2.3 From 4cc5b03137e513dd54e9feb07a564398ca53b342 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:12:32 +0100 Subject: Added opcodes --- ethchain/stack.go | 103 +++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 52 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index e08f84082..13b0f247b 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -9,57 +9,57 @@ type OpCode int // Op codes const ( - oSTOP OpCode = iota - oADD - oMUL - oSUB - oDIV - oSDIV - oMOD - oSMOD - oEXP - oNEG - oLT - oLE - oGT - oGE - oEQ - oNOT - oMYADDRESS - oTXSENDER - oTXVALUE - oTXFEE - oTXDATAN - oTXDATA - oBLK_PREVHASH - oBLK_COINBASE - oBLK_TIMESTAMP - oBLK_NUMBER - oBLK_DIFFICULTY - oBASEFEE - oSHA256 OpCode = 32 - oRIPEMD160 OpCode = 33 - oECMUL OpCode = 34 - oECADD OpCode = 35 - oECSIGN OpCode = 36 - oECRECOVER OpCode = 37 - oECVALID OpCode = 38 - oSHA3 OpCode = 39 - oPUSH OpCode = 48 - oPOP OpCode = 49 - oDUP OpCode = 50 - oSWAP OpCode = 51 - oMLOAD OpCode = 52 - oMSTORE OpCode = 53 - oSLOAD OpCode = 54 - oSSTORE OpCode = 55 - oJMP OpCode = 56 - oJMPI OpCode = 57 - oIND OpCode = 58 - oEXTRO OpCode = 59 - oBALANCE OpCode = 60 - oMKTX OpCode = 61 - oSUICIDE OpCode = 62 + oSTOP = 0x00 + oADD = 0x01 + oMUL = 0x02 + oSUB = 0x03 + oDIV = 0x04 + oSDIV = 0x05 + oMOD = 0x06 + oSMOD = 0x07 + oEXP = 0x08 + oNEG = 0x09 + oLT = 0x0a + oLE = 0x0b + oGT = 0x0c + oGE = 0x0d + oEQ = 0x0e + oNOT = 0x0f + oMYADDRESS = 0x10 + oTXSENDER = 0x11 + oTXVALUE = 0x12 + oTXDATAN = 0x13 + oTXDATA = 0x14 + oBLK_PREVHASH = 0x15 + oBLK_COINBASE = 0x16 + oBLK_TIMESTAMP = 0x17 + oBLK_NUMBER = 0x18 + oBLK_DIFFICULTY = 0x19 + oBLK_NONCE = 0x1a + oBASEFEE = 0x1b + oSHA256 = 0x20 + oRIPEMD160 = 0x21 + oECMUL = 0x22 + oECADD = 0x23 + oECSIGN = 0x24 + oECRECOVER = 0x25 + oECVALID = 0x26 + oSHA3 = 0x27 + oPUSH = 0x30 + oPOP = 0x31 + oDUP = 0x32 + oSWAP = 0x33 + oMLOAD = 0x34 + oMSTORE = 0x35 + oSLOAD = 0x36 + oSSTORE = 0x37 + oJMP = 0x38 + oJMPI = 0x39 + oIND = 0x3a + oEXTRO = 0x3b + oBALANCE = 0x3c + oMKTX = 0x3d + oSUICIDE = 0x3f ) // Since the opcodes aren't all in order we can't use a regular slice @@ -83,7 +83,6 @@ var opCodeToString = map[OpCode]string{ oMYADDRESS: "MYADDRESS", oTXSENDER: "TXSENDER", oTXVALUE: "TXVALUE", - oTXFEE: "TXFEE", oTXDATAN: "TXDATAN", oTXDATA: "TXDATA", oBLK_PREVHASH: "BLK_PREVHASH", -- cgit v1.2.3 From d8b5bbd48c8e989808058150137d9713d1936b18 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:13:22 +0100 Subject: Added compile --- ethchain/block_manager_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index 853d459d8..df3e56e5e 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -17,12 +17,13 @@ func TestVm(t *testing.T) { bm := NewBlockManager(nil) block := bm.bc.genesisBlock - ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), []string{ + script := Compile([]string{ "PUSH", "1", "PUSH", "2", "STOP", }) + ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), script) bm.ApplyTransactions(block, []*Transaction{ctrct}) } -- cgit v1.2.3 From d69db6e617478911e90f6627329012578bfd0fe5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:13:42 +0100 Subject: Removed compiling from the transaction --- ethchain/transaction.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2417bbd7d..39b2bda94 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -24,12 +24,7 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { tx.Nonce = 0 // Serialize the data - tx.Data = make([]string, len(data)) - for i, val := range data { - instr, _ := ethutil.CompileInstr(val) - - tx.Data[i] = string(instr) - } + tx.Data = data return &tx } -- cgit v1.2.3 From b29c1eecd104de58611b9a17a68b48321fd40e87 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:44:18 +0100 Subject: Removed debug print --- ethchain/vm.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index d5f4d7ad6..9abd9cd41 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -91,7 +91,6 @@ out: tf := new(big.Int).Add(fee, fee2) if contract.Amount.Cmp(tf) < 0 { - fmt.Println("Contract fee", ContractFee) fmt.Println("Insufficient fees to continue running the contract", tf, contract.Amount) break } @@ -392,7 +391,7 @@ out: fmt.Printf("Invalid OPCODE: %x\n", op) } fmt.Println("") - vm.stack.Print() + //vm.stack.Print() pc++ } -- cgit v1.2.3 From 88a9c62fccd16a782e7d7221daf6b6f207c22097 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:44:29 +0100 Subject: Proper tests --- ethchain/block_manager.go | 420 ++--------------------------------------- ethchain/block_manager_test.go | 10 +- 2 files changed, 24 insertions(+), 406 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index b82e5a74a..ad96f6a34 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -6,11 +6,8 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/ethereum/eth-go/ethwire" - "github.com/obscuren/secp256k1-go" "log" - "math" "math/big" - "strconv" "sync" "time" ) @@ -113,9 +110,12 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { // 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) + if contract := block.GetContract(tx.Recipient); contract != nil { + bm.ProcessContract(contract, tx, block) + } else { + bm.TransactionPool.ProcessTransaction(tx, block) + } } } } @@ -300,7 +300,7 @@ func (bm *BlockManager) Stop() { bm.bc.Stop() } -func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { +func (bm *BlockManager) ProcessContract(contract *Contract, tx *Transaction, block *Block) { // Recovering function in case the VM had any errors /* defer func() { @@ -310,402 +310,16 @@ func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { }() */ - // 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 + vm := &Vm{} + vm.Process(contract, NewState(block.state), RuntimeVars{ + address: tx.Hash()[12:], + blockNumber: block.BlockInfo().Number, + sender: tx.Sender(), + prevHash: block.PrevHash, + coinbase: block.Coinbase, + time: block.Time, + diff: block.Difficulty, + txValue: tx.Value, + txData: tx.Data, }) } - -// Contract evaluation is done here. -func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallback) { - addr := tx.Hash()[12:] - // Instruction pointer - pc := 0 - blockInfo := bm.bc.BlockInfo(block) - - contract := block.GetContract(addr) - - if contract == nil { - fmt.Println("Contract not found") - return - } - - Pow256 := ethutil.BigPow(2, 256) - - if ethutil.Config.Debug { - fmt.Printf("# op\n") - } - - stepcount := 0 - totalFee := new(big.Int) - - // helper function for getting a contract's memory address - getMem := func(num int) *ethutil.Value { - nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256) - return contract.Addr(nb) - } -out: - for { - stepcount++ - // The base big int for all calculations. Use this for any results. - base := new(big.Int) - val := getMem(pc) - //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) - op := OpCode(val.Uint()) - - var fee *big.Int = new(big.Int) - var fee2 *big.Int = new(big.Int) - if stepcount > 16 { - fee.Add(fee, StepFee) - } - - // Calculate the fees - switch op { - case oSSTORE: - y, x := bm.stack.Peekn() - val := contract.Addr(ethutil.BigToBytes(x, 256)) - if val.IsEmpty() && len(y.Bytes()) > 0 { - fee2.Add(DataFee, StoreFee) - } else { - fee2.Sub(DataFee, StoreFee) - } - case oSLOAD: - fee.Add(fee, StoreFee) - case oEXTRO, oBALANCE: - fee.Add(fee, ExtroFee) - case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: - fee.Add(fee, CryptoFee) - case oMKTX: - fee.Add(fee, ContractFee) - } - - tf := new(big.Int).Add(fee, fee2) - if contract.Amount.Cmp(tf) < 0 { - break - } - // Add the fee to the total fee. It's subtracted when we're done looping - totalFee.Add(totalFee, tf) - - if !cb(0) { - break - } - - if ethutil.Config.Debug { - fmt.Printf("%-3d %-4s", pc, op.String()) - } - - switch op { - case oSTOP: - fmt.Println("") - 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) - } - 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(getMem(pc).BigInt()) - 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.NewValueFromBytes([]byte(contract.State().Get(x.String()))) - if !decoder.IsNil() { - bm.stack.Push(decoder.BigInt()) - } else { - bm.stack.Push(ethutil.BigFalse) - } - case oSSTORE: - // Store Y at index X - y, x := bm.stack.Popn() - addr := ethutil.BigToBytes(x, 256) - fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(addr)) - contract.SetAddr(addr, y) - //contract.State().Update(string(idx), string(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() - default: - fmt.Println("Invalid OPCODE", op) - } - fmt.Println("") - bm.stack.Print() - pc++ - } - - block.UpdateContract(addr, contract) -} - -// 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.NewValueFromBytes([]byte(val)) - if decoder.IsNil() { - return ethutil.BigFalse - } - - return decoder.BigInt() -} diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index df3e56e5e..ec4fbe8c5 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -22,8 +22,12 @@ func TestVm(t *testing.T) { "1", "PUSH", "2", - "STOP", }) - ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), script) - bm.ApplyTransactions(block, []*Transaction{ctrct}) + tx := NewTransaction(ContractAddr, big.NewInt(200000000), script) + addr := tx.Hash()[12:] + bm.ApplyTransactions(block, []*Transaction{tx}) + + tx2 := NewTransaction(addr, big.NewInt(1e17), nil) + tx2.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) + bm.ApplyTransactions(block, []*Transaction{tx2}) } -- cgit v1.2.3 From 95a8ebc2495476c5dbe6c35f30629ca11f660b86 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:45:21 +0100 Subject: Changed MakeContract on block MakeContract in Block is now using the MakeContract defined in contract.go --- ethchain/block.go | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 0b4f93e8c..7ad9984be 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -220,23 +220,9 @@ func (block *Block) Undo() { } func (block *Block) MakeContract(tx *Transaction) { - // Create contract if there's no recipient - if tx.IsContract() { - addr := tx.Hash()[12:] - - value := tx.Value - contract := NewContract(value, []byte("")) - block.state.Update(string(addr), string(contract.RlpEncode())) - for i, val := range tx.Data { - if len(val) > 0 { - bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) - contract.state.Update(string(bytNum), val) - } - } - block.UpdateContract(addr, contract) + contract := MakeContract(tx, NewState(block.state)) - block.contractStates[string(addr)] = contract.state - } + block.contractStates[string(tx.Hash()[12:])] = contract.state } /////// Block Encoding -- cgit v1.2.3 From 6c7255cde2afdff7710af23c9830835398e6b43d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 13:15:34 +0100 Subject: Fixed a minor issue on crashed contracts --- ethchain/block.go | 5 +++-- ethchain/contract.go | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 7ad9984be..472ae134a 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -221,8 +221,9 @@ func (block *Block) Undo() { func (block *Block) MakeContract(tx *Transaction) { contract := MakeContract(tx, NewState(block.state)) - - block.contractStates[string(tx.Hash()[12:])] = contract.state + if contract != nil { + block.contractStates[string(tx.Hash()[12:])] = contract.state + } } /////// Block Encoding diff --git a/ethchain/contract.go b/ethchain/contract.go index dbcbb3697..14abb05d1 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -65,6 +66,8 @@ func MakeContract(tx *Transaction, state *State) *Contract { state.trie.Update(string(addr), string(contract.RlpEncode())) return contract + } else { + fmt.Println("NO CONTRACT") } return nil -- cgit v1.2.3 From 0afdedb01a8e4203129175dc9dcc213a55906a66 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 13:50:52 +0100 Subject: Some log statements changed to the default logger --- ethchain/block_manager.go | 25 ++++--------------------- ethchain/vm.go | 10 +++++----- 2 files changed, 9 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index ad96f6a34..04036dbb1 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -165,37 +165,20 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { if bm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo bm.bc.CurrentBlock.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.Value().Val}) + // Add the block to the chain + bm.bc.Add(block) + // 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()) + ethutil.Config.Log.Infof("[BMGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) } else { fmt.Println("total diff failed") } diff --git a/ethchain/vm.go b/ethchain/vm.go index 9abd9cd41..c7a91a9c5 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -48,7 +48,7 @@ func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { Pow256 := ethutil.BigPow(2, 256) if ethutil.Config.Debug { - fmt.Printf("# op\n") + ethutil.Config.Log.Debugf("# op\n") } stepcount := 0 @@ -98,7 +98,7 @@ out: totalFee.Add(totalFee, tf) if ethutil.Config.Debug { - fmt.Printf("%-3d %-4s", pc, op.String()) + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) } switch op { @@ -385,12 +385,12 @@ out: // Delete the contract state.trie.Update(string(addr), "") - fmt.Printf("(%d) => %x\n", deletedMemory, recAddr) + ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) break out default: fmt.Printf("Invalid OPCODE: %x\n", op) } - fmt.Println("") + ethutil.Config.Log.Debugln("") //vm.stack.Print() pc++ } @@ -399,7 +399,7 @@ out: } func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { - fmt.Printf(" => creating inline tx %x %v %v %v", addr, value, from, length) + ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) j := 0 dataItems := make([]string, int(length.Uint64())) for i := from.Uint64(); i < length.Uint64(); i++ { -- cgit v1.2.3 From 507fc7b9d1e227de91b25e18891c4cd44452b222 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:21:35 +0100 Subject: Length checking when fetching contract. Contract always have 3 fields --- ethchain/block.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 472ae134a..7ca44a47d 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -131,6 +131,11 @@ func (block *Block) GetContract(addr []byte) *Contract { return nil } + value := ethutil.NewValueFromBytes([]byte(data)) + if value.Len() == 2 { + return nil + } + contract := &Contract{} contract.RlpDecode([]byte(data)) -- cgit v1.2.3 From ce07d9bb4c95a118636c4b71e9cba2d81540c4a5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:21:49 +0100 Subject: Error logging on tx processing --- ethchain/block_manager.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 04036dbb1..364a06158 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -92,12 +92,13 @@ func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { } func (bm *BlockManager) GetAddrState(addr []byte) *AddressState { - addrState := bm.addrStateStore.Get(addr) - if addrState == nil { - addrState = bm.WatchAddr(addr) + account := bm.addrStateStore.Get(addr) + if account == nil { + a := bm.bc.CurrentBlock.GetAddr(addr) + account = &AddressState{Nonce: a.Nonce, Account: a} } - return addrState + return account } func (bm *BlockManager) BlockChain() *BlockChain { @@ -114,7 +115,10 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { if contract := block.GetContract(tx.Recipient); contract != nil { bm.ProcessContract(contract, tx, block) } else { - bm.TransactionPool.ProcessTransaction(tx, block) + err := bm.TransactionPool.ProcessTransaction(tx, block) + if err != nil { + ethutil.Config.Log.Infoln("[BMGR]", err) + } } } } -- cgit v1.2.3 From 1e7b3cbb1343d5362b8ed55d06b1927171f56a41 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:22:05 +0100 Subject: Removed debug log --- ethchain/contract.go | 3 --- 1 file changed, 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/contract.go b/ethchain/contract.go index 14abb05d1..dbcbb3697 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -1,7 +1,6 @@ package ethchain import ( - "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -66,8 +65,6 @@ func MakeContract(tx *Transaction, state *State) *Contract { state.trie.Update(string(addr), string(contract.RlpEncode())) return contract - } else { - fmt.Println("NO CONTRACT") } return nil -- cgit v1.2.3 From 4b8c50e2cde130bf278b14040a267aab573dd53e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:22:18 +0100 Subject: Deprication --- ethchain/transaction.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 39b2bda94..57df9cdc4 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -29,7 +29,12 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { return &tx } +// XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { + return NewTransactionFromBytes(data) +} + +func NewTransactionFromBytes(data []byte) *Transaction { tx := &Transaction{} tx.RlpDecode(data) -- cgit v1.2.3 From e98b53bbef8cdbeed54546c75d856d53810e424c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:22:27 +0100 Subject: WIP Observing pattern --- ethchain/transaction_pool.go | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 1278cc4dc..cd09bf02e 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -17,6 +17,17 @@ const ( ) type TxPoolHook chan *Transaction +type TxMsgTy byte + +const ( + TxPre = iota + TxPost +) + +type TxMsg struct { + Tx *Transaction + Type TxMsgTy +} func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction { for e := pool.Front(); e != nil; e = e.Next() { @@ -59,6 +70,8 @@ type TxPool struct { BlockManager *BlockManager SecondaryProcessor TxProcessor + + subscribers []chan TxMsg } func NewTxPool() *TxPool { @@ -73,21 +86,17 @@ func NewTxPool() *TxPool { // Blocking function. Don't use directly. Use QueueTransaction instead func (pool *TxPool) addTransaction(tx *Transaction) { - log.Println("Adding tx to pool") 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()}) - log.Println("broadcasting it") } // 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) @@ -132,6 +141,11 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error block.UpdateAddr(tx.Sender(), sender) + log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) + + // Notify the subscribers + pool.notifySubscribers(TxPost, tx) + return } @@ -145,7 +159,8 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - sender := block.GetAddr(tx.Sender()) + accountState := pool.BlockManager.GetAddrState(tx.Sender()) + sender := accountState.Account totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) // Make sure there's enough in the sender's account. Having insufficient @@ -185,9 +200,8 @@ out: // doesn't matter since this is a goroutine pool.addTransaction(tx) - if pool.SecondaryProcessor != nil { - pool.SecondaryProcessor.ProcessTransaction(tx) - } + // Notify the subscribers + pool.notifySubscribers(TxPre, tx) } case <-pool.quit: break out @@ -231,3 +245,14 @@ func (pool *TxPool) Stop() { pool.Flush() } + +func (pool *TxPool) Subscribe(channel chan TxMsg) { + pool.subscribers = append(pool.subscribers, channel) +} + +func (pool *TxPool) notifySubscribers(ty TxMsgTy, tx *Transaction) { + msg := TxMsg{Type: ty, Tx: tx} + for _, subscriber := range pool.subscribers { + subscriber <- msg + } +} -- cgit v1.2.3