From f6d1bfe45bf3709d7bad40bf563b5c09228622e3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 14 Feb 2014 23:56:09 +0100 Subject: The great merge --- ethchain/.gitignore | 12 + ethchain/block.go | 363 ++++++++++++++++++++++++ ethchain/block_chain.go | 184 ++++++++++++ ethchain/block_manager.go | 627 +++++++++++++++++++++++++++++++++++++++++ ethchain/block_manager_test.go | 75 +++++ ethchain/contract.go | 66 +++++ ethchain/dagger.go | 199 +++++++++++++ ethchain/dagger_test.go | 18 ++ ethchain/error.go | 42 +++ ethchain/fees.go | 65 +++++ ethchain/genesis.go | 39 +++ ethchain/stack.go | 167 +++++++++++ ethchain/transaction.go | 157 +++++++++++ ethchain/transaction_pool.go | 219 ++++++++++++++ ethchain/transaction_test.go | 54 ++++ 15 files changed, 2287 insertions(+) create mode 100644 ethchain/.gitignore create mode 100644 ethchain/block.go create mode 100644 ethchain/block_chain.go create mode 100644 ethchain/block_manager.go create mode 100644 ethchain/block_manager_test.go create mode 100644 ethchain/contract.go create mode 100644 ethchain/dagger.go create mode 100644 ethchain/dagger_test.go create mode 100644 ethchain/error.go create mode 100644 ethchain/fees.go create mode 100644 ethchain/genesis.go create mode 100644 ethchain/stack.go create mode 100644 ethchain/transaction.go create mode 100644 ethchain/transaction_pool.go create mode 100644 ethchain/transaction_test.go (limited to 'ethchain') diff --git a/ethchain/.gitignore b/ethchain/.gitignore new file mode 100644 index 000000000..f725d58d1 --- /dev/null +++ b/ethchain/.gitignore @@ -0,0 +1,12 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store + diff --git a/ethchain/block.go b/ethchain/block.go new file mode 100644 index 000000000..a7a1f787b --- /dev/null +++ b/ethchain/block.go @@ -0,0 +1,363 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" + "time" +) + +type BlockInfo struct { + Number uint64 + Hash []byte + Parent []byte +} + +func (bi *BlockInfo) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + bi.Number = decoder.Get(0).Uint() + bi.Hash = decoder.Get(1).Bytes() + bi.Parent = decoder.Get(2).Bytes() +} + +func (bi *BlockInfo) RlpEncode() []byte { + return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent}) +} + +type Block struct { + // Hash to the previous block + PrevHash []byte + // Uncles of this block + Uncles []*Block + UncleSha []byte + // The coin base address + Coinbase []byte + // Block Trie state + state *ethutil.Trie + // Difficulty for the current block + Difficulty *big.Int + // Creation time + Time int64 + // Extra data + Extra string + // Block Nonce for verification + Nonce []byte + // List of transactions and/or contracts + transactions []*Transaction + TxSha []byte +} + +// New block takes a raw encoded string +// XXX DEPRICATED +func NewBlockFromData(raw []byte) *Block { + return NewBlockFromBytes(raw) +} + +func NewBlockFromBytes(raw []byte) *Block { + block := &Block{} + block.RlpDecode(raw) + + return block +} + +// New block takes a raw encoded string +func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block { + block := &Block{} + block.RlpValueDecode(rlpValue) + + return block +} + +func CreateBlock(root interface{}, + prevHash []byte, + base []byte, + Difficulty *big.Int, + Nonce []byte, + extra string, + txes []*Transaction) *Block { + + block := &Block{ + // Slice of transactions to include in this block + transactions: txes, + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + } + block.SetTransactions(txes) + block.SetUncles([]*Block{}) + + block.state = ethutil.NewTrie(ethutil.Config.Db, root) + + for _, tx := range txes { + block.MakeContract(tx) + } + + return block +} + +// Returns a hash of the block +func (block *Block) Hash() []byte { + return ethutil.Sha3Bin(block.RlpValue().Encode()) +} + +func (block *Block) HashNoNonce() []byte { + return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) +} + +func (block *Block) PrintHash() { + fmt.Println(block) + fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce}))) +} + +func (block *Block) State() *ethutil.Trie { + return block.state +} + +func (block *Block) Transactions() []*Transaction { + return block.transactions +} + +func (block *Block) GetContract(addr []byte) *Contract { + data := block.state.Get(string(addr)) + if data == "" { + return nil + } + + contract := &Contract{} + contract.RlpDecode([]byte(data)) + + return contract +} +func (block *Block) UpdateContract(addr []byte, contract *Contract) { + // Make sure the state is synced + contract.State().Sync() + + block.state.Update(string(addr), string(contract.RlpEncode())) +} + +func (block *Block) GetAddr(addr []byte) *Address { + var address *Address + + data := block.State().Get(string(addr)) + if data == "" { + address = NewAddress(big.NewInt(0)) + } else { + address = NewAddressFromData([]byte(data)) + } + + return address +} +func (block *Block) UpdateAddr(addr []byte, address *Address) { + block.state.Update(string(addr), string(address.RlpEncode())) +} + +func (block *Block) PayFee(addr []byte, fee *big.Int) bool { + contract := block.GetContract(addr) + // If we can't pay the fee return + if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ { + fmt.Println("Contract has insufficient funds", contract.Amount, fee) + + return false + } + + base := new(big.Int) + contract.Amount = base.Sub(contract.Amount, fee) + block.state.Update(string(addr), string(contract.RlpEncode())) + + data := block.state.Get(string(block.Coinbase)) + + // Get the ether (Coinbase) and add the fee (gief fee to miner) + ether := NewAddressFromData([]byte(data)) + + base = new(big.Int) + ether.Amount = base.Add(ether.Amount, fee) + + block.state.Update(string(block.Coinbase), string(ether.RlpEncode())) + + return true +} + +func (block *Block) BlockInfo() BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (block *Block) MakeContract(tx *Transaction) { + // Create contract if there's no recipient + if tx.IsContract() { + addr := tx.Hash() + + value := tx.Value + contract := NewContract(value, []byte("")) + block.state.Update(string(addr), string(contract.RlpEncode())) + for i, val := range tx.Data { + contract.state.Update(string(ethutil.NumberToBytes(uint64(i), 32)), val) + } + block.UpdateContract(addr, contract) + } +} + +/////// Block Encoding +func (block *Block) encodedUncles() interface{} { + uncles := make([]interface{}, len(block.Uncles)) + for i, uncle := range block.Uncles { + uncles[i] = uncle.RlpEncode() + } + + return uncles +} + +func (block *Block) encodedTxs() interface{} { + // Marshal the transactions of this block + encTx := make([]interface{}, len(block.transactions)) + for i, tx := range block.transactions { + // Cast it to a string (safe) + encTx[i] = tx.RlpData() + } + + return encTx +} + +func (block *Block) rlpTxs() interface{} { + // Marshal the transactions of this block + encTx := make([]interface{}, len(block.transactions)) + for i, tx := range block.transactions { + // Cast it to a string (safe) + encTx[i] = tx.RlpData() + } + + return encTx +} + +func (block *Block) rlpUncles() interface{} { + // Marshal the transactions of this block + uncles := make([]interface{}, len(block.Uncles)) + for i, uncle := range block.Uncles { + // Cast it to a string (safe) + uncles[i] = uncle.header() + } + + return uncles +} + +func (block *Block) SetUncles(uncles []*Block) { + block.Uncles = uncles + + // Sha of the concatenated uncles + block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles())) +} + +func (block *Block) SetTransactions(txs []*Transaction) { + block.transactions = txs + + block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs())) +} + +func (block *Block) RlpValue() *ethutil.RlpValue { + return ethutil.NewRlpValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()}) +} + +func (block *Block) RlpEncode() []byte { + // Encode a slice interface which contains the header and the list of + // transactions. + return block.RlpValue().Encode() +} + +func (block *Block) RlpDecode(data []byte) { + rlpValue := ethutil.NewValueFromBytes(data) + block.RlpValueDecode(rlpValue) +} + +func (block *Block) RlpValueDecode(decoder *ethutil.Value) { + header := decoder.Get(0) + + block.PrevHash = header.Get(0).Bytes() + block.UncleSha = header.Get(1).Bytes() + block.Coinbase = header.Get(2).Bytes() + block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val) + block.TxSha = header.Get(4).Bytes() + block.Difficulty = header.Get(5).BigInt() + block.Time = int64(header.Get(6).BigInt().Uint64()) + block.Extra = header.Get(7).Str() + block.Nonce = header.Get(8).Bytes() + + // Tx list might be empty if this is an uncle. Uncles only have their + // header set. + if decoder.Get(1).IsNil() == false { // Yes explicitness + txes := decoder.Get(1) + block.transactions = make([]*Transaction, txes.Len()) + for i := 0; i < txes.Len(); i++ { + tx := NewTransactionFromValue(txes.Get(i)) + + block.transactions[i] = tx + + /* + if ethutil.Config.Debug { + ethutil.Config.Db.Put(tx.Hash(), ethutil.Encode(tx)) + } + */ + } + + } + + if decoder.Get(2).IsNil() == false { // Yes explicitness + uncles := decoder.Get(2) + block.Uncles = make([]*Block, uncles.Len()) + for i := 0; i < uncles.Len(); i++ { + block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i)) + } + } + +} + +func NewUncleBlockFromValue(header *ethutil.Value) *Block { + block := &Block{} + + block.PrevHash = header.Get(0).Bytes() + block.UncleSha = header.Get(1).Bytes() + block.Coinbase = header.Get(2).Bytes() + block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val) + block.TxSha = header.Get(4).Bytes() + block.Difficulty = header.Get(5).BigInt() + block.Time = int64(header.Get(6).BigInt().Uint64()) + block.Extra = header.Get(7).Str() + block.Nonce = header.Get(8).Bytes() + + return block +} + +func (block *Block) String() string { + return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce) +} + +//////////// UNEXPORTED ///////////////// +func (block *Block) header() []interface{} { + return []interface{}{ + // Sha of the previous block + block.PrevHash, + // Sha of uncles + block.UncleSha, + // Coinbase address + block.Coinbase, + // root state + block.state.Root, + // Sha of tx + block.TxSha, + // Current block Difficulty + block.Difficulty, + // Time the block was found? + block.Time, + // Extra data + block.Extra, + // Block's Nonce for validation + block.Nonce, + } +} diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go new file mode 100644 index 000000000..56bc43a8e --- /dev/null +++ b/ethchain/block_chain.go @@ -0,0 +1,184 @@ +package ethchain + +import ( + "bytes" + "github.com/ethereum/eth-go/ethutil" + "log" + "math" + "math/big" +) + +type BlockChain struct { + // The famous, the fabulous Mister GENESIIIIIIS (block) + genesisBlock *Block + // Last known total difficulty + TD *big.Int + + LastBlockNumber uint64 + + CurrentBlock *Block + LastBlockHash []byte +} + +func NewBlockChain() *BlockChain { + bc := &BlockChain{} + bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) + + bc.setLastBlock() + + return bc +} + +func (bc *BlockChain) Genesis() *Block { + return bc.genesisBlock +} + +func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { + var root interface{} + var lastBlockTime int64 + hash := ZeroHash256 + + if bc.CurrentBlock != nil { + root = bc.CurrentBlock.State().Root + hash = bc.LastBlockHash + lastBlockTime = bc.CurrentBlock.Time + } + + block := CreateBlock( + root, + hash, + coinbase, + ethutil.BigPow(2, 32), + nil, + "", + txs) + + if bc.CurrentBlock != nil { + var mul *big.Int + if block.Time < lastBlockTime+42 { + mul = big.NewInt(1) + } else { + mul = big.NewInt(-1) + } + + diff := new(big.Int) + diff.Add(diff, bc.CurrentBlock.Difficulty) + diff.Div(diff, big.NewInt(1024)) + diff.Mul(diff, mul) + diff.Add(diff, bc.CurrentBlock.Difficulty) + block.Difficulty = diff + } + + return block +} + +func (bc *BlockChain) HasBlock(hash []byte) bool { + data, _ := ethutil.Config.Db.Get(hash) + return len(data) != 0 +} + +func (bc *BlockChain) GenesisBlock() *Block { + return bc.genesisBlock +} + +// Get chain return blocks from hash up to max in RLP format +func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { + var chain []interface{} + // Get the current hash to start with + currentHash := bc.CurrentBlock.Hash() + // Get the last number on the block chain + lastNumber := bc.BlockInfo(bc.CurrentBlock).Number + // Get the parents number + parentNumber := bc.BlockInfoByHash(hash).Number + // Get the min amount. We might not have max amount of blocks + count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max))) + startNumber := parentNumber + count + + num := lastNumber + for ; num > startNumber; currentHash = bc.GetBlock(currentHash).PrevHash { + num-- + } + for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { + // Get the block of the chain + block := bc.GetBlock(currentHash) + currentHash = block.PrevHash + + chain = append(chain, block.RlpValue().Value) + //chain = append([]interface{}{block.RlpValue().Value}, chain...) + + num-- + } + + return chain +} + +func (bc *BlockChain) setLastBlock() { + data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) + if len(data) != 0 { + block := NewBlockFromBytes(data) + info := bc.BlockInfo(block) + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + bc.LastBlockNumber = info.Number + + log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + } + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) +} + +func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { + ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes()) + bc.TD = td +} + +// Add a block to the chain and record addition information +func (bc *BlockChain) Add(block *Block) { + bc.writeBlockInfo(block) + + // Prepare the genesis block + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + + ethutil.Config.Db.Put(block.Hash(), block.RlpEncode()) +} + +func (bc *BlockChain) GetBlock(hash []byte) *Block { + data, _ := ethutil.Config.Db.Get(hash) + + return NewBlockFromData(data) +} + +func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (bc *BlockChain) BlockInfo(block *Block) BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +// Unexported method for writing extra non-essential block info to the db +func (bc *BlockChain) writeBlockInfo(block *Block) { + bc.LastBlockNumber++ + bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash} + + // For now we use the block hash with the words "info" appended as key + ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode()) +} + +func (bc *BlockChain) Stop() { + if bc.CurrentBlock != nil { + ethutil.Config.Db.Put([]byte("LastBlock"), bc.CurrentBlock.RlpEncode()) + + log.Println("[CHAIN] Stopped") + } +} diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go new file mode 100644 index 000000000..92f20e253 --- /dev/null +++ b/ethchain/block_manager.go @@ -0,0 +1,627 @@ +package ethchain + +import ( + "bytes" + "encoding/hex" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" + "log" + "math" + "math/big" + "strconv" + "sync" + "time" +) + +type BlockProcessor interface { + ProcessBlock(block *Block) +} + +func CalculateBlockReward(block *Block, uncleLength int) *big.Int { + return BlockReward +} + +type BlockManager struct { + // Mutex for locking the block processor. Blocks can only be handled one at a time + mutex sync.Mutex + + // The block chain :) + bc *BlockChain + + // Stack for processing contracts + stack *Stack + // non-persistent key/value memory storage + mem map[string]*big.Int + + TransactionPool *TxPool + + Pow PoW + + Speaker PublicSpeaker + + SecondaryBlockProcessor BlockProcessor +} + +func AddTestNetFunds(block *Block) { + for _, addr := range []string{ + "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin + "93658b04240e4bd4046fd2d6d417d20f146f4b43", // Jeffrey + "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit + "80c01a26338f0d905e295fccb71fa9ea849ffa12", // Alex + } { + //log.Println("2^200 Wei to", addr) + codedAddr, _ := hex.DecodeString(addr) + addr := block.GetAddr(codedAddr) + addr.Amount = ethutil.BigPow(2, 200) + block.UpdateAddr(codedAddr, addr) + } +} + +func NewBlockManager(speaker PublicSpeaker) *BlockManager { + bm := &BlockManager{ + //server: s, + bc: NewBlockChain(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Speaker: speaker, + } + + if bm.bc.CurrentBlock == nil { + AddTestNetFunds(bm.bc.genesisBlock) + // Prepare the genesis block + //bm.bc.genesisBlock.State().Sync() + bm.bc.Add(bm.bc.genesisBlock) + log.Println(bm.bc.genesisBlock) + + log.Printf("Genesis: %x\n", bm.bc.genesisBlock.Hash()) + //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) + //bm.bc.genesisBlock.PrintHash() + } + + return bm +} + +func (bm *BlockManager) BlockChain() *BlockChain { + return bm.bc +} + +func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { + // Process each transaction/contract + for _, tx := range txs { + // If there's no recipient, it's a contract + if tx.IsContract() { + block.MakeContract(tx) + bm.ProcessContract(tx, block) + } else { + bm.TransactionPool.ProcessTransaction(tx, block) + } + } +} + +// Block processing and validating with a given (temporarily) state +func (bm *BlockManager) ProcessBlock(block *Block) error { + // Processing a blocks may never happen simultaneously + bm.mutex.Lock() + defer bm.mutex.Unlock() + + hash := block.Hash() + + if bm.bc.HasBlock(hash) { + return nil + } + + /* + if ethutil.Config.Debug { + log.Printf("[BMGR] Processing block(%x)\n", hash) + } + */ + + // Check if we have the parent hash, if it isn't known we discard it + // Reasons might be catching up or simply an invalid block + if !bm.bc.HasBlock(block.PrevHash) && bm.bc.CurrentBlock != nil { + return ParentError(block.PrevHash) + } + + // Process the transactions on to current block + bm.ApplyTransactions(bm.bc.CurrentBlock, block.Transactions()) + + // Block validation + if err := bm.ValidateBlock(block); err != nil { + return err + } + + // I'm not sure, but I don't know if there should be thrown + // any errors at this time. + if err := bm.AccumelateRewards(bm.bc.CurrentBlock, block); err != nil { + return err + } + + if !block.State().Cmp(bm.bc.CurrentBlock.State()) { + //if block.State().Root != state.Root { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().Root, bm.bc.CurrentBlock.State().Root) + } + + // Calculate the new total difficulty and sync back to the db + if bm.CalculateTD(block) { + // Sync the current block's state to the database + bm.bc.CurrentBlock.State().Sync() + // Add the block to the chain + bm.bc.Add(block) + + /* + ethutil.Config.Db.Put(block.Hash(), block.RlpEncode()) + bm.bc.CurrentBlock = block + bm.LastBlockHash = block.Hash() + bm.writeBlockInfo(block) + */ + + /* + txs := bm.TransactionPool.Flush() + var coded = []interface{}{} + for _, tx := range txs { + err := bm.TransactionPool.ValidateTransaction(tx) + if err == nil { + coded = append(coded, tx.RlpEncode()) + } + } + */ + + // Broadcast the valid block back to the wire + //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.RlpValue().Value}) + + // If there's a block processor present, pass in the block for further + // processing + if bm.SecondaryBlockProcessor != nil { + bm.SecondaryBlockProcessor.ProcessBlock(block) + } + + log.Printf("[BMGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + } else { + fmt.Println("total diff failed") + } + + return nil +} + +func (bm *BlockManager) CalculateTD(block *Block) bool { + uncleDiff := new(big.Int) + for _, uncle := range block.Uncles { + uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) + } + + // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty + td := new(big.Int) + td = td.Add(bm.bc.TD, uncleDiff) + td = td.Add(td, block.Difficulty) + + // The new TD will only be accepted if the new difficulty is + // is greater than the previous. + if td.Cmp(bm.bc.TD) > 0 { + // Set the new total difficulty back to the block chain + bm.bc.SetTotalDifficulty(td) + + /* + if ethutil.Config.Debug { + log.Println("[BMGR] TD(block) =", td) + } + */ + + return true + } + + return false +} + +// Validates the current block. Returns an error if the block was invalid, +// an uncle or anything that isn't on the current block chain. +// Validation validates easy over difficult (dagger takes longer time = difficult) +func (bm *BlockManager) ValidateBlock(block *Block) error { + // TODO + // 2. Check if the difficulty is correct + + // Check each uncle's previous hash. In order for it to be valid + // is if it has the same block hash as the current + previousBlock := bm.bc.GetBlock(block.PrevHash) + for _, uncle := range block.Uncles { + if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 { + return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash) + } + } + + diff := block.Time - bm.bc.CurrentBlock.Time + if diff < 0 { + return ValidationError("Block timestamp less then prev block %v", diff) + } + + // New blocks must be within the 15 minute range of the last block. + if diff > int64(15*time.Minute) { + return ValidationError("Block is too far in the future of last block (> 15 minutes)") + } + + // Verify the nonce of the block. Return an error if it's not valid + if !bm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { + return ValidationError("Block's nonce is invalid (= %v)", block.Nonce) + } + + return nil +} + +func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { + // Get the coinbase rlp data + addr := processor.GetAddr(block.Coinbase) + // Reward amount of ether to the coinbase address + addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) + + processor.UpdateAddr(block.Coinbase, addr) + + // TODO Reward each uncle + + return nil +} + +func (bm *BlockManager) Stop() { + bm.bc.Stop() +} + +func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { + // Recovering function in case the VM had any errors + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from VM execution with err =", r) + } + }() + + // Process contract + bm.ProcContract(tx, block, func(opType OpType) bool { + // TODO turn on once big ints are in place + //if !block.PayFee(tx.Hash(), StepFee.Uint64()) { + // return false + //} + + return true // Continue + }) +} + +// Contract evaluation is done here. +func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallback) { + + // Instruction pointer + pc := 0 + blockInfo := bm.bc.BlockInfo(block) + + contract := block.GetContract(tx.Hash()) + if contract == nil { + fmt.Println("Contract not found") + return + } + + Pow256 := ethutil.BigPow(2, 256) + + if ethutil.Config.Debug { + fmt.Printf("# op arg\n") + } +out: + for { + // The base big int for all calculations. Use this for any results. + base := new(big.Int) + // XXX Should Instr return big int slice instead of string slice? + // Get the next instruction from the contract + //op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc))))) + nb := ethutil.NumberToBytes(uint64(pc), 32) + o, _, _ := ethutil.Instr(contract.State().Get(string(nb))) + op := OpCode(o) + + if !cb(0) { + break + } + + if ethutil.Config.Debug { + fmt.Printf("%-3d %-4s\n", pc, op.String()) + } + + switch op { + case oSTOP: + break out + case oADD: + x, y := bm.stack.Popn() + // (x + y) % 2 ** 256 + base.Add(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + bm.stack.Push(base) + case oSUB: + x, y := bm.stack.Popn() + // (x - y) % 2 ** 256 + base.Sub(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + bm.stack.Push(base) + case oMUL: + x, y := bm.stack.Popn() + // (x * y) % 2 ** 256 + base.Mul(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + bm.stack.Push(base) + case oDIV: + x, y := bm.stack.Popn() + // floor(x / y) + base.Div(x, y) + // Pop result back on the stack + bm.stack.Push(base) + case oSDIV: + x, y := bm.stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Div(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + bm.stack.Push(z) + case oMOD: + x, y := bm.stack.Popn() + base.Mod(x, y) + bm.stack.Push(base) + case oSMOD: + x, y := bm.stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Mod(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + bm.stack.Push(z) + case oEXP: + x, y := bm.stack.Popn() + base.Exp(x, y, Pow256) + + bm.stack.Push(base) + case oNEG: + base.Sub(Pow256, bm.stack.Pop()) + bm.stack.Push(base) + case oLT: + x, y := bm.stack.Popn() + // x < y + if x.Cmp(y) < 0 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oLE: + x, y := bm.stack.Popn() + // x <= y + if x.Cmp(y) < 1 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oGT: + x, y := bm.stack.Popn() + // x > y + if x.Cmp(y) > 0 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oGE: + x, y := bm.stack.Popn() + // x >= y + if x.Cmp(y) > -1 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oNOT: + x, y := bm.stack.Popn() + // x != y + if x.Cmp(y) != 0 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + + // Please note that the following code contains some + // ugly string casting. This will have to change to big + // ints. TODO :) + case oMYADDRESS: + bm.stack.Push(ethutil.BigD(tx.Hash())) + case oTXSENDER: + bm.stack.Push(ethutil.BigD(tx.Sender())) + case oTXVALUE: + bm.stack.Push(tx.Value) + case oTXDATAN: + bm.stack.Push(big.NewInt(int64(len(tx.Data)))) + case oTXDATA: + v := bm.stack.Pop() + // v >= len(data) + if v.Cmp(big.NewInt(int64(len(tx.Data)))) >= 0 { + bm.stack.Push(ethutil.Big("0")) + } else { + bm.stack.Push(ethutil.Big(tx.Data[v.Uint64()])) + } + case oBLK_PREVHASH: + bm.stack.Push(ethutil.BigD(block.PrevHash)) + case oBLK_COINBASE: + bm.stack.Push(ethutil.BigD(block.Coinbase)) + case oBLK_TIMESTAMP: + bm.stack.Push(big.NewInt(block.Time)) + case oBLK_NUMBER: + bm.stack.Push(big.NewInt(int64(blockInfo.Number))) + case oBLK_DIFFICULTY: + bm.stack.Push(block.Difficulty) + case oBASEFEE: + // e = 10^21 + e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0)) + d := new(big.Rat) + d.SetInt(block.Difficulty) + c := new(big.Rat) + c.SetFloat64(0.5) + // d = diff / 0.5 + d.Quo(d, c) + // base = floor(d) + base.Div(d.Num(), d.Denom()) + + x := new(big.Int) + x.Div(e, base) + + // x = floor(10^21 / floor(diff^0.5)) + bm.stack.Push(x) + case oSHA256, oSHA3, oRIPEMD160: + // This is probably save + // ceil(pop / 32) + length := int(math.Ceil(float64(bm.stack.Pop().Uint64()) / 32.0)) + // New buffer which will contain the concatenated popped items + data := new(bytes.Buffer) + for i := 0; i < length; i++ { + // Encode the number to bytes and have it 32bytes long + num := ethutil.NumberToBytes(bm.stack.Pop().Bytes(), 256) + data.WriteString(string(num)) + } + + if op == oSHA256 { + bm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes()))) + } else if op == oSHA3 { + bm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes()))) + } else { + bm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes()))) + } + case oECMUL: + y := bm.stack.Pop() + x := bm.stack.Pop() + //n := bm.stack.Pop() + + //if ethutil.Big(x).Cmp(ethutil.Big(y)) { + data := new(bytes.Buffer) + data.WriteString(x.String()) + data.WriteString(y.String()) + if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 { + // TODO + } else { + // Invalid, push infinity + bm.stack.Push(ethutil.Big("0")) + bm.stack.Push(ethutil.Big("0")) + } + //} else { + // // Invalid, push infinity + // bm.stack.Push("0") + // bm.stack.Push("0") + //} + + case oECADD: + case oECSIGN: + case oECRECOVER: + case oECVALID: + case oPUSH: + pc++ + bm.stack.Push(bm.mem[strconv.Itoa(pc)]) + case oPOP: + // Pop current value of the stack + bm.stack.Pop() + case oDUP: + // Dup top stack + x := bm.stack.Pop() + bm.stack.Push(x) + bm.stack.Push(x) + case oSWAP: + // Swap two top most values + x, y := bm.stack.Popn() + bm.stack.Push(y) + bm.stack.Push(x) + case oMLOAD: + x := bm.stack.Pop() + bm.stack.Push(bm.mem[x.String()]) + case oMSTORE: + x, y := bm.stack.Popn() + bm.mem[x.String()] = y + case oSLOAD: + // Load the value in storage and push it on the stack + x := bm.stack.Pop() + // decode the object as a big integer + decoder := ethutil.NewRlpValueFromBytes([]byte(contract.State().Get(x.String()))) + if !decoder.IsNil() { + bm.stack.Push(decoder.AsBigInt()) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oSSTORE: + // Store Y at index X + x, y := bm.stack.Popn() + contract.State().Update(x.String(), string(ethutil.Encode(y))) + case oJMP: + x := int(bm.stack.Pop().Uint64()) + // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) + pc = x + pc-- + case oJMPI: + x := bm.stack.Pop() + // Set pc to x if it's non zero + if x.Cmp(ethutil.BigFalse) != 0 { + pc = int(x.Uint64()) + pc-- + } + case oIND: + bm.stack.Push(big.NewInt(int64(pc))) + case oEXTRO: + memAddr := bm.stack.Pop() + contractAddr := bm.stack.Pop().Bytes() + + // Push the contract's memory on to the stack + bm.stack.Push(getContractMemory(block, contractAddr, memAddr)) + case oBALANCE: + // Pushes the balance of the popped value on to the stack + d := block.State().Get(bm.stack.Pop().String()) + ether := NewAddressFromData([]byte(d)) + bm.stack.Push(ether.Amount) + case oMKTX: + value, addr := bm.stack.Popn() + from, length := bm.stack.Popn() + + j := 0 + dataItems := make([]string, int(length.Uint64())) + for i := from.Uint64(); i < length.Uint64(); i++ { + dataItems[j] = string(bm.mem[strconv.Itoa(int(i))].Bytes()) + j++ + } + // TODO sign it? + tx := NewTransaction(addr.Bytes(), value, dataItems) + // Add the transaction to the tx pool + bm.TransactionPool.QueueTransaction(tx) + case oSUICIDE: + //addr := bm.stack.Pop() + } + pc++ + } +} + +// Returns an address from the specified contract's address +func getContractMemory(block *Block, contractAddr []byte, memAddr *big.Int) *big.Int { + contract := block.GetContract(contractAddr) + if contract == nil { + log.Panicf("invalid contract addr %x", contractAddr) + } + val := contract.State().Get(memAddr.String()) + + // decode the object as a big integer + decoder := ethutil.NewRlpValueFromBytes([]byte(val)) + if decoder.IsNil() { + return ethutil.BigFalse + } + + return decoder.AsBigInt() +} diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go new file mode 100644 index 000000000..502c50b97 --- /dev/null +++ b/ethchain/block_manager_test.go @@ -0,0 +1,75 @@ +package ethchain + +/* +import ( + _ "fmt" + "testing" +) + +func TestVm(t *testing.T) { + InitFees() + + db, _ := NewMemDatabase() + Db = db + + ctrct := NewTransaction("", 200000000, []string{ + "PUSH", "1a2f2e", + "PUSH", "hallo", + "POP", // POP hallo + "PUSH", "3", + "LOAD", // Load hallo back on the stack + + "PUSH", "1", + "PUSH", "2", + "ADD", + + "PUSH", "2", + "PUSH", "1", + "SUB", + + "PUSH", "100000000000000000000000", + "PUSH", "10000000000000", + "SDIV", + + "PUSH", "105", + "PUSH", "200", + "MOD", + + "PUSH", "100000000000000000000000", + "PUSH", "10000000000000", + "SMOD", + + "PUSH", "5", + "PUSH", "10", + "LT", + + "PUSH", "5", + "PUSH", "5", + "LE", + + "PUSH", "50", + "PUSH", "5", + "GT", + + "PUSH", "5", + "PUSH", "5", + "GE", + + "PUSH", "10", + "PUSH", "10", + "NOT", + + "MYADDRESS", + "TXSENDER", + + "STOP", + }) + tx := NewTransaction("1e8a42ea8cce13", 100, []string{}) + + block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx}) + db.Put(block.Hash(), block.RlpEncode()) + + bm := NewBlockManager() + bm.ProcessBlock(block) +} +*/ diff --git a/ethchain/contract.go b/ethchain/contract.go new file mode 100644 index 000000000..d1fcec3b4 --- /dev/null +++ b/ethchain/contract.go @@ -0,0 +1,66 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type Contract struct { + Amount *big.Int + Nonce uint64 + state *ethutil.Trie +} + +func NewContract(Amount *big.Int, root []byte) *Contract { + contract := &Contract{Amount: Amount, Nonce: 0} + contract.state = ethutil.NewTrie(ethutil.Config.Db, string(root)) + + return contract +} + +func (c *Contract) RlpEncode() []byte { + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.Root}) +} + +func (c *Contract) RlpDecode(data []byte) { + decoder := ethutil.NewRlpValueFromBytes(data) + + c.Amount = decoder.Get(0).AsBigInt() + c.Nonce = decoder.Get(1).AsUint() + c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).AsRaw()) +} + +func (c *Contract) State() *ethutil.Trie { + return c.state +} + +type Address struct { + Amount *big.Int + Nonce uint64 +} + +func NewAddress(amount *big.Int) *Address { + return &Address{Amount: amount, Nonce: 0} +} + +func NewAddressFromData(data []byte) *Address { + address := &Address{} + address.RlpDecode(data) + + return address +} + +func (a *Address) AddFee(fee *big.Int) { + a.Amount.Add(a.Amount, fee) +} + +func (a *Address) RlpEncode() []byte { + return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) +} + +func (a *Address) RlpDecode(data []byte) { + decoder := ethutil.NewRlpValueFromBytes(data) + + a.Amount = decoder.Get(0).AsBigInt() + a.Nonce = decoder.Get(1).AsUint() +} diff --git a/ethchain/dagger.go b/ethchain/dagger.go new file mode 100644 index 000000000..5b4f8b2cd --- /dev/null +++ b/ethchain/dagger.go @@ -0,0 +1,199 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/sha3" + "hash" + "log" + "math/big" + "math/rand" + "time" +) + +type PoW interface { + Search(block *Block) []byte + Verify(hash []byte, diff *big.Int, nonce []byte) bool +} + +type EasyPow struct { + hash *big.Int +} + +func (pow *EasyPow) Search(block *Block) []byte { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + hash := block.HashNoNonce() + diff := block.Difficulty + for { + sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) + if pow.Verify(hash, diff, sha) { + return sha + } + } + + return nil +} + +func (pow *EasyPow) Verify(hash []byte, diff *big.Int, nonce []byte) bool { + sha := sha3.NewKeccak256() + + d := append(hash, nonce...) + sha.Write(d) + + v := ethutil.BigPow(2, 256) + ret := new(big.Int).Div(v, diff) + + res := new(big.Int) + res.SetBytes(sha.Sum(nil)) + + return res.Cmp(ret) == -1 +} + +func (pow *EasyPow) SetHash(hash *big.Int) { +} + +type Dagger struct { + hash *big.Int + xn *big.Int +} + +var Found bool + +func (dag *Dagger) Find(obj *big.Int, resChan chan int64) { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + for i := 0; i < 1000; i++ { + rnd := r.Int63() + + res := dag.Eval(big.NewInt(rnd)) + log.Printf("rnd %v\nres %v\nobj %v\n", rnd, res, obj) + if res.Cmp(obj) < 0 { + // Post back result on the channel + resChan <- rnd + // Notify other threads we've found a valid nonce + Found = true + } + + // Break out if found + if Found { + break + } + } + + resChan <- 0 +} + +func (dag *Dagger) Search(hash, diff *big.Int) *big.Int { + // TODO fix multi threading. Somehow it results in the wrong nonce + amountOfRoutines := 1 + + dag.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + Found = false + resChan := make(chan int64, 3) + var res int64 + + for k := 0; k < amountOfRoutines; k++ { + go dag.Find(obj, resChan) + } + + // Wait for each go routine to finish + for k := 0; k < amountOfRoutines; k++ { + // Get the result from the channel. 0 = quit + if r := <-resChan; r != 0 { + res = r + } + } + + return big.NewInt(res) +} + +func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool { + dag.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + return dag.Eval(nonce).Cmp(obj) < 0 +} + +func DaggerVerify(hash, diff, nonce *big.Int) bool { + dagger := &Dagger{} + dagger.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + return dagger.Eval(nonce).Cmp(obj) < 0 +} + +func (dag *Dagger) Node(L uint64, i uint64) *big.Int { + if L == i { + return dag.hash + } + + var m *big.Int + if L == 9 { + m = big.NewInt(16) + } else { + m = big.NewInt(3) + } + + sha := sha3.NewKeccak256() + sha.Reset() + d := sha3.NewKeccak256() + b := new(big.Int) + ret := new(big.Int) + + for k := 0; k < int(m.Uint64()); k++ { + d.Reset() + d.Write(dag.hash.Bytes()) + d.Write(dag.xn.Bytes()) + d.Write(big.NewInt(int64(L)).Bytes()) + d.Write(big.NewInt(int64(i)).Bytes()) + d.Write(big.NewInt(int64(k)).Bytes()) + + b.SetBytes(Sum(d)) + pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1) + sha.Write(dag.Node(L-1, pk).Bytes()) + } + + ret.SetBytes(Sum(sha)) + + return ret +} + +func Sum(sha hash.Hash) []byte { + //in := make([]byte, 32) + return sha.Sum(nil) +} + +func (dag *Dagger) Eval(N *big.Int) *big.Int { + pow := ethutil.BigPow(2, 26) + dag.xn = pow.Div(N, pow) + + sha := sha3.NewKeccak256() + sha.Reset() + ret := new(big.Int) + + for k := 0; k < 4; k++ { + d := sha3.NewKeccak256() + b := new(big.Int) + + d.Reset() + d.Write(dag.hash.Bytes()) + d.Write(dag.xn.Bytes()) + d.Write(N.Bytes()) + d.Write(big.NewInt(int64(k)).Bytes()) + + b.SetBytes(Sum(d)) + pk := (b.Uint64() & 0x1ffffff) + + sha.Write(dag.Node(9, pk).Bytes()) + } + + return ret.SetBytes(Sum(sha)) +} diff --git a/ethchain/dagger_test.go b/ethchain/dagger_test.go new file mode 100644 index 000000000..9d4e03c92 --- /dev/null +++ b/ethchain/dagger_test.go @@ -0,0 +1,18 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" + "testing" +) + +func BenchmarkDaggerSearch(b *testing.B) { + hash := big.NewInt(0) + diff := ethutil.BigPow(2, 36) + o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity + + // Reset timer so the big generation isn't included in the benchmark + b.ResetTimer() + // Validate + DaggerVerify(hash, diff, o) +} diff --git a/ethchain/error.go b/ethchain/error.go new file mode 100644 index 000000000..0f1d061c0 --- /dev/null +++ b/ethchain/error.go @@ -0,0 +1,42 @@ +package ethchain + +import "fmt" + +// Parent error. In case a parent is unknown this error will be thrown +// by the block manager +type ParentErr struct { + Message string +} + +func (err *ParentErr) Error() string { + return err.Message +} + +func ParentError(hash []byte) error { + return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)} +} + +func IsParentErr(err error) bool { + _, ok := err.(*ParentErr) + + return ok +} + +// Block validation error. If any validation fails, this error will be thrown +type ValidationErr struct { + Message string +} + +func (err *ValidationErr) Error() string { + return err.Message +} + +func ValidationError(format string, v ...interface{}) *ValidationErr { + return &ValidationErr{Message: fmt.Sprintf(format, v...)} +} + +func IsValidationErr(err error) bool { + _, ok := err.(*ValidationErr) + + return ok +} diff --git a/ethchain/fees.go b/ethchain/fees.go new file mode 100644 index 000000000..8f1646ab4 --- /dev/null +++ b/ethchain/fees.go @@ -0,0 +1,65 @@ +package ethchain + +import ( + "math/big" +) + +var StepFee *big.Int = new(big.Int) +var TxFeeRat *big.Int = big.NewInt(100000000000000) +var TxFee *big.Int = big.NewInt(100) +var ContractFee *big.Int = new(big.Int) +var MemFee *big.Int = new(big.Int) +var DataFee *big.Int = new(big.Int) +var CryptoFee *big.Int = new(big.Int) +var ExtroFee *big.Int = new(big.Int) + +var BlockReward *big.Int = big.NewInt(1500000000000000000) +var Period1Reward *big.Int = new(big.Int) +var Period2Reward *big.Int = new(big.Int) +var Period3Reward *big.Int = new(big.Int) +var Period4Reward *big.Int = new(big.Int) + +func InitFees() { + /* + // Base for 2**64 + b60 := new(big.Int) + b60.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) + // Base for 2**80 + b80 := new(big.Int) + b80.Exp(big.NewInt(2), big.NewInt(80), big.NewInt(0)) + + StepFee.Exp(big.NewInt(10), big.NewInt(16), big.NewInt(0)) + //StepFee.Div(b60, big.NewInt(64)) + //fmt.Println("StepFee:", StepFee) + + TxFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) + //fmt.Println("TxFee:", TxFee) + + ContractFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) + //fmt.Println("ContractFee:", ContractFee) + + MemFee.Div(b60, big.NewInt(4)) + //fmt.Println("MemFee:", MemFee) + + DataFee.Div(b60, big.NewInt(16)) + //fmt.Println("DataFee:", DataFee) + + CryptoFee.Div(b60, big.NewInt(16)) + //fmt.Println("CrytoFee:", CryptoFee) + + ExtroFee.Div(b60, big.NewInt(16)) + //fmt.Println("ExtroFee:", ExtroFee) + + Period1Reward.Mul(b80, big.NewInt(1024)) + //fmt.Println("Period1Reward:", Period1Reward) + + Period2Reward.Mul(b80, big.NewInt(512)) + //fmt.Println("Period2Reward:", Period2Reward) + + Period3Reward.Mul(b80, big.NewInt(256)) + //fmt.Println("Period3Reward:", Period3Reward) + + Period4Reward.Mul(b80, big.NewInt(128)) + //fmt.Println("Period4Reward:", Period4Reward) + */ +} diff --git a/ethchain/genesis.go b/ethchain/genesis.go new file mode 100644 index 000000000..060d347e4 --- /dev/null +++ b/ethchain/genesis.go @@ -0,0 +1,39 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +/* + * This is the special genesis block. + */ + +var ZeroHash256 = make([]byte, 32) +var ZeroHash160 = make([]byte, 20) +var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) + +var GenisisHeader = []interface{}{ + // Previous hash (none) + //"", + ZeroHash256, + // Sha of uncles + ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + // Coinbase + ZeroHash160, + // Root state + "", + // Sha of transactions + //EmptyShaList, + ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + // Difficulty + ethutil.BigPow(2, 22), + // Time + int64(0), + // Extra + "", + // Nonce + ethutil.Sha3Bin(big.NewInt(42).Bytes()), +} + +var Genesis = []interface{}{GenisisHeader, []interface{}{}, []interface{}{}} diff --git a/ethchain/stack.go b/ethchain/stack.go new file mode 100644 index 000000000..c80d01e5c --- /dev/null +++ b/ethchain/stack.go @@ -0,0 +1,167 @@ +package ethchain + +import ( + "fmt" + "math/big" +) + +type OpCode int + +// Op codes +const ( + oSTOP OpCode = iota + oADD + oMUL + oSUB + oDIV + oSDIV + oMOD + oSMOD + oEXP + oNEG + oLT + oLE + oGT + oGE + oEQ + oNOT + oMYADDRESS + oTXSENDER + oTXVALUE + oTXFEE + oTXDATAN + oTXDATA + oBLK_PREVHASH + oBLK_COINBASE + oBLK_TIMESTAMP + oBLK_NUMBER + oBLK_DIFFICULTY + oBASEFEE + oSHA256 OpCode = 32 + oRIPEMD160 OpCode = 33 + oECMUL OpCode = 34 + oECADD OpCode = 35 + oECSIGN OpCode = 36 + oECRECOVER OpCode = 37 + oECVALID OpCode = 38 + oSHA3 OpCode = 39 + oPUSH OpCode = 48 + oPOP OpCode = 49 + oDUP OpCode = 50 + oSWAP OpCode = 51 + oMLOAD OpCode = 52 + oMSTORE OpCode = 53 + oSLOAD OpCode = 54 + oSSTORE OpCode = 55 + oJMP OpCode = 56 + oJMPI OpCode = 57 + oIND OpCode = 58 + oEXTRO OpCode = 59 + oBALANCE OpCode = 60 + oMKTX OpCode = 61 + oSUICIDE OpCode = 62 +) + +// Since the opcodes aren't all in order we can't use a regular slice +var opCodeToString = map[OpCode]string{ + oSTOP: "STOP", + oADD: "ADD", + oMUL: "MUL", + oSUB: "SUB", + oDIV: "DIV", + oSDIV: "SDIV", + oMOD: "MOD", + oSMOD: "SMOD", + oEXP: "EXP", + oNEG: "NEG", + oLT: "LT", + oLE: "LE", + oGT: "GT", + oGE: "GE", + oEQ: "EQ", + oNOT: "NOT", + oMYADDRESS: "MYADDRESS", + oTXSENDER: "TXSENDER", + oTXVALUE: "TXVALUE", + oTXFEE: "TXFEE", + oTXDATAN: "TXDATAN", + oTXDATA: "TXDATA", + oBLK_PREVHASH: "BLK_PREVHASH", + oBLK_COINBASE: "BLK_COINBASE", + oBLK_TIMESTAMP: "BLK_TIMESTAMP", + oBLK_NUMBER: "BLK_NUMBER", + oBLK_DIFFICULTY: "BLK_DIFFICULTY", + oBASEFEE: "BASEFEE", + oSHA256: "SHA256", + oRIPEMD160: "RIPEMD160", + oECMUL: "ECMUL", + oECADD: "ECADD", + oECSIGN: "ECSIGN", + oECRECOVER: "ECRECOVER", + oECVALID: "ECVALID", + oSHA3: "SHA3", + oPUSH: "PUSH", + oPOP: "POP", + oDUP: "DUP", + oSWAP: "SWAP", + oMLOAD: "MLOAD", + oMSTORE: "MSTORE", + oSLOAD: "SLOAD", + oSSTORE: "SSTORE", + oJMP: "JMP", + oJMPI: "JMPI", + oIND: "IND", + oEXTRO: "EXTRO", + oBALANCE: "BALANCE", + oMKTX: "MKTX", + oSUICIDE: "SUICIDE", +} + +func (o OpCode) String() string { + return opCodeToString[o] +} + +type OpType int + +const ( + tNorm = iota + tData + tExtro + tCrypto +) + +type TxCallback func(opType OpType) bool + +// Simple push/pop stack mechanism +type Stack struct { + data []*big.Int +} + +func NewStack() *Stack { + return &Stack{} +} + +func (st *Stack) Pop() *big.Int { + s := len(st.data) + + str := st.data[s-1] + st.data = st.data[:s-1] + + return str +} + +func (st *Stack) Popn() (*big.Int, *big.Int) { + s := len(st.data) + + ints := st.data[s-2:] + st.data = st.data[:s-2] + + return ints[0], ints[1] +} + +func (st *Stack) Push(d *big.Int) { + st.data = append(st.data, d) +} +func (st *Stack) Print() { + fmt.Println(st.data) +} diff --git a/ethchain/transaction.go b/ethchain/transaction.go new file mode 100644 index 000000000..1a9258201 --- /dev/null +++ b/ethchain/transaction.go @@ -0,0 +1,157 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" + "math/big" +) + +type Transaction struct { + Nonce uint64 + Recipient []byte + Value *big.Int + Data []string + Memory []int + v byte + r, s []byte +} + +func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { + tx := Transaction{Recipient: to, Value: value} + tx.Nonce = 0 + + // Serialize the data + tx.Data = make([]string, len(data)) + for i, val := range data { + instr, err := ethutil.CompileInstr(val) + if err != nil { + //fmt.Printf("compile error:%d %v\n", i+1, err) + } + + tx.Data[i] = instr + } + + return &tx +} + +func NewTransactionFromData(data []byte) *Transaction { + tx := &Transaction{} + tx.RlpDecode(data) + + return tx +} + +func NewTransactionFromValue(val *ethutil.Value) *Transaction { + tx := &Transaction{} + tx.RlpValueDecode(val) + + return tx +} + +func (tx *Transaction) Hash() []byte { + data := make([]interface{}, len(tx.Data)) + for i, val := range tx.Data { + data[i] = val + } + + preEnc := []interface{}{ + tx.Nonce, + tx.Recipient, + tx.Value, + data, + } + + return ethutil.Sha3Bin(ethutil.Encode(preEnc)) +} + +func (tx *Transaction) IsContract() bool { + return len(tx.Recipient) == 0 +} + +func (tx *Transaction) Signature(key []byte) []byte { + hash := tx.Hash() + + sig, _ := secp256k1.Sign(hash, key) + + return sig +} + +func (tx *Transaction) PublicKey() []byte { + hash := tx.Hash() + + // If we don't make a copy we will overwrite the existing underlying array + dst := make([]byte, len(tx.r)) + copy(dst, tx.r) + + sig := append(dst, tx.s...) + sig = append(sig, tx.v-27) + + pubkey, _ := secp256k1.RecoverPubkey(hash, sig) + + return pubkey +} + +func (tx *Transaction) Sender() []byte { + pubkey := tx.PublicKey() + + // Validate the returned key. + // Return nil if public key isn't in full format + if pubkey[0] != 4 { + return nil + } + + return ethutil.Sha3Bin(pubkey[1:])[12:] +} + +func (tx *Transaction) Sign(privk []byte) error { + + sig := tx.Signature(privk) + + tx.r = sig[:32] + tx.s = sig[32:64] + tx.v = sig[64] + 27 + + return nil +} + +func (tx *Transaction) RlpData() interface{} { + // Prepare the transaction for serialization + return []interface{}{ + tx.Nonce, + tx.Recipient, + tx.Value, + ethutil.NewSliceValue(tx.Data).Slice(), + tx.v, + tx.r, + tx.s, + } +} + +func (tx *Transaction) RlpValue() *ethutil.Value { + return ethutil.NewValue(tx.RlpData()) +} + +func (tx *Transaction) RlpEncode() []byte { + return tx.RlpValue().Encode() +} + +func (tx *Transaction) RlpDecode(data []byte) { + tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) +} + +func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { + tx.Nonce = decoder.Get(0).Uint() + tx.Recipient = decoder.Get(1).Bytes() + tx.Value = decoder.Get(2).BigInt() + + d := decoder.Get(3) + tx.Data = make([]string, d.Len()) + for i := 0; i < d.Len(); i++ { + tx.Data[i] = d.Get(i).Str() + } + + // TODO something going wrong here + tx.v = byte(decoder.Get(4).Uint()) + tx.r = decoder.Get(5).Bytes() + tx.s = decoder.Get(6).Bytes() +} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go new file mode 100644 index 000000000..c2d65a2a7 --- /dev/null +++ b/ethchain/transaction_pool.go @@ -0,0 +1,219 @@ +package ethchain + +import ( + "bytes" + "container/list" + "errors" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" + "log" + "math/big" + "sync" +) + +const ( + txPoolQueueSize = 50 +) + +type TxPoolHook chan *Transaction + +func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction { + for e := pool.Front(); e != nil; e = e.Next() { + if tx, ok := e.Value.(*Transaction); ok { + if finder(tx, e) { + return tx + } + } + } + + return nil +} + +type PublicSpeaker interface { + Broadcast(msgType ethwire.MsgType, data []interface{}) +} + +// The tx pool a thread safe transaction pool handler. In order to +// guarantee a non blocking pool we use a queue channel which can be +// independently read without needing access to the actual pool. If the +// pool is being drained or synced for whatever reason the transactions +// will simple queue up and handled when the mutex is freed. +type TxPool struct { + //server *Server + Speaker PublicSpeaker + // The mutex for accessing the Tx pool. + mutex sync.Mutex + // Queueing channel for reading and writing incoming + // transactions to + queueChan chan *Transaction + // Quiting channel + quit chan bool + // The actual pool + pool *list.List + + BlockManager *BlockManager + + Hook TxPoolHook +} + +func NewTxPool() *TxPool { + return &TxPool{ + //server: s, + mutex: sync.Mutex{}, + pool: list.New(), + queueChan: make(chan *Transaction, txPoolQueueSize), + quit: make(chan bool), + } +} + +// Blocking function. Don't use directly. Use QueueTransaction instead +func (pool *TxPool) addTransaction(tx *Transaction) { + pool.mutex.Lock() + pool.pool.PushBack(tx) + pool.mutex.Unlock() + + // Broadcast the transaction to the rest of the peers + pool.Speaker.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) +} + +// Process transaction validates the Tx and processes funds from the +// sender to the recipient. +func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) { + log.Printf("[TXPL] Processing Tx %x\n", tx.Hash()) + + defer func() { + if r := recover(); r != nil { + log.Println(r) + err = fmt.Errorf("%v", r) + } + }() + // Get the sender + sender := block.GetAddr(tx.Sender()) + + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + if sender.Amount.Cmp(totAmount) < 0 { + return errors.New("Insufficient amount in sender's account") + } + + if sender.Nonce != tx.Nonce { + if ethutil.Config.Debug { + return fmt.Errorf("Invalid nonce %d(%d) continueing anyway", tx.Nonce, sender.Nonce) + } else { + return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce) + } + } + + // Subtract the amount from the senders account + sender.Amount.Sub(sender.Amount, totAmount) + sender.Nonce += 1 + + // Get the receiver + receiver := block.GetAddr(tx.Recipient) + // Add the amount to receivers account which should conclude this transaction + receiver.Amount.Add(receiver.Amount, tx.Value) + + block.UpdateAddr(tx.Sender(), sender) + block.UpdateAddr(tx.Recipient, receiver) + + return +} + +func (pool *TxPool) ValidateTransaction(tx *Transaction) error { + // Get the last block so we can retrieve the sender and receiver from + // the merkle trie + block := pool.BlockManager.BlockChain().CurrentBlock + // Something has gone horribly wrong if this happens + if block == nil { + return errors.New("No last block on the block chain") + } + + // Get the sender + sender := block.GetAddr(tx.Sender()) + + totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + if sender.Amount.Cmp(totAmount) < 0 { + return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender()) + } + + // Increment the nonce making each tx valid only once to prevent replay + // attacks + + return nil +} + +func (pool *TxPool) queueHandler() { +out: + for { + select { + case tx := <-pool.queueChan: + hash := tx.Hash() + foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { + return bytes.Compare(tx.Hash(), hash) == 0 + }) + + if foundTx != nil { + break + } + + // Validate the transaction + err := pool.ValidateTransaction(tx) + if err != nil { + if ethutil.Config.Debug { + log.Println("Validating Tx failed", err) + } + } else { + // Call blocking version. At this point it + // doesn't matter since this is a goroutine + pool.addTransaction(tx) + + if pool.Hook != nil { + pool.Hook <- tx + } + } + case <-pool.quit: + break out + } + } +} + +func (pool *TxPool) QueueTransaction(tx *Transaction) { + pool.queueChan <- tx +} + +func (pool *TxPool) Flush() []*Transaction { + pool.mutex.Lock() + defer pool.mutex.Unlock() + + txList := make([]*Transaction, pool.pool.Len()) + i := 0 + for e := pool.pool.Front(); e != nil; e = e.Next() { + if tx, ok := e.Value.(*Transaction); ok { + txList[i] = tx + } + + i++ + } + + // Recreate a new list all together + // XXX Is this the fastest way? + pool.pool = list.New() + + return txList +} + +func (pool *TxPool) Start() { + go pool.queueHandler() +} + +func (pool *TxPool) Stop() { + log.Println("[TXP] Stopping...") + + close(pool.quit) + + pool.Flush() +} diff --git a/ethchain/transaction_test.go b/ethchain/transaction_test.go new file mode 100644 index 000000000..c9090b83d --- /dev/null +++ b/ethchain/transaction_test.go @@ -0,0 +1,54 @@ +package ethchain + +import ( + "encoding/hex" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" + "testing" +) + +func TestAddressRetrieval(t *testing.T) { + // TODO + // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f + key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4") + + tx := &Transaction{ + Nonce: 0, + Recipient: ZeroHash160, + Value: big.NewInt(0), + Data: nil, + } + //fmt.Printf("rlp %x\n", tx.RlpEncode()) + //fmt.Printf("sha rlp %x\n", tx.Hash()) + + tx.Sign(key) + + //fmt.Printf("hex tx key %x\n", tx.PublicKey()) + //fmt.Printf("seder %x\n", tx.Sender()) +} + +func TestAddressRetrieval2(t *testing.T) { + // TODO + // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f + key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4") + addr, _ := hex.DecodeString("944400f4b88ac9589a0f17ed4671da26bddb668b") + tx := &Transaction{ + Nonce: 0, + Recipient: addr, + Value: big.NewInt(1000), + Data: nil, + } + tx.Sign(key) + //data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7") + //tx := NewTransactionFromData(data) + fmt.Println(tx.RlpValue()) + + fmt.Printf("rlp %x\n", tx.RlpEncode()) + fmt.Printf("sha rlp %x\n", tx.Hash()) + + //tx.Sign(key) + + fmt.Printf("hex tx key %x\n", tx.PublicKey()) + fmt.Printf("seder %x\n", tx.Sender()) +} -- cgit v1.2.3 From 73fd358d940418b15dec850f50407bd2e504d88c Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 01:34:18 +0100 Subject: Removed RlpValue in favour of Value --- ethchain/block.go | 8 ++++---- ethchain/block_chain.go | 2 +- ethchain/block_manager.go | 8 ++++---- ethchain/contract.go | 14 +++++++------- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index a7a1f787b..0678f64e2 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -102,7 +102,7 @@ func CreateBlock(root interface{}, // Returns a hash of the block func (block *Block) Hash() []byte { - return ethutil.Sha3Bin(block.RlpValue().Encode()) + return ethutil.Sha3Bin(block.Value().Encode()) } func (block *Block) HashNoNonce() []byte { @@ -261,14 +261,14 @@ func (block *Block) SetTransactions(txs []*Transaction) { 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) Value() *ethutil.Value { + return ethutil.NewValue([]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() + return block.Value().Encode() } func (block *Block) RlpDecode(data []byte) { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 56bc43a8e..54f48bc60 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -103,7 +103,7 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { block := bc.GetBlock(currentHash) currentHash = block.PrevHash - chain = append(chain, block.RlpValue().Value) + chain = append(chain, block.Value().Val) //chain = append([]interface{}{block.RlpValue().Value}, chain...) num-- diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 92f20e253..7d8397790 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -553,9 +553,9 @@ out: // 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()))) + decoder := ethutil.NewValueFromBytes([]byte(contract.State().Get(x.String()))) if !decoder.IsNil() { - bm.stack.Push(decoder.AsBigInt()) + bm.stack.Push(decoder.BigInt()) } else { bm.stack.Push(ethutil.BigFalse) } @@ -618,10 +618,10 @@ func getContractMemory(block *Block, contractAddr []byte, memAddr *big.Int) *big val := contract.State().Get(memAddr.String()) // decode the object as a big integer - decoder := ethutil.NewRlpValueFromBytes([]byte(val)) + decoder := ethutil.NewValueFromBytes([]byte(val)) if decoder.IsNil() { return ethutil.BigFalse } - return decoder.AsBigInt() + return decoder.BigInt() } diff --git a/ethchain/contract.go b/ethchain/contract.go index d1fcec3b4..70189593b 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -23,11 +23,11 @@ func (c *Contract) RlpEncode() []byte { } func (c *Contract) RlpDecode(data []byte) { - decoder := ethutil.NewRlpValueFromBytes(data) + decoder := ethutil.NewValueFromBytes(data) - c.Amount = decoder.Get(0).AsBigInt() - c.Nonce = decoder.Get(1).AsUint() - c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).AsRaw()) + c.Amount = decoder.Get(0).BigInt() + c.Nonce = decoder.Get(1).Uint() + c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()) } func (c *Contract) State() *ethutil.Trie { @@ -59,8 +59,8 @@ func (a *Address) RlpEncode() []byte { } func (a *Address) RlpDecode(data []byte) { - decoder := ethutil.NewRlpValueFromBytes(data) + decoder := ethutil.NewValueFromBytes(data) - a.Amount = decoder.Get(0).AsBigInt() - a.Nonce = decoder.Get(1).AsUint() + a.Amount = decoder.Get(0).BigInt() + a.Nonce = decoder.Get(1).Uint() } -- cgit v1.2.3 From f5fbbb147fc84297bba0f72856573f1ca6444fec Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 12:11:40 +0100 Subject: Removed debug message --- ethchain/block_manager.go | 2 -- 1 file changed, 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 7d8397790..8b237a29a 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -71,9 +71,7 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { 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) -- cgit v1.2.3 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 From d65b4cd0dd49975410374801fae3ece7d7e087b3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Mar 2014 20:42:05 +0100 Subject: Updated block to use state instead of trie directly --- ethchain/block.go | 61 ++++++++++++++++++++++++-------------------- ethchain/block_chain.go | 2 +- ethchain/block_manager.go | 26 +++++++++---------- ethchain/state.go | 8 ++++++ ethchain/transaction_pool.go | 8 +++--- 5 files changed, 60 insertions(+), 45 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 7ca44a47d..8de57cced 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -34,7 +34,8 @@ type Block struct { // The coin base address Coinbase []byte // Block Trie state - state *ethutil.Trie + //state *ethutil.Trie + state *State // Difficulty for the current block Difficulty *big.Int // Creation time @@ -94,7 +95,7 @@ func CreateBlock(root interface{}, block.SetTransactions(txes) block.SetUncles([]*Block{}) - block.state = ethutil.NewTrie(ethutil.Config.Db, root) + block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) for _, tx := range txes { block.MakeContract(tx) @@ -109,15 +110,15 @@ func (block *Block) Hash() []byte { } 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})) + return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) } func (block *Block) PrintHash() { fmt.Println(block) - fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce}))) + fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce}))) } -func (block *Block) State() *ethutil.Trie { +func (block *Block) State() *State { return block.state } @@ -125,6 +126,7 @@ func (block *Block) Transactions() []*Transaction { return block.transactions } +/* func (block *Block) GetContract(addr []byte) *Contract { data := block.state.Get(string(addr)) if data == "" { @@ -152,13 +154,13 @@ 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())) + block.state.trie.Update(string(addr), string(contract.RlpEncode())) } func (block *Block) GetAddr(addr []byte) *Address { var address *Address - data := block.State().Get(string(addr)) + data := block.state.trie.Get(string(addr)) if data == "" { address = NewAddress(big.NewInt(0)) } else { @@ -168,11 +170,12 @@ func (block *Block) GetAddr(addr []byte) *Address { return address } func (block *Block) UpdateAddr(addr []byte, address *Address) { - block.state.Update(string(addr), string(address.RlpEncode())) + block.state.trie.Update(string(addr), string(address.RlpEncode())) } +*/ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { - contract := block.GetContract(addr) + contract := block.state.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) @@ -182,9 +185,9 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { base := new(big.Int) contract.Amount = base.Sub(contract.Amount, fee) - block.state.Update(string(addr), string(contract.RlpEncode())) + block.state.trie.Update(string(addr), string(contract.RlpEncode())) - data := block.state.Get(string(block.Coinbase)) + data := block.state.trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) ether := NewAddressFromData([]byte(data)) @@ -192,7 +195,7 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { base = new(big.Int) ether.Amount = base.Add(ether.Amount, fee) - block.state.Update(string(block.Coinbase), string(ether.RlpEncode())) + block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) return true } @@ -207,25 +210,29 @@ func (block *Block) BlockInfo() BlockInfo { // 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 all contracts currently in cache + for _, val := range block.contractStates { + val.Sync() + } + */ // Sync the block state itself - block.state.Sync() + block.state.trie.Sync() } func (block *Block) Undo() { - // Sync all contracts currently in cache - for _, val := range block.contractStates { - val.Undo() - } + /* + // Sync all contracts currently in cache + for _, val := range block.contractStates { + val.Undo() + } + */ // Sync the block state itself - block.state.Undo() + block.state.Reset() } func (block *Block) MakeContract(tx *Transaction) { - contract := MakeContract(tx, NewState(block.state)) + contract := MakeContract(tx, block.state) if contract != nil { block.contractStates[string(tx.Hash()[12:])] = contract.state } @@ -308,7 +315,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { 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.state = NewState(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()) @@ -345,7 +352,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *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.state = NewState(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()) @@ -356,7 +363,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\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)) + return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) } //////////// UNEXPORTED ///////////////// @@ -369,7 +376,7 @@ func (block *Block) header() []interface{} { // Coinbase address block.Coinbase, // root state - block.state.Root, + block.state.trie.Root, // Sha of tx block.TxSha, // Current block Difficulty diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 96d22366d..026fc1cea 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -39,7 +39,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { hash := ZeroHash256 if bc.CurrentBlock != nil { - root = bc.CurrentBlock.State().Root + root = bc.CurrentBlock.state.trie.Root hash = bc.LastBlockHash lastBlockTime = bc.CurrentBlock.Time } diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 364a06158..8ea71ab31 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -51,9 +51,9 @@ func AddTestNetFunds(block *Block) { } { //log.Println("2^200 Wei to", addr) codedAddr, _ := hex.DecodeString(addr) - addr := block.GetAddr(codedAddr) + addr := block.state.GetAccount(codedAddr) addr.Amount = ethutil.BigPow(2, 200) - block.UpdateAddr(codedAddr, addr) + block.state.UpdateAccount(codedAddr, addr) } } @@ -71,7 +71,7 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { if bm.bc.CurrentBlock == nil { AddTestNetFunds(bm.bc.genesisBlock) - bm.bc.genesisBlock.State().Sync() + bm.bc.genesisBlock.state.trie.Sync() // Prepare the genesis block bm.bc.Add(bm.bc.genesisBlock) @@ -86,7 +86,7 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { // 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) + account := bm.bc.CurrentBlock.state.GetAccount(addr) return bm.addrStateStore.Add(addr, account) } @@ -94,7 +94,7 @@ func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { func (bm *BlockManager) GetAddrState(addr []byte) *AddressState { account := bm.addrStateStore.Get(addr) if account == nil { - a := bm.bc.CurrentBlock.GetAddr(addr) + a := bm.bc.CurrentBlock.state.GetAccount(addr) account = &AddressState{Nonce: a.Nonce, Account: a} } @@ -112,7 +112,7 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { if tx.IsContract() { block.MakeContract(tx) } else { - if contract := block.GetContract(tx.Recipient); contract != nil { + if contract := block.state.GetContract(tx.Recipient); contract != nil { bm.ProcessContract(contract, tx, block) } else { err := bm.TransactionPool.ProcessTransaction(tx, block) @@ -161,8 +161,8 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { return err } - if !block.State().Cmp(bm.bc.CurrentBlock.State()) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().Root, bm.bc.CurrentBlock.State().Root) + if !block.state.Cmp(bm.bc.CurrentBlock.state) { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, bm.bc.CurrentBlock.State().trie.Root) } // Calculate the new total difficulty and sync back to the db @@ -267,17 +267,17 @@ func CalculateUncleReward(block *Block) *big.Int { func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { // Get the coinbase rlp data - addr := processor.GetAddr(block.Coinbase) + addr := processor.state.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - processor.UpdateAddr(block.Coinbase, addr) + processor.state.UpdateAccount(block.Coinbase, addr) for _, uncle := range block.Uncles { - uncleAddr := processor.GetAddr(uncle.Coinbase) + uncleAddr := processor.state.GetAccount(uncle.Coinbase) uncleAddr.AddFee(CalculateUncleReward(uncle)) - processor.UpdateAddr(uncle.Coinbase, uncleAddr) + processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) } return nil @@ -298,7 +298,7 @@ func (bm *BlockManager) ProcessContract(contract *Contract, tx *Transaction, blo */ vm := &Vm{} - vm.Process(contract, NewState(block.state), RuntimeVars{ + vm.Process(contract, block.state, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, sender: tx.Sender(), diff --git a/ethchain/state.go b/ethchain/state.go index 1a18ea1d7..cff192b54 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -13,6 +13,10 @@ func NewState(trie *ethutil.Trie) *State { return &State{trie: trie} } +func (s *State) Reset() { + s.trie.Undo() +} + func (s *State) GetContract(addr []byte) *Contract { data := s.trie.Get(string(addr)) if data == "" { @@ -54,3 +58,7 @@ func (s *State) GetAccount(addr []byte) (account *Address) { func (s *State) UpdateAccount(addr []byte, account *Address) { s.trie.Update(string(addr), string(account.RlpEncode())) } + +func (s *State) Cmp(other *State) bool { + return s.trie.Cmp(other.trie) +} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index cd09bf02e..763560570 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -104,7 +104,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } }() // Get the sender - sender := block.GetAddr(tx.Sender()) + sender := block.state.GetAccount(tx.Sender()) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. @@ -122,7 +122,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } // Get the receiver - receiver := block.GetAddr(tx.Recipient) + receiver := block.state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self @@ -136,10 +136,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error // Add the amount to receivers account which should conclude this transaction receiver.Amount.Add(receiver.Amount, tx.Value) - block.UpdateAddr(tx.Recipient, receiver) + block.state.UpdateAccount(tx.Recipient, receiver) } - block.UpdateAddr(tx.Sender(), sender) + block.state.UpdateAccount(tx.Sender(), sender) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) -- cgit v1.2.3 From bfed1c7cac98e135ba176c03bd7b4fe51c0dc932 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Mar 2014 11:03:16 +0100 Subject: Trie's are no longer referenced directly but through State instead --- ethchain/block.go | 65 ++-------------------------------------------------- ethchain/contract.go | 17 +++++++------- ethchain/state.go | 51 ++++++++++++++++++++++++++++++++++++++++- ethchain/vm.go | 4 ++-- 4 files changed, 63 insertions(+), 74 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 8de57cced..b5739102c 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -126,54 +126,6 @@ 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 - } - - value := ethutil.NewValueFromBytes([]byte(data)) - if value.Len() == 2 { - return nil - } - - 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) { - // Make sure the state is synced - //contract.State().Sync() - - block.state.trie.Update(string(addr), string(contract.RlpEncode())) -} - -func (block *Block) GetAddr(addr []byte) *Address { - var address *Address - - data := block.state.trie.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.trie.Update(string(addr), string(address.RlpEncode())) -} -*/ - func (block *Block) PayFee(addr []byte, fee *big.Int) bool { contract := block.state.GetContract(addr) // If we can't pay the fee return @@ -210,23 +162,10 @@ func (block *Block) BlockInfo() BlockInfo { // 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.trie.Sync() + 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.Reset() } @@ -234,7 +173,7 @@ func (block *Block) Undo() { func (block *Block) MakeContract(tx *Transaction) { contract := MakeContract(tx, block.state) if contract != nil { - block.contractStates[string(tx.Hash()[12:])] = contract.state + block.state.states[string(tx.Hash()[12:])] = contract.state } } diff --git a/ethchain/contract.go b/ethchain/contract.go index dbcbb3697..21ac828fe 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -8,18 +8,19 @@ import ( type Contract struct { Amount *big.Int Nonce uint64 - state *ethutil.Trie + //state *ethutil.Trie + state *State } func NewContract(Amount *big.Int, root []byte) *Contract { contract := &Contract{Amount: Amount, Nonce: 0} - contract.state = ethutil.NewTrie(ethutil.Config.Db, string(root)) + contract.state = NewState(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}) + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) } func (c *Contract) RlpDecode(data []byte) { @@ -27,18 +28,18 @@ func (c *Contract) RlpDecode(data []byte) { c.Amount = decoder.Get(0).BigInt() c.Nonce = decoder.Get(1).Uint() - c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()) + c.state = NewState(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)))) + return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) } func (c *Contract) SetAddr(addr []byte, value interface{}) { - c.state.Update(string(addr), string(ethutil.NewValue(value).Encode())) + c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *Contract) State() *ethutil.Trie { +func (c *Contract) State() *State { return c.state } @@ -59,7 +60,7 @@ func MakeContract(tx *Transaction, state *State) *Contract { 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))) + contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val))) } } state.trie.Update(string(addr), string(contract.RlpEncode())) diff --git a/ethchain/state.go b/ethchain/state.go index cff192b54..4cd2c58ef 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -5,16 +5,46 @@ import ( "math/big" ) +// States within the ethereum protocol are used to store anything +// within the merkle trie. States take care of caching and storing +// nested states. It's the general query interface to retrieve: +// * Contracts +// * Accounts type State struct { + // The trie for this structure trie *ethutil.Trie + // Nested states + states map[string]*State } +// Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie} + return &State{trie: trie, states: make(map[string]*State)} } +// Resets the trie and all siblings func (s *State) Reset() { s.trie.Undo() + + // Reset all nested states + for _, state := range s.states { + state.Reset() + } +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + s.trie.Sync() + + // Sync all nested states + for _, state := range s.states { + state.Sync() + } +} + +// Purges the current trie. +func (s *State) Purge() int { + return s.trie.NewIterator().Purge() } func (s *State) GetContract(addr []byte) *Contract { @@ -23,9 +53,28 @@ func (s *State) GetContract(addr []byte) *Contract { return nil } + // Whet get contract is called the retrieved value might + // be an account. The StateManager uses this to check + // to see if the address a tx was sent to is a contract + // or an account + value := ethutil.NewValueFromBytes([]byte(data)) + if value.Len() == 2 { + return nil + } + + // build contract contract := &Contract{} contract.RlpDecode([]byte(data)) + // Check if there's a cached state for this contract + cachedState := s.states[string(addr)] + if cachedState != nil { + contract.state = cachedState + } else { + // If it isn't cached, cache the state + s.states[string(addr)] = contract.state + } + return contract } diff --git a/ethchain/vm.go b/ethchain/vm.go index c7a91a9c5..7e119ac99 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -330,7 +330,7 @@ out: // 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()))) + decoder := contract.Addr(x.Bytes()) if !decoder.IsNil() { vm.stack.Push(decoder.BigInt()) } else { @@ -375,7 +375,7 @@ out: case oSUICIDE: recAddr := vm.stack.Pop().Bytes() // Purge all memory - deletedMemory := contract.state.NewIterator().Purge() + deletedMemory := contract.state.Purge() // Add refunds to the pop'ed address refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) account := state.GetAccount(recAddr) -- cgit v1.2.3 From 9d492b0509d3614072e0f9ed9fd1dc560ba29fc9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Mar 2014 11:05:12 +0100 Subject: Renamed Address to Account --- ethchain/address.go | 30 +++++++++++++++--------------- ethchain/block.go | 2 +- ethchain/block_manager.go | 6 +++--- ethchain/state.go | 8 ++++---- 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'ethchain') diff --git a/ethchain/address.go b/ethchain/address.go index a228c7566..aa1709f2c 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -5,31 +5,31 @@ import ( "math/big" ) -type Address struct { +type Account struct { Amount *big.Int Nonce uint64 } -func NewAddress(amount *big.Int) *Address { - return &Address{Amount: amount, Nonce: 0} +func NewAccount(amount *big.Int) *Account { + return &Account{Amount: amount, Nonce: 0} } -func NewAddressFromData(data []byte) *Address { - address := &Address{} +func NewAccountFromData(data []byte) *Account { + address := &Account{} address.RlpDecode(data) return address } -func (a *Address) AddFee(fee *big.Int) { +func (a *Account) AddFee(fee *big.Int) { a.Amount.Add(a.Amount, fee) } -func (a *Address) RlpEncode() []byte { +func (a *Account) RlpEncode() []byte { return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) } -func (a *Address) RlpDecode(data []byte) { +func (a *Account) RlpDecode(data []byte) { decoder := ethutil.NewValueFromBytes(data) a.Amount = decoder.Get(0).BigInt() @@ -37,24 +37,24 @@ func (a *Address) RlpDecode(data []byte) { } type AddrStateStore struct { - states map[string]*AddressState + states map[string]*AccountState } func NewAddrStateStore() *AddrStateStore { - return &AddrStateStore{states: make(map[string]*AddressState)} + return &AddrStateStore{states: make(map[string]*AccountState)} } -func (s *AddrStateStore) Add(addr []byte, account *Address) *AddressState { - state := &AddressState{Nonce: account.Nonce, Account: account} +func (s *AddrStateStore) Add(addr []byte, account *Account) *AccountState { + state := &AccountState{Nonce: account.Nonce, Account: account} s.states[string(addr)] = state return state } -func (s *AddrStateStore) Get(addr []byte) *AddressState { +func (s *AddrStateStore) Get(addr []byte) *AccountState { return s.states[string(addr)] } -type AddressState struct { +type AccountState struct { Nonce uint64 - Account *Address + Account *Account } diff --git a/ethchain/block.go b/ethchain/block.go index b5739102c..20af73ba2 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -142,7 +142,7 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { data := block.state.trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) - ether := NewAddressFromData([]byte(data)) + ether := NewAccountFromData([]byte(data)) base = new(big.Int) ether.Amount = base.Add(ether.Amount, fee) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 8ea71ab31..b184fa9c9 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -85,17 +85,17 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { } // Watches any given address and puts it in the address state store -func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { +func (bm *BlockManager) WatchAddr(addr []byte) *AccountState { account := bm.bc.CurrentBlock.state.GetAccount(addr) return bm.addrStateStore.Add(addr, account) } -func (bm *BlockManager) GetAddrState(addr []byte) *AddressState { +func (bm *BlockManager) GetAddrState(addr []byte) *AccountState { account := bm.addrStateStore.Get(addr) if account == nil { a := bm.bc.CurrentBlock.state.GetAccount(addr) - account = &AddressState{Nonce: a.Nonce, Account: a} + account = &AccountState{Nonce: a.Nonce, Account: a} } return account diff --git a/ethchain/state.go b/ethchain/state.go index 4cd2c58ef..e6649cf22 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -93,18 +93,18 @@ func Compile(code []string) (script []string) { return } -func (s *State) GetAccount(addr []byte) (account *Address) { +func (s *State) GetAccount(addr []byte) (account *Account) { data := s.trie.Get(string(addr)) if data == "" { - account = NewAddress(big.NewInt(0)) + account = NewAccount(big.NewInt(0)) } else { - account = NewAddressFromData([]byte(data)) + account = NewAccountFromData([]byte(data)) } return } -func (s *State) UpdateAccount(addr []byte, account *Address) { +func (s *State) UpdateAccount(addr []byte, account *Account) { s.trie.Update(string(addr), string(account.RlpEncode())) } -- cgit v1.2.3 From 92f2abdf769f52ea8e5e6d02bf326744e926f5b4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 5 Mar 2014 10:42:51 +0100 Subject: Partially refactored server/txpool/block manager/block chain The Ethereum structure now complies to a EthManager interface which is being used by the tx pool, block manager and block chain in order to gain access to each other. It's become simpeler. TODO: BlockManager => StateManager --- ethchain/block_chain.go | 29 +++++++++++- ethchain/block_manager.go | 102 +++++++++++++++++++++++-------------------- ethchain/state.go | 38 ++++++++++++++++ ethchain/transaction_pool.go | 18 +++----- 4 files changed, 127 insertions(+), 60 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 026fc1cea..2865e0a21 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -9,6 +9,7 @@ import ( ) type BlockChain struct { + Ethereum EthManager // The famous, the fabulous Mister GENESIIIIIIS (block) genesisBlock *Block // Last known total difficulty @@ -20,7 +21,7 @@ type BlockChain struct { LastBlockHash []byte } -func NewBlockChain() *BlockChain { +func NewBlockChain(ethereum EthManager) *BlockChain { bc := &BlockChain{} bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) @@ -129,6 +130,21 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { return blocks } +func AddTestNetFunds(block *Block) { + for _, addr := range []string{ + "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin + "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey + "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex + } { + //log.Println("2^200 Wei to", addr) + codedAddr := ethutil.FromHex(addr) + addr := block.state.GetAccount(codedAddr) + addr.Amount = ethutil.BigPow(2, 200) + block.state.UpdateAccount(codedAddr, addr) + } +} + func (bc *BlockChain) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { @@ -139,10 +155,21 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockNumber = info.Number log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + } else { + AddTestNetFunds(bc.genesisBlock) + + bc.genesisBlock.state.trie.Sync() + // Prepare the genesis block + bc.Add(bc.genesisBlock) + + //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) + //bm.bc.genesisBlock.PrintHash() } // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) + + log.Printf("Last block: %x\n", bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index b184fa9c9..fa50304ea 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -2,11 +2,9 @@ package ethchain import ( "bytes" - "encoding/hex" "fmt" "github.com/ethereum/eth-go/ethutil" - _ "github.com/ethereum/eth-go/ethwire" - "log" + "github.com/ethereum/eth-go/ethwire" "math/big" "sync" "time" @@ -16,14 +14,20 @@ type BlockProcessor interface { ProcessBlock(block *Block) } +type EthManager interface { + StateManager() *BlockManager + BlockChain() *BlockChain + TxPool() *TxPool + Broadcast(msgType ethwire.MsgType, data []interface{}) +} + // 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 - // The block chain :) + // Canonical block chain bc *BlockChain - // States for addresses. You can watch any address // at any given time addrStateStore *AddrStateStore @@ -33,59 +37,41 @@ type BlockManager struct { // non-persistent key/value memory storage mem map[string]*big.Int - TransactionPool *TxPool - Pow PoW - Speaker PublicSpeaker + Ethereum EthManager SecondaryBlockProcessor BlockProcessor -} -func AddTestNetFunds(block *Block) { - for _, addr := range []string{ - "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin - "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey - "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - } { - //log.Println("2^200 Wei to", addr) - codedAddr, _ := hex.DecodeString(addr) - addr := block.state.GetAccount(codedAddr) - addr.Amount = ethutil.BigPow(2, 200) - block.state.UpdateAccount(codedAddr, addr) - } + // The managed states + // Processor state. Anything processed will be applied to this + // state + procState *State + // Comparative state it used for comparing and validating end + // results + compState *State } -func NewBlockManager(speaker PublicSpeaker) *BlockManager { +func NewBlockManager(ethereum EthManager) *BlockManager { bm := &BlockManager{ - //server: s, - bc: NewBlockChain(), stack: NewStack(), mem: make(map[string]*big.Int), Pow: &EasyPow{}, - Speaker: speaker, + Ethereum: ethereum, addrStateStore: NewAddrStateStore(), + bc: ethereum.BlockChain(), } - if bm.bc.CurrentBlock == nil { - AddTestNetFunds(bm.bc.genesisBlock) - - bm.bc.genesisBlock.state.trie.Sync() - // Prepare the genesis block - bm.bc.Add(bm.bc.genesisBlock) - - //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 } +func (bm *BlockManager) ProcState() *State { + return bm.procState +} + // Watches any given address and puts it in the address state store func (bm *BlockManager) WatchAddr(addr []byte) *AccountState { + //FIXME account := bm.procState.GetAccount(addr) account := bm.bc.CurrentBlock.state.GetAccount(addr) return bm.addrStateStore.Add(addr, account) @@ -105,17 +91,26 @@ func (bm *BlockManager) BlockChain() *BlockChain { return bm.bc } +func (bm *BlockManager) MakeContract(tx *Transaction) { + contract := MakeContract(tx, bm.procState) + if contract != nil { + bm.procState.states[string(tx.Hash()[12:])] = contract.state + } +} + 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() { + //FIXME bm.MakeContract(tx) block.MakeContract(tx) } else { + //FIXME if contract := procState.GetContract(tx.Recipient); contract != nil { if contract := block.state.GetContract(tx.Recipient); contract != nil { bm.ProcessContract(contract, tx, block) } else { - err := bm.TransactionPool.ProcessTransaction(tx, block) + err := bm.Ethereum.TxPool().ProcessTransaction(tx, block) if err != nil { ethutil.Config.Log.Infoln("[BMGR]", err) } @@ -124,6 +119,18 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { } } +// The prepare function, prepares the state manager for the next +// "ProcessBlock" action. +func (bm *BlockManager) Prepare(processer *State, comparative *State) { + bm.compState = comparative + bm.procState = processer +} + +// Default prepare function +func (bm *BlockManager) PrepareDefault(block *Block) { + bm.Prepare(bm.BlockChain().CurrentBlock.State(), block.State()) +} + // Block processing and validating with a given (temporarily) state func (bm *BlockManager) ProcessBlock(block *Block) error { // Processing a blocks may never happen simultaneously @@ -161,17 +168,20 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { return err } + // if !bm.compState.Cmp(bm.procState) if !block.state.Cmp(bm.bc.CurrentBlock.state) { return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, bm.bc.CurrentBlock.State().trie.Root) + //FIXME return fmt.Errorf("Invalid merkle root. Expected %x, got %x", bm.compState.trie.Root, bm.procState.trie.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 and cancelling out the deferred Undo bm.bc.CurrentBlock.Sync() + //FIXME bm.procState.Sync() // Broadcast the valid block back to the wire - //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + //bm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) // Add the block to the chain bm.bc.Add(block) @@ -207,12 +217,6 @@ func (bm *BlockManager) CalculateTD(block *Block) bool { // 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 } @@ -268,16 +272,19 @@ func CalculateUncleReward(block *Block) *big.Int { func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { // Get the coinbase rlp data addr := processor.state.GetAccount(block.Coinbase) + //FIXME addr := proc.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) processor.state.UpdateAccount(block.Coinbase, addr) + //FIXME proc.UpdateAccount(block.Coinbase, addr) for _, uncle := range block.Uncles { uncleAddr := processor.state.GetAccount(uncle.Coinbase) uncleAddr.AddFee(CalculateUncleReward(uncle)) processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) + //FIXME proc.UpdateAccount(uncle.Coinbase, uncleAddr) } return nil @@ -298,6 +305,7 @@ func (bm *BlockManager) ProcessContract(contract *Contract, tx *Transaction, blo */ vm := &Vm{} + //vm.Process(contract, bm.procState, RuntimeVars{ vm.Process(contract, block.state, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, diff --git a/ethchain/state.go b/ethchain/state.go index e6649cf22..be25fe7b4 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -111,3 +111,41 @@ func (s *State) UpdateAccount(addr []byte, account *Account) { func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } + +type ObjType byte + +const ( + NilTy ObjType = iota + AccountTy + ContractTy + + UnknownTy +) + +// Returns the object stored at key and the type stored at key +// Returns nil if nothing is stored +func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { + // Fetch data from the trie + data := s.trie.Get(string(key)) + // Returns the nil type, indicating nothing could be retrieved. + // Anything using this function should check for this ret val + if data == "" { + return nil, NilTy + } + + var typ ObjType + val := ethutil.NewValueFromBytes([]byte(data)) + // Check the length of the retrieved value. + // Len 2 = Account + // Len 3 = Contract + // Other = invalid for now. If other types emerge, add them here + if val.Len() == 2 { + typ = AccountTy + } else if val.Len() == 3 { + typ = ContractTy + } else { + typ = UnknownTy + } + + return val, typ +} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 763560570..2c9a26936 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -41,10 +41,6 @@ func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Tra return nil } -type PublicSpeaker interface { - Broadcast(msgType ethwire.MsgType, data []interface{}) -} - type TxProcessor interface { ProcessTransaction(tx *Transaction) } @@ -55,8 +51,7 @@ type TxProcessor interface { // 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 + Ethereum EthManager // The mutex for accessing the Tx pool. mutex sync.Mutex // Queueing channel for reading and writing incoming @@ -67,20 +62,19 @@ type TxPool struct { // The actual pool pool *list.List - BlockManager *BlockManager - SecondaryProcessor TxProcessor subscribers []chan TxMsg } -func NewTxPool() *TxPool { +func NewTxPool(ethereum EthManager) *TxPool { return &TxPool{ //server: s, mutex: sync.Mutex{}, pool: list.New(), queueChan: make(chan *Transaction, txPoolQueueSize), quit: make(chan bool), + Ethereum: ethereum, } } @@ -91,7 +85,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { pool.mutex.Unlock() // Broadcast the transaction to the rest of the peers - pool.Speaker.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) + pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) } // Process transaction validates the Tx and processes funds from the @@ -152,14 +146,14 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error 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 + block := pool.Ethereum.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 - accountState := pool.BlockManager.GetAddrState(tx.Sender()) + accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) sender := accountState.Account totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) -- cgit v1.2.3 From 6c6e8b0fd7415a43c67699f145e76daff959d745 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 5 Mar 2014 10:57:32 +0100 Subject: Renamed block manager to state manager --- ethchain/block_manager.go | 320 ---------------------------------------------- ethchain/state_manager.go | 320 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 320 insertions(+), 320 deletions(-) delete mode 100644 ethchain/block_manager.go create mode 100644 ethchain/state_manager.go (limited to 'ethchain') diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go deleted file mode 100644 index fa50304ea..000000000 --- a/ethchain/block_manager.go +++ /dev/null @@ -1,320 +0,0 @@ -package ethchain - -import ( - "bytes" - "fmt" - "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" - "math/big" - "sync" - "time" -) - -type BlockProcessor interface { - ProcessBlock(block *Block) -} - -type EthManager interface { - StateManager() *BlockManager - BlockChain() *BlockChain - TxPool() *TxPool - Broadcast(msgType ethwire.MsgType, data []interface{}) -} - -// 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 - - // Canonical 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 - mem map[string]*big.Int - - Pow PoW - - Ethereum EthManager - - SecondaryBlockProcessor BlockProcessor - - // The managed states - // Processor state. Anything processed will be applied to this - // state - procState *State - // Comparative state it used for comparing and validating end - // results - compState *State -} - -func NewBlockManager(ethereum EthManager) *BlockManager { - bm := &BlockManager{ - stack: NewStack(), - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Ethereum: ethereum, - addrStateStore: NewAddrStateStore(), - bc: ethereum.BlockChain(), - } - - return bm -} - -func (bm *BlockManager) ProcState() *State { - return bm.procState -} - -// Watches any given address and puts it in the address state store -func (bm *BlockManager) WatchAddr(addr []byte) *AccountState { - //FIXME account := bm.procState.GetAccount(addr) - account := bm.bc.CurrentBlock.state.GetAccount(addr) - - return bm.addrStateStore.Add(addr, account) -} - -func (bm *BlockManager) GetAddrState(addr []byte) *AccountState { - account := bm.addrStateStore.Get(addr) - if account == nil { - a := bm.bc.CurrentBlock.state.GetAccount(addr) - account = &AccountState{Nonce: a.Nonce, Account: a} - } - - return account -} - -func (bm *BlockManager) BlockChain() *BlockChain { - return bm.bc -} - -func (bm *BlockManager) MakeContract(tx *Transaction) { - contract := MakeContract(tx, bm.procState) - if contract != nil { - bm.procState.states[string(tx.Hash()[12:])] = contract.state - } -} - -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() { - //FIXME bm.MakeContract(tx) - block.MakeContract(tx) - } else { - //FIXME if contract := procState.GetContract(tx.Recipient); contract != nil { - if contract := block.state.GetContract(tx.Recipient); contract != nil { - bm.ProcessContract(contract, tx, block) - } else { - err := bm.Ethereum.TxPool().ProcessTransaction(tx, block) - if err != nil { - ethutil.Config.Log.Infoln("[BMGR]", err) - } - } - } - } -} - -// The prepare function, prepares the state manager for the next -// "ProcessBlock" action. -func (bm *BlockManager) Prepare(processer *State, comparative *State) { - bm.compState = comparative - bm.procState = processer -} - -// Default prepare function -func (bm *BlockManager) PrepareDefault(block *Block) { - bm.Prepare(bm.BlockChain().CurrentBlock.State(), block.State()) -} - -// 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() - // 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.Undo() - - hash := block.Hash() - - if bm.bc.HasBlock(hash) { - return nil - } - - // 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 !bm.compState.Cmp(bm.procState) - if !block.state.Cmp(bm.bc.CurrentBlock.state) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, bm.bc.CurrentBlock.State().trie.Root) - //FIXME return fmt.Errorf("Invalid merkle root. Expected %x, got %x", bm.compState.trie.Root, bm.procState.trie.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 and cancelling out the deferred Undo - bm.bc.CurrentBlock.Sync() - //FIXME bm.procState.Sync() - - // Broadcast the valid block back to the wire - //bm.Ethereum.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) - } - - ethutil.Config.Log.Infof("[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) - - 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 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.state.GetAccount(block.Coinbase) - //FIXME addr := proc.GetAccount(block.Coinbase) - // Reward amount of ether to the coinbase address - addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - - processor.state.UpdateAccount(block.Coinbase, addr) - //FIXME proc.UpdateAccount(block.Coinbase, addr) - - for _, uncle := range block.Uncles { - uncleAddr := processor.state.GetAccount(uncle.Coinbase) - uncleAddr.AddFee(CalculateUncleReward(uncle)) - - processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) - //FIXME proc.UpdateAccount(uncle.Coinbase, uncleAddr) - } - - return nil -} - -func (bm *BlockManager) Stop() { - bm.bc.Stop() -} - -func (bm *BlockManager) ProcessContract(contract *Contract, 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) - } - }() - */ - - vm := &Vm{} - //vm.Process(contract, bm.procState, RuntimeVars{ - vm.Process(contract, 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, - }) -} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go new file mode 100644 index 000000000..7085146df --- /dev/null +++ b/ethchain/state_manager.go @@ -0,0 +1,320 @@ +package ethchain + +import ( + "bytes" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" + "math/big" + "sync" + "time" +) + +type BlockProcessor interface { + ProcessBlock(block *Block) +} + +type EthManager interface { + StateManager() *StateManager + BlockChain() *BlockChain + TxPool() *TxPool + Broadcast(msgType ethwire.MsgType, data []interface{}) +} + +// TODO rename to state manager +type StateManager struct { + // Mutex for locking the block processor. Blocks can only be handled one at a time + mutex sync.Mutex + + // Canonical 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 + mem map[string]*big.Int + + Pow PoW + + Ethereum EthManager + + SecondaryBlockProcessor BlockProcessor + + // The managed states + // Processor state. Anything processed will be applied to this + // state + procState *State + // Comparative state it used for comparing and validating end + // results + compState *State +} + +func NewStateManager(ethereum EthManager) *StateManager { + sm := &StateManager{ + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Ethereum: ethereum, + addrStateStore: NewAddrStateStore(), + bc: ethereum.BlockChain(), + } + + return sm +} + +func (sm *StateManager) ProcState() *State { + return sm.procState +} + +// Watches any given address and puts it in the address state store +func (sm *StateManager) WatchAddr(addr []byte) *AccountState { + //FIXME account := sm.procState.GetAccount(addr) + account := sm.bc.CurrentBlock.state.GetAccount(addr) + + return sm.addrStateStore.Add(addr, account) +} + +func (sm *StateManager) GetAddrState(addr []byte) *AccountState { + account := sm.addrStateStore.Get(addr) + if account == nil { + a := sm.bc.CurrentBlock.state.GetAccount(addr) + account = &AccountState{Nonce: a.Nonce, Account: a} + } + + return account +} + +func (sm *StateManager) BlockChain() *BlockChain { + return sm.bc +} + +func (sm *StateManager) MakeContract(tx *Transaction) { + contract := MakeContract(tx, sm.procState) + if contract != nil { + sm.procState.states[string(tx.Hash()[12:])] = contract.state + } +} + +func (sm *StateManager) 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() { + //FIXME sm.MakeContract(tx) + block.MakeContract(tx) + } else { + //FIXME if contract := procState.GetContract(tx.Recipient); contract != nil { + if contract := block.state.GetContract(tx.Recipient); contract != nil { + sm.ProcessContract(contract, tx, block) + } else { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block) + if err != nil { + ethutil.Config.Log.Infoln("[smGR]", err) + } + } + } + } +} + +// The prepare function, prepares the state manager for the next +// "ProcessBlock" action. +func (sm *StateManager) Prepare(processer *State, comparative *State) { + sm.compState = comparative + sm.procState = processer +} + +// Default prepare function +func (sm *StateManager) PrepareDefault(block *Block) { + sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) +} + +// Block processing and validating with a given (temporarily) state +func (sm *StateManager) ProcessBlock(block *Block) error { + // Processing a blocks may never happen simultaneously + sm.mutex.Lock() + defer sm.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 sm.bc.CurrentBlock.Undo() + + hash := block.Hash() + + if sm.bc.HasBlock(hash) { + return nil + } + + // 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 !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { + return ParentError(block.PrevHash) + } + + // Process the transactions on to current block + sm.ApplyTransactions(sm.bc.CurrentBlock, block.Transactions()) + + // Block validation + if err := sm.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 := sm.AccumelateRewards(sm.bc.CurrentBlock, block); err != nil { + return err + } + + // if !sm.compState.Cmp(sm.procState) + if !block.state.Cmp(sm.bc.CurrentBlock.state) { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, sm.bc.CurrentBlock.State().trie.Root) + //FIXME return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) + } + + // Calculate the new total difficulty and sync back to the db + if sm.CalculateTD(block) { + // Sync the current block's state to the database and cancelling out the deferred Undo + sm.bc.CurrentBlock.Sync() + //FIXME sm.procState.Sync() + + // Broadcast the valid block back to the wire + //sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + + // Add the block to the chain + sm.bc.Add(block) + + // If there's a block processor present, pass in the block for further + // processing + if sm.SecondaryBlockProcessor != nil { + sm.SecondaryBlockProcessor.ProcessBlock(block) + } + + ethutil.Config.Log.Infof("[smGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + } else { + fmt.Println("total diff failed") + } + + return nil +} + +func (sm *StateManager) 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(sm.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(sm.bc.TD) > 0 { + // Set the new total difficulty back to the block chain + sm.bc.SetTotalDifficulty(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 (sm *StateManager) 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 := sm.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 - sm.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 !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { + return ValidationError("Block's nonce is invalid (= %v)", block.Nonce) + } + + 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 (sm *StateManager) AccumelateRewards(processor *Block, block *Block) error { + // Get the coinbase rlp data + addr := processor.state.GetAccount(block.Coinbase) + //FIXME addr := proc.GetAccount(block.Coinbase) + // Reward amount of ether to the coinbase address + addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) + + processor.state.UpdateAccount(block.Coinbase, addr) + //FIXME proc.UpdateAccount(block.Coinbase, addr) + + for _, uncle := range block.Uncles { + uncleAddr := processor.state.GetAccount(uncle.Coinbase) + uncleAddr.AddFee(CalculateUncleReward(uncle)) + + processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) + //FIXME proc.UpdateAccount(uncle.Coinbase, uncleAddr) + } + + return nil +} + +func (sm *StateManager) Stop() { + sm.bc.Stop() +} + +func (sm *StateManager) ProcessContract(contract *Contract, 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) + } + }() + */ + + vm := &Vm{} + //vm.Process(contract, sm.procState, RuntimeVars{ + vm.Process(contract, 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, + }) +} -- cgit v1.2.3 From be543a6d178063a60d404a373ced296ed6d4744c Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 6 Mar 2014 13:03:24 +0100 Subject: Removed comments --- ethchain/fees.go | 42 ------------------------------------------ 1 file changed, 42 deletions(-) (limited to 'ethchain') diff --git a/ethchain/fees.go b/ethchain/fees.go index 02f09fa04..c0a5d2d88 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -30,46 +30,4 @@ func InitFees() { ExtroFee.Mul(ExtroFee, TxFeeRat) CryptoFee.Mul(CryptoFee, TxFeeRat) ContractFee.Mul(ContractFee, TxFeeRat) - /* - // 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) - */ } -- cgit v1.2.3 From e7770b2332067ab0492fe46374713dbdf4ea1ac0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 6 Mar 2014 13:06:54 +0100 Subject: Added miner state --- ethchain/state_manager.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 7085146df..0923b017e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -21,7 +21,6 @@ type EthManager interface { Broadcast(msgType ethwire.MsgType, data []interface{}) } -// TODO rename to state manager type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex @@ -50,6 +49,8 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State + + miningState *State } func NewStateManager(ethereum EthManager) *StateManager { -- cgit v1.2.3 From 685ea3e9a944cc982bf5afc5b3e29c935a6e4c0b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 7 Mar 2014 11:26:35 +0100 Subject: Wip keychains --- ethchain/keypair.go | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 ethchain/keypair.go (limited to 'ethchain') diff --git a/ethchain/keypair.go b/ethchain/keypair.go new file mode 100644 index 000000000..9fdc95972 --- /dev/null +++ b/ethchain/keypair.go @@ -0,0 +1,74 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type KeyPair struct { + PrivateKey []byte + PublicKey []byte + + // The associated account + account *Account + state *State +} + +func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { + keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} + + return keyPair +} + +func (k *KeyPair) Address() []byte { + return ethutil.Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *KeyPair) Account() *Account { + if k.account == nil { + k.account = k.state.GetAccount(k.Address()) + } + + return k.account +} + +// Create transaction, creates a new and signed transaction, ready for processing +func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { + tx := NewTransaction(receiver, value, data) + tx.Nonce = k.account.Nonce + + // Sign the transaction with the private key in this key chain + tx.Sign(k.PrivateKey) + + return tx +} + +func (k *KeyPair) RlpEncode() []byte { + return ethutil.EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() +} + +type KeyRing struct { + keys []*KeyPair +} + +func (k *KeyRing) Add(pair *KeyPair) { + k.keys = append(k.keys, pair) +} + +// The public "singleton" keyring +var keyRing *KeyRing + +func GetKeyRing(state *State) *KeyRing { + if keyRing == nil { + keyRing = &KeyRing{} + + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + it := ethutil.NewValueFromBytes(data).NewIterator() + for it.Next() { + v := it.Value() + keyRing.Add(NewKeyPairFromValue(v)) + } + } + + return keyRing +} -- cgit v1.2.3 From d5efeab8f92509dec3cafcafb36e1856bb084f12 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 10 Mar 2014 11:53:02 +0100 Subject: Initial smart-miner stuff --- ethchain/block_chain.go | 1 + ethchain/dagger.go | 24 ++++++++++++++++-------- ethchain/state_manager.go | 15 +++++++++++++++ ethchain/transaction_pool.go | 8 +++++++- 4 files changed, 39 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2865e0a21..93970a2c5 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -136,6 +136,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 5b4f8b2cd..c33b3c14e 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -11,7 +11,7 @@ import ( ) type PoW interface { - Search(block *Block) []byte + Search(block *Block, breakChan chan bool) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -19,15 +19,23 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block) []byte { +func (pow *EasyPow) Search(block *Block, breakChan chan bool) []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 + select { + case shouldbreak := <-breakChan: + if shouldbreak { + log.Println("Got signal: Breaking out mining.") + return nil + } + default: + sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) + if pow.Verify(hash, diff, sha) { + return sha + } } } @@ -98,9 +106,9 @@ func (dag *Dagger) Search(hash, diff *big.Int) *big.Int { for k := 0; k < amountOfRoutines; k++ { go dag.Find(obj, resChan) - } - // Wait for each go routine to finish + // Wait for each go routine to finish + } for k := 0; k < amountOfRoutines; k++ { // Get the result from the channel. 0 = quit if r := <-resChan; r != 0 { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 7085146df..2652f3f29 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -19,6 +19,7 @@ type EthManager interface { BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) + Reactor() *ethutil.ReactorEngine } // TODO rename to state manager @@ -50,6 +51,9 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State + + // Mining state, solely used for mining + miningState *State } func NewStateManager(ethereum EthManager) *StateManager { @@ -69,6 +73,10 @@ func (sm *StateManager) ProcState() *State { return sm.procState } +func (sm *StateManager) MiningState() *State { + return sm.miningState +} + // Watches any given address and puts it in the address state store func (sm *StateManager) WatchAddr(addr []byte) *AccountState { //FIXME account := sm.procState.GetAccount(addr) @@ -97,6 +105,8 @@ func (sm *StateManager) MakeContract(tx *Transaction) { sm.procState.states[string(tx.Hash()[12:])] = contract.state } } +func (sm *StateManager) ApplyTransaction(block *Block, tx *Transaction) { +} func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract @@ -126,6 +136,10 @@ func (sm *StateManager) Prepare(processer *State, comparative *State) { sm.procState = processer } +func (sm *StateManager) PrepareMiningState() { + sm.miningState = sm.BlockChain().CurrentBlock.State() +} + // Default prepare function func (sm *StateManager) PrepareDefault(block *Block) { sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) @@ -193,6 +207,7 @@ func (sm *StateManager) ProcessBlock(block *Block) error { } ethutil.Config.Log.Infof("[smGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + sm.Ethereum.Reactor().Post("newBlock", block) } else { fmt.Println("total diff failed") } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 2c9a26936..345764d09 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,6 +91,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // 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.Println("Processing TX") defer func() { if r := recover(); r != nil { log.Println(r) @@ -137,7 +138,6 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) - // Notify the subscribers pool.notifySubscribers(TxPost, tx) return @@ -174,6 +174,7 @@ out: for { select { case tx := <-pool.queueChan: + log.Println("Received new Tx to queue") hash := tx.Hash() foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { return bytes.Compare(tx.Hash(), hash) == 0 @@ -190,9 +191,14 @@ out: log.Println("Validating Tx failed", err) } } else { + log.Println("Transaction ok, adding") // Call blocking version. At this point it // doesn't matter since this is a goroutine pool.addTransaction(tx) + log.Println("Added") + + // Notify the subscribers + pool.Ethereum.Reactor().Post("newTx", tx) // Notify the subscribers pool.notifySubscribers(TxPre, tx) -- cgit v1.2.3 From b15a4985e89b1fbf67731bde2e4cef45b3fdf347 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 10:33:03 +0100 Subject: Moved on to the state manager --- ethchain/state_manager.go | 49 ++++++++++++++++++++++---------------------- ethchain/transaction_pool.go | 4 ++-- 2 files changed, 27 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 0923b017e..c2a31ff6c 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -62,6 +62,7 @@ func NewStateManager(ethereum EthManager) *StateManager { addrStateStore: NewAddrStateStore(), bc: ethereum.BlockChain(), } + sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm } @@ -72,8 +73,8 @@ func (sm *StateManager) ProcState() *State { // Watches any given address and puts it in the address state store func (sm *StateManager) WatchAddr(addr []byte) *AccountState { - //FIXME account := sm.procState.GetAccount(addr) - account := sm.bc.CurrentBlock.state.GetAccount(addr) + //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) + account := sm.procState.GetAccount(addr) return sm.addrStateStore.Add(addr, account) } @@ -104,16 +105,16 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { for _, tx := range txs { // If there's no recipient, it's a contract if tx.IsContract() { - //FIXME sm.MakeContract(tx) - block.MakeContract(tx) + sm.MakeContract(tx) + //XXX block.MakeContract(tx) } else { - //FIXME if contract := procState.GetContract(tx.Recipient); contract != nil { - if contract := block.state.GetContract(tx.Recipient); contract != nil { + if contract := sm.procState.GetContract(tx.Recipient); contract != nil { + //XXX if contract := block.state.GetContract(tx.Recipient); contract != nil { sm.ProcessContract(contract, tx, block) } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block) if err != nil { - ethutil.Config.Log.Infoln("[smGR]", err) + ethutil.Config.Log.Infoln("[STATE]", err) } } } @@ -165,21 +166,21 @@ func (sm *StateManager) ProcessBlock(block *Block) error { // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err := sm.AccumelateRewards(sm.bc.CurrentBlock, block); err != nil { + if err := sm.AccumelateRewards(block); err != nil { return err } // if !sm.compState.Cmp(sm.procState) - if !block.state.Cmp(sm.bc.CurrentBlock.state) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, sm.bc.CurrentBlock.State().trie.Root) - //FIXME return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) + if !sm.compState.Cmp(sm.procState) { + //XXX return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, sm.bc.CurrentBlock.State().trie.Root) + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) } // Calculate the new total difficulty and sync back to the db if sm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - sm.bc.CurrentBlock.Sync() - //FIXME sm.procState.Sync() + //XXX sm.bc.CurrentBlock.Sync() + sm.procState.Sync() // Broadcast the valid block back to the wire //sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) @@ -193,7 +194,7 @@ func (sm *StateManager) ProcessBlock(block *Block) error { sm.SecondaryBlockProcessor.ProcessBlock(block) } - ethutil.Config.Log.Infof("[smGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) } else { fmt.Println("total diff failed") } @@ -270,22 +271,22 @@ func CalculateUncleReward(block *Block) *big.Int { return UncleReward } -func (sm *StateManager) AccumelateRewards(processor *Block, block *Block) error { +func (sm *StateManager) AccumelateRewards(block *Block) error { // Get the coinbase rlp data - addr := processor.state.GetAccount(block.Coinbase) - //FIXME addr := proc.GetAccount(block.Coinbase) + //XXX addr := processor.state.GetAccount(block.Coinbase) + addr := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - processor.state.UpdateAccount(block.Coinbase, addr) - //FIXME proc.UpdateAccount(block.Coinbase, addr) + //XXX processor.state.UpdateAccount(block.Coinbase, addr) + sm.procState.UpdateAccount(block.Coinbase, addr) for _, uncle := range block.Uncles { - uncleAddr := processor.state.GetAccount(uncle.Coinbase) + uncleAddr := sm.procState.GetAccount(uncle.Coinbase) uncleAddr.AddFee(CalculateUncleReward(uncle)) - processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) - //FIXME proc.UpdateAccount(uncle.Coinbase, uncleAddr) + //processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) + sm.procState.UpdateAccount(uncle.Coinbase, uncleAddr) } return nil @@ -306,8 +307,8 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo */ vm := &Vm{} - //vm.Process(contract, sm.procState, RuntimeVars{ - vm.Process(contract, block.state, RuntimeVars{ + //vm.Process(contract, block.state, RuntimeVars{ + vm.Process(contract, sm.procState, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, sender: tx.Sender(), diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 2c9a26936..fdc386303 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -233,11 +233,11 @@ func (pool *TxPool) Start() { } func (pool *TxPool) Stop() { - log.Println("[TXP] Stopping...") - close(pool.quit) pool.Flush() + + log.Println("[TXP] Stopped") } func (pool *TxPool) Subscribe(channel chan TxMsg) { -- cgit v1.2.3 From 3274e0a2496e622a847b213bb5ba0272650ef06c Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 17 Mar 2014 10:37:29 +0100 Subject: Removed extra invalid nonce return --- ethchain/transaction_pool.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 345764d09..b8366d274 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -109,11 +109,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } 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) - } + return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce) } // Get the receiver -- cgit v1.2.3 From 8ea7e21f64842380833cce7aafa52b909cb8426b Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 17 Mar 2014 10:37:37 +0100 Subject: Merge --- ethchain/dagger.go | 23 +++++++++++---- ethchain/keypair.go | 74 +++++++++++++++++++++++++++++++++++++++++++++++ ethchain/state_manager.go | 1 - 3 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 ethchain/keypair.go (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index c33b3c14e..4d2034e20 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -11,7 +11,7 @@ import ( ) type PoW interface { - Search(block *Block, breakChan chan bool) []byte + Search(block *Block, minerChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -19,19 +19,32 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, breakChan chan bool) []byte { +func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty + i := int64(0) + start := time.Now().UnixNano() for { select { - case shouldbreak := <-breakChan: - if shouldbreak { - log.Println("Got signal: Breaking out mining.") + case chanMessage := <-minerChan: + if _, ok := chanMessage.Resource.(*Block); ok { + log.Println("BREAKING OUT: BLOCK") + return nil + } + if _, ok := chanMessage.Resource.(*Transaction); ok { + log.Println("BREAKING OUT: TX") return nil } default: + i++ + if i%1234567 == 0 { + elapsed := time.Now().UnixNano() - start + hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 + log.Println("Hashing @", int64(hashes), "khash") + } + sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) if pow.Verify(hash, diff, sha) { return sha diff --git a/ethchain/keypair.go b/ethchain/keypair.go new file mode 100644 index 000000000..9fdc95972 --- /dev/null +++ b/ethchain/keypair.go @@ -0,0 +1,74 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type KeyPair struct { + PrivateKey []byte + PublicKey []byte + + // The associated account + account *Account + state *State +} + +func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { + keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} + + return keyPair +} + +func (k *KeyPair) Address() []byte { + return ethutil.Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *KeyPair) Account() *Account { + if k.account == nil { + k.account = k.state.GetAccount(k.Address()) + } + + return k.account +} + +// Create transaction, creates a new and signed transaction, ready for processing +func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { + tx := NewTransaction(receiver, value, data) + tx.Nonce = k.account.Nonce + + // Sign the transaction with the private key in this key chain + tx.Sign(k.PrivateKey) + + return tx +} + +func (k *KeyPair) RlpEncode() []byte { + return ethutil.EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() +} + +type KeyRing struct { + keys []*KeyPair +} + +func (k *KeyRing) Add(pair *KeyPair) { + k.keys = append(k.keys, pair) +} + +// The public "singleton" keyring +var keyRing *KeyRing + +func GetKeyRing(state *State) *KeyRing { + if keyRing == nil { + keyRing = &KeyRing{} + + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + it := ethutil.NewValueFromBytes(data).NewIterator() + for it.Next() { + v := it.Value() + keyRing.Add(NewKeyPairFromValue(v)) + } + } + + return keyRing +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 2652f3f29..39dece40e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -22,7 +22,6 @@ type EthManager interface { Reactor() *ethutil.ReactorEngine } -// TODO rename to state manager type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex -- cgit v1.2.3 From 07578fe25f475bb81ad308f592de2d89016d8431 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 11:13:35 +0100 Subject: Pretty print nonce --- ethchain/state_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c2a31ff6c..e67f0f680 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -253,7 +253,7 @@ func (sm *StateManager) ValidateBlock(block *Block) error { // Verify the nonce of the block. Return an error if it's not valid if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { - return ValidationError("Block's nonce is invalid (= %v)", block.Nonce) + return ValidationError("Block's nonce is invalid (= %v)", ethutil.Hex(block.Nonce)) } return nil -- cgit v1.2.3 From 826c827e6b1922604601f15361c962aef6f7f1a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 11:15:09 +0100 Subject: Added a copy method to state --- ethchain/state.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index be25fe7b4..b9c2c576d 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -112,6 +112,10 @@ func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } +func (s *State) Copy() *State { + return NewState(s.trie.Copy()) +} + type ObjType byte const ( -- cgit v1.2.3 From ae837c4719855384921fcaadb1a575942dc9833d Mon Sep 17 00:00:00 2001 From: Maran Date: Thu, 20 Mar 2014 11:20:29 +0100 Subject: More mining rework --- ethchain/block.go | 3 +++ ethchain/block_chain.go | 3 +-- ethchain/dagger.go | 16 +++++----------- ethchain/state_manager.go | 28 ++++++++-------------------- ethchain/transaction_pool.go | 9 ++++----- 5 files changed, 21 insertions(+), 38 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 20af73ba2..d42aa7d83 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -304,6 +304,9 @@ 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\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) } +func (block *Block) GetRoot() interface{} { + return block.state.trie.Root +} //////////// UNEXPORTED ///////////////// func (block *Block) header() []interface{} { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 93970a2c5..90ad4516a 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -44,7 +44,6 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { hash = bc.LastBlockHash lastBlockTime = bc.CurrentBlock.Time } - block := CreateBlock( root, hash, @@ -181,8 +180,8 @@ func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { // 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() diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 4d2034e20..a80a9d421 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -11,7 +11,7 @@ import ( ) type PoW interface { - Search(block *Block, minerChan chan ethutil.React) []byte + Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -19,7 +19,7 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte { +func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty @@ -28,15 +28,9 @@ func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte { for { select { - case chanMessage := <-minerChan: - if _, ok := chanMessage.Resource.(*Block); ok { - log.Println("BREAKING OUT: BLOCK") - return nil - } - if _, ok := chanMessage.Resource.(*Transaction); ok { - log.Println("BREAKING OUT: TX") - return nil - } + case <-reactChan: + log.Println("[pow] Received reactor event; breaking out.") + return nil default: i++ if i%1234567 == 0 { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3be940745..46d8228d9 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -50,9 +50,6 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State - - // Mining state, solely used for mining - miningState *State } func NewStateManager(ethereum EthManager) *StateManager { @@ -65,7 +62,6 @@ func NewStateManager(ethereum EthManager) *StateManager { bc: ethereum.BlockChain(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() - return sm } @@ -73,10 +69,6 @@ func (sm *StateManager) ProcState() *State { return sm.procState } -func (sm *StateManager) MiningState() *State { - return sm.miningState -} - // Watches any given address and puts it in the address state store func (sm *StateManager) WatchAddr(addr []byte) *AccountState { //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) @@ -105,8 +97,6 @@ func (sm *StateManager) MakeContract(tx *Transaction) { sm.procState.states[string(tx.Hash()[12:])] = contract.state } } -func (sm *StateManager) ApplyTransaction(block *Block, tx *Transaction) { -} func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract @@ -136,17 +126,13 @@ func (sm *StateManager) Prepare(processer *State, comparative *State) { sm.procState = processer } -func (sm *StateManager) PrepareMiningState() { - sm.miningState = sm.BlockChain().CurrentBlock.State() -} - // Default prepare function func (sm *StateManager) PrepareDefault(block *Block) { sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) } // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(block *Block) error { +func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -155,7 +141,6 @@ func (sm *StateManager) ProcessBlock(block *Block) error { // nodes this won't happen because Commit would have been called // before that. defer sm.bc.CurrentBlock.Undo() - hash := block.Hash() if sm.bc.HasBlock(hash) { @@ -207,7 +192,9 @@ func (sm *StateManager) ProcessBlock(block *Block) error { } ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) - sm.Ethereum.Reactor().Post("newBlock", block) + if dontReact == false { + sm.Ethereum.Reactor().Post("newBlock", block) + } } else { fmt.Println("total diff failed") } @@ -285,15 +272,16 @@ func CalculateUncleReward(block *Block) *big.Int { } func (sm *StateManager) AccumelateRewards(block *Block) error { + // Get the coinbase rlp data //XXX addr := processor.state.GetAccount(block.Coinbase) addr := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - //XXX processor.state.UpdateAccount(block.Coinbase, addr) - sm.procState.UpdateAccount(block.Coinbase, addr) - + var acc []byte + copy(acc, block.Coinbase) + sm.procState.UpdateAccount(acc, addr) for _, uncle := range block.Uncles { uncleAddr := sm.procState.GetAccount(uncle.Coinbase) uncleAddr.AddFee(CalculateUncleReward(uncle)) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index b0df1b6c0..26827c289 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,7 +91,6 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // 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.Println("Processing TX") defer func() { if r := recover(); r != nil { log.Println(r) @@ -105,11 +104,11 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error // 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") + return errors.New("[TXPL] Insufficient amount in sender's account") } if sender.Nonce != tx.Nonce { - return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce) + return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transactoin nonce is %d instead", sender.Nonce, tx.Nonce) } // Get the receiver @@ -145,7 +144,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { block := pool.Ethereum.BlockChain().CurrentBlock // Something has gone horribly wrong if this happens if block == nil { - return errors.New("No last block on the block chain") + return errors.New("[TXPL] No last block on the block chain") } // Get the sender @@ -156,7 +155,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // 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()) + return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } // Increment the nonce making each tx valid only once to prevent replay -- cgit v1.2.3 From bdc0d1b7ad4e2a4ff78f287f088c13a5d6ab2148 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:24:02 +0100 Subject: Added AddFunds method --- ethchain/address.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/address.go b/ethchain/address.go index aa1709f2c..f1f27a1a5 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -22,7 +22,11 @@ func NewAccountFromData(data []byte) *Account { } func (a *Account) AddFee(fee *big.Int) { - a.Amount.Add(a.Amount, fee) + a.AddFunds(fee) +} + +func (a *Account) AddFunds(funds *big.Int) { + a.Amount.Add(a.Amount, funds) } func (a *Account) RlpEncode() []byte { -- cgit v1.2.3 From c135b389fe358006bd3586097e1b17232b0c86e6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:24:53 +0100 Subject: Commented out code due to rewrite vm --- ethchain/block_manager_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index ec4fbe8c5..3a1e5f510 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -1,5 +1,6 @@ package ethchain +/* import ( _ "fmt" "github.com/ethereum/eth-go/ethdb" @@ -14,9 +15,10 @@ func TestVm(t *testing.T) { db, _ := ethdb.NewMemDatabase() ethutil.Config.Db = db - bm := NewBlockManager(nil) + bm := NewStateManager(nil) block := bm.bc.genesisBlock + bm.Prepare(block.State(), block.State()) script := Compile([]string{ "PUSH", "1", @@ -31,3 +33,4 @@ func TestVm(t *testing.T) { tx2.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) bm.ApplyTransactions(block, []*Transaction{tx2}) } +*/ -- cgit v1.2.3 From 82d0f65dab253e215349ea685382bca9672378d8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:25:11 +0100 Subject: Comply to Callee structure --- ethchain/contract.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/contract.go b/ethchain/contract.go index 21ac828fe..10c5e2df6 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -43,12 +43,17 @@ func (c *Contract) State() *State { return c.state } -func (c *Contract) GetMem(num int) *ethutil.Value { - nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256) +func (c *Contract) GetMem(num int64) *ethutil.Value { + nb := ethutil.BigToBytes(big.NewInt(num), 256) return c.Addr(nb) } +// Return the gas back to the origin. Used by the Virtual machine or Closures +func (c *Contract) ReturnGas(val *big.Int, state *State) { + c.Amount.Add(c.Amount, val) +} + func MakeContract(tx *Transaction, state *State) *Contract { // Create contract if there's no recipient if tx.IsContract() { -- cgit v1.2.3 From 38ea6a6d5dffb7573b29541c2a6687145bdcc495 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:26:07 +0100 Subject: Closures and vm based on closures Status: Work in progress --- ethchain/closure.go | 68 +++++++++++++++++++++++++++++++++++++ ethchain/vm.go | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++--- ethchain/vm_test.go | 56 ++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 ethchain/closure.go (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go new file mode 100644 index 000000000..4ef43a2da --- /dev/null +++ b/ethchain/closure.go @@ -0,0 +1,68 @@ +package ethchain + +// TODO Re write VM to use values instead of big integers? + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type Callee interface { + ReturnGas(*big.Int, *State) +} + +type ClosureBody interface { + Callee + ethutil.RlpEncodable + GetMem(int64) *ethutil.Value +} + +// Basic inline closure object which implement the 'closure' interface +type Closure struct { + callee Callee + object ClosureBody + state *State + + gas *big.Int + val *big.Int +} + +// Create a new closure for the given data items +func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure { + return &Closure{callee, object, state, gas, val} +} + +// Retuns the x element in data slice +func (c *Closure) GetMem(x int64) *ethutil.Value { + m := c.object.GetMem(x) + if m == nil { + return ethutil.EmptyValue() + } + + return m +} + +func (c *Closure) Return(ret []byte) []byte { + // Return the remaining gas to the callee + // If no callee is present return it to + // the origin (i.e. contract or tx) + if c.callee != nil { + c.callee.ReturnGas(c.gas, c.state) + } else { + c.object.ReturnGas(c.gas, c.state) + // TODO incase it's a POST contract we gotta serialise the contract again. + // But it's not yet defined + } + + return ret +} + +// Implement the Callee interface +func (c *Closure) ReturnGas(gas *big.Int, state *State) { + // Return the gas to the closure + c.gas.Add(c.gas, gas) +} + +func (c *Closure) GetGas() *big.Int { + return c.gas +} diff --git a/ethchain/vm.go b/ethchain/vm.go index 7e119ac99..861b041d8 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -32,13 +32,101 @@ type RuntimeVars struct { txData []string } +func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byte { + // If the amount of gas supplied is less equal to 0 + if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { + // TODO Do something + } + + // Memory for the current closure + var mem []byte + // New stack (should this be shared?) + stack := NewStack() + // Instruction pointer + pc := int64(0) + // Current address + //addr := vars.address + step := 0 + + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("# op\n") + } + + for { + step++ + // Get the memory location of pc + val := closure.GetMem(pc) + // Get the opcode (it must be an opcode!) + op := OpCode(val.Uint()) + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } + + // TODO Get each instruction cost properly + fee := new(big.Int) + fee.Add(fee, big.NewInt(1000)) + + if closure.GetGas().Cmp(fee) < 0 { + return closure.Return(nil) + } + + switch op { + case oSTOP: + return closure.Return(nil) + case oPUSH: + pc++ + val := closure.GetMem(pc).BigInt() + stack.Push(val) + case oMSTORE: + // Pop value of the stack + val := stack.Pop() + // Set the bytes to the memory field + mem = append(mem, ethutil.BigToBytes(val, 256)...) + case oCALL: + // Pop return size and offset + retSize, retOffset := stack.Popn() + // Pop input size and offset + inSize, inOffset := stack.Popn() + // TODO remove me. + fmt.Sprintln(inSize, inOffset) + // Pop gas and value of the stack. + gas, value := stack.Popn() + // Closure addr + addr := stack.Pop() + + contract := state.GetContract(addr.Bytes()) + closure := NewClosure(closure, contract, state, gas, value) + ret := vm.RunClosure(closure, state, vars) + + // Ensure that memory is large enough to hold the returned data + totSize := new(big.Int).Add(retOffset, retSize) + lenSize := big.NewInt(int64(len(mem))) + // Resize the current memory slice so that the return value may fit + if totSize.Cmp(lenSize) > 0 { + diff := new(big.Int).Sub(totSize, lenSize) + newSlice := make([]byte, diff.Int64()+1) + mem = append(mem, newSlice...) + } + copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret) + case oRETURN: + size, offset := stack.Popn() + ret := mem[offset.Int64() : offset.Int64()+size.Int64()+1] + + return closure.Return(ret) + } + + pc++ + } +} + +// Old VM code 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 + pc := int64(0) if contract == nil { fmt.Println("Contract not found") @@ -344,7 +432,7 @@ out: contract.SetAddr(addr, y) //contract.State().Update(string(idx), string(y)) case oJMP: - x := int(vm.stack.Pop().Uint64()) + x := vm.stack.Pop().Int64() // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) pc = x pc-- @@ -352,7 +440,7 @@ out: x := vm.stack.Pop() // Set pc to x if it's non zero if x.Cmp(ethutil.BigFalse) != 0 { - pc = int(x.Uint64()) + pc = x.Int64() pc-- } case oIND: @@ -400,9 +488,9 @@ out: func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) - j := 0 + j := int64(0) dataItems := make([]string, int(length.Uint64())) - for i := from.Uint64(); i < length.Uint64(); i++ { + for i := from.Int64(); i < length.Int64(); i++ { dataItems[j] = contract.GetMem(j).Str() j++ } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 6ceb0ff15..4e72c9249 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -8,6 +8,8 @@ import ( "testing" ) +/* + func TestRun(t *testing.T) { InitFees() @@ -104,3 +106,57 @@ func TestRun2(t *testing.T) { txData: tx.Data, }) } +*/ + +// XXX Full stack test +func TestRun3(t *testing.T) { + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + script := Compile([]string{ + "PUSH", "300", + "MSTORE", + "PUSH", "300", + "MSTORE", + "PUSH", "62", + "PUSH", "0", + "RETURN", + }) + tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) + addr := tx.Hash()[12:] + fmt.Printf("addr contract %x\n", addr) + contract := MakeContract(tx, state) + state.UpdateContract(addr, contract) + + callerScript := Compile([]string{ + "PUSH", "62", // REND + "PUSH", "0", // RSTART + "PUSH", "22", // MEND + "PUSH", "15", // MSTART + "PUSH", "1000", /// Gas + "PUSH", "0", /// value + "PUSH", string(addr), // Sender + "CALL", + }) + callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) + callerAddr := callerTx.Hash()[12:] + executer := NewTransaction(ContractAddr, ethutil.Big("10000"), nil) + + executer.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) + callerClosure := NewClosure(executer, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) + + vm := &Vm{} + vm.RunClosure(callerClosure, state, RuntimeVars{ + address: callerAddr, + blockNumber: 1, + sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + txValue: big.NewInt(10000), + txData: nil, + }) +} -- cgit v1.2.3 From 59d8dc39505981d1ae07b05a71d3f4cf1f33319a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:26:30 +0100 Subject: Fixed issue with stack where it sliced of the wrong values --- ethchain/stack.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index 13b0f247b..349e7817a 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -2,6 +2,7 @@ package ethchain import ( "fmt" + "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -60,6 +61,10 @@ const ( oBALANCE = 0x3c oMKTX = 0x3d oSUICIDE = 0x3f + + // TODO FIX OPCODES + oCALL = 0x40 + oRETURN = 0x41 ) // Since the opcodes aren't all in order we can't use a regular slice @@ -114,6 +119,9 @@ var opCodeToString = map[OpCode]string{ oBALANCE: "BALANCE", oMKTX: "MKTX", oSUICIDE: "SUICIDE", + + oCALL: "CALL", + oRETURN: "RETURN", } func (o OpCode) String() string { @@ -141,6 +149,56 @@ func NewStack() *Stack { } func (st *Stack) Pop() *big.Int { + str := st.data[0] + st.data = st.data[1:] + + return str +} + +func (st *Stack) Popn() (*big.Int, *big.Int) { + ints := st.data[:2] + st.data = st.data[2:] + + return ints[0], ints[1] +} + +func (st *Stack) Peek() *big.Int { + str := st.data[0] + + return str +} + +func (st *Stack) Peekn() (*big.Int, *big.Int) { + ints := st.data[: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("### STACK ###") + if len(st.data) > 0 { + for i, val := range st.data { + fmt.Printf("%-3d %v\n", i, val) + } + } else { + fmt.Println("-- empty --") + } + fmt.Println("#############") +} + +////////////// TODO this will eventually become the main stack once the big ints are removed from the VM +type ValueStack struct { + data []*ethutil.Value +} + +func NewValueStack() *ValueStack { + return &ValueStack{} +} + +func (st *ValueStack) Pop() *ethutil.Value { s := len(st.data) str := st.data[s-1] @@ -149,7 +207,7 @@ func (st *Stack) Pop() *big.Int { return str } -func (st *Stack) Popn() (*big.Int, *big.Int) { +func (st *ValueStack) Popn() (*ethutil.Value, *ethutil.Value) { s := len(st.data) ints := st.data[s-2:] @@ -158,7 +216,7 @@ func (st *Stack) Popn() (*big.Int, *big.Int) { return ints[0], ints[1] } -func (st *Stack) Peek() *big.Int { +func (st *ValueStack) Peek() *ethutil.Value { s := len(st.data) str := st.data[s-1] @@ -166,7 +224,7 @@ func (st *Stack) Peek() *big.Int { return str } -func (st *Stack) Peekn() (*big.Int, *big.Int) { +func (st *ValueStack) Peekn() (*ethutil.Value, *ethutil.Value) { s := len(st.data) ints := st.data[s-2:] @@ -174,10 +232,10 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) { return ints[0], ints[1] } -func (st *Stack) Push(d *big.Int) { +func (st *ValueStack) Push(d *ethutil.Value) { st.data = append(st.data, d) } -func (st *Stack) Print() { +func (st *ValueStack) Print() { fmt.Println("### STACK ###") if len(st.data) > 0 { for i, val := range st.data { -- cgit v1.2.3 From c17381b853e2d762787ca30c5ce45aeece99dfd1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:26:51 +0100 Subject: Moved code around --- ethchain/state.go | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index b9c2c576d..b84d60c6c 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -79,20 +79,10 @@ func (s *State) GetContract(addr []byte) *Contract { } func (s *State) UpdateContract(addr []byte, contract *Contract) { + s.states[string(addr)] = contract.state 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 *Account) { data := s.trie.Get(string(addr)) if data == "" { @@ -153,3 +143,31 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { return val, typ } + +func (s *State) Put(key, object []byte) { + s.trie.Update(string(key), string(object)) +} + +// Script compilation functions +// Compiles strings to machine code +func Compile(code []string) (script []string) { + script = make([]string, len(code)) + for i, val := range code { + instr, _ := ethutil.CompileInstr(val) + + script[i] = string(instr) + } + + return +} + +func CompileToValues(code []string) (script []*ethutil.Value) { + script = make([]*ethutil.Value, len(code)) + for i, val := range code { + instr, _ := ethutil.CompileInstr(val) + + script[i] = ethutil.NewValue(instr) + } + + return +} -- cgit v1.2.3 From 3520771d68df1e9becfb29cc2f85d7042f3fb9d1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:27:09 +0100 Subject: Comply to Callee interface --- ethchain/transaction.go | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 57df9cdc4..07e7ea970 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -29,6 +29,15 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { return &tx } +// Implements Callee +func (tx *Transaction) ReturnGas(value *big.Int, state *State) { + // Return the value back to the sender + sender := tx.Sender() + account := state.GetAccount(sender) + account.AddFunds(value) + state.UpdateAccount(sender, account) +} + // XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { return NewTransactionFromBytes(data) -- cgit v1.2.3 From c68ff9886bdd59294bc2bf0a6b8bf9b83645cc9a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 19:50:53 +0100 Subject: Fixed MSTORE and added some more commets --- ethchain/closure.go | 16 ++++++++++++---- ethchain/stack.go | 1 + ethchain/vm.go | 46 ++++++++++++++++++++++++++++++++++------------ ethchain/vm_test.go | 6 ++++-- 4 files changed, 51 insertions(+), 18 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 4ef43a2da..204fbce06 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -21,15 +21,17 @@ type ClosureBody interface { type Closure struct { callee Callee object ClosureBody - state *State + State *State gas *big.Int val *big.Int + + args []byte } // Create a new closure for the given data items func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure { - return &Closure{callee, object, state, gas, val} + return &Closure{callee, object, state, gas, val, nil} } // Retuns the x element in data slice @@ -42,14 +44,20 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { return m } +func (c *Closure) Call(vm *Vm, args []byte) []byte { + c.args = args + + return vm.RunClosure(c) +} + func (c *Closure) Return(ret []byte) []byte { // Return the remaining gas to the callee // If no callee is present return it to // the origin (i.e. contract or tx) if c.callee != nil { - c.callee.ReturnGas(c.gas, c.state) + c.callee.ReturnGas(c.gas, c.State) } else { - c.object.ReturnGas(c.gas, c.state) + c.object.ReturnGas(c.gas, c.State) // TODO incase it's a POST contract we gotta serialise the contract again. // But it's not yet defined } diff --git a/ethchain/stack.go b/ethchain/stack.go index 349e7817a..bfb19614e 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -235,6 +235,7 @@ func (st *ValueStack) Peekn() (*ethutil.Value, *ethutil.Value) { func (st *ValueStack) Push(d *ethutil.Value) { st.data = append(st.data, d) } + func (st *ValueStack) Print() { fmt.Println("### STACK ###") if len(st.data) > 0 { diff --git a/ethchain/vm.go b/ethchain/vm.go index 861b041d8..2fa78a748 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -18,6 +18,8 @@ type Vm struct { mem map[string]*big.Int vars RuntimeVars + + state *State } type RuntimeVars struct { @@ -32,7 +34,11 @@ type RuntimeVars struct { txData []string } -func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byte { +func NewVm(state *State, vars RuntimeVars) *Vm { + return &Vm{vars: vars, state: state} +} + +func (vm *Vm) RunClosure(closure *Closure) []byte { // If the amount of gas supplied is less equal to 0 if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { // TODO Do something @@ -71,17 +77,28 @@ func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byt } switch op { - case oSTOP: + case oSTOP: // Stop the closure return closure.Return(nil) - case oPUSH: + case oPUSH: // Push PC+1 on to the stack pc++ val := closure.GetMem(pc).BigInt() stack.Push(val) - case oMSTORE: + case oMSTORE: // Store the value at stack top-1 in to memory at location stack top // Pop value of the stack - val := stack.Pop() - // Set the bytes to the memory field - mem = append(mem, ethutil.BigToBytes(val, 256)...) + val, mStart := stack.Popn() + // Ensure that memory is large enough to hold the data + // If it isn't resize the memory slice so that it may hold the value + bytesLen := big.NewInt(32) + totSize := new(big.Int).Add(mStart, bytesLen) + lenSize := big.NewInt(int64(len(mem))) + if totSize.Cmp(lenSize) > 0 { + // Calculate the diff between the sizes + diff := new(big.Int).Sub(totSize, lenSize) + // Create a new empty slice and append it + newSlice := make([]byte, diff.Int64()+1) + mem = append(mem, newSlice...) + } + copy(mem[mStart.Int64():mStart.Int64()+bytesLen.Int64()+1], ethutil.BigToBytes(val, 256)) case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() @@ -93,20 +110,25 @@ func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byt gas, value := stack.Popn() // Closure addr addr := stack.Pop() - - contract := state.GetContract(addr.Bytes()) - closure := NewClosure(closure, contract, state, gas, value) - ret := vm.RunClosure(closure, state, vars) + // Fetch the contract which will serve as the closure body + contract := vm.state.GetContract(addr.Bytes()) + // Create a new callable closure + closure := NewClosure(closure, contract, vm.state, gas, value) + // Executer the closure and get the return value (if any) + ret := closure.Call(vm, nil) // Ensure that memory is large enough to hold the returned data + // If it isn't resize the memory slice so that it may hold the value totSize := new(big.Int).Add(retOffset, retSize) lenSize := big.NewInt(int64(len(mem))) - // Resize the current memory slice so that the return value may fit if totSize.Cmp(lenSize) > 0 { + // Calculate the diff between the sizes diff := new(big.Int).Sub(totSize, lenSize) + // Create a new empty slice and append it newSlice := make([]byte, diff.Int64()+1) mem = append(mem, newSlice...) } + // Copy over the returned values to the memory given the offset and size copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret) case oRETURN: size, offset := stack.Popn() diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 4e72c9249..654ddb566 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -117,8 +117,10 @@ func TestRun3(t *testing.T) { script := Compile([]string{ "PUSH", "300", + "PUSH", "0", "MSTORE", "PUSH", "300", + "PUSH", "31", "MSTORE", "PUSH", "62", "PUSH", "0", @@ -147,8 +149,7 @@ func TestRun3(t *testing.T) { executer.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) callerClosure := NewClosure(executer, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) - vm := &Vm{} - vm.RunClosure(callerClosure, state, RuntimeVars{ + vm := NewVm(state, RuntimeVars{ address: callerAddr, blockNumber: 1, sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), @@ -159,4 +160,5 @@ func TestRun3(t *testing.T) { txValue: big.NewInt(10000), txData: nil, }) + callerClosure.Call(vm, nil) } -- cgit v1.2.3 From f3d27bf5d878120346f8cdd0744e7f1f8e1ee631 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 22:51:20 +0100 Subject: Rewrote opcodes again --- ethchain/stack.go | 303 ++++++++++++++++++++++------------------------ ethchain/state_manager.go | 3 +- ethchain/vm.go | 41 ++----- 3 files changed, 155 insertions(+), 192 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index bfb19614e..429c31d08 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -2,7 +2,7 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethutil" + _ "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -10,116 +10,136 @@ type OpCode int // Op codes const ( - 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 - - // TODO FIX OPCODES - oCALL = 0x40 - oRETURN = 0x41 + // 0x0 range - arithmetic ops + oSTOP = 0x00 + oADD = 0x01 + oMUL = 0x02 + oSUB = 0x03 + oDIV = 0x04 + oSDIV = 0x05 + oMOD = 0x06 + oSMOD = 0x07 + oEXP = 0x08 + oNEG = 0x09 + oLT = 0x0a + oGT = 0x0b + oEQ = 0x0c + oNOT = 0x0d + + // 0x10 range - bit ops + oAND = 0x10 + oOR = 0x11 + oXOR = 0x12 + oBYTE = 0x13 + + // 0x20 range - crypto + oSHA3 = 0x20 + + // 0x30 range - closure state + oADDRESS = 0x30 + oBALANCE = 0x31 + oORIGIN = 0x32 + oCALLER = 0x33 + oCALLVALUE = 0x34 + oCALLDATA = 0x35 + oCALLDATASIZE = 0x36 + oRETURNDATASIZE = 0x37 + oTXGASPRICE = 0x38 + + // 0x40 range - block operations + oPREVHASH = 0x40 + oPREVNONCE = 0x41 + oCOINBASE = 0x42 + oTIMESTAMP = 0x43 + oNUMBER = 0x44 + oDIFFICULTY = 0x45 + oGASLIMIT = 0x46 + + // 0x50 range - 'storage' and execution + oPUSH = 0x50 + oPOP = 0x51 + oDUP = 0x52 + oSWAP = 0x53 + oMLOAD = 0x54 + oMSTORE = 0x55 + oMSTORE8 = 0x56 + oSLOAD = 0x57 + oSSTORE = 0x58 + oJUMP = 0x59 + oJUMPI = 0x5a + oPC = 0x5b + oMEMSIZE = 0x5c + + // 0x60 range - closures + oCREATE = 0x60 + oCALL = 0x61 + oRETURN = 0x62 ) // 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", - 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", + // 0x0 range - arithmetic ops + oSTOP: "STOP", + oADD: "ADD", + oMUL: "MUL", + oSUB: "SUB", + oDIV: "DIV", + oSDIV: "SDIV", + oMOD: "MOD", + oSMOD: "SMOD", + oEXP: "EXP", + oNEG: "NEG", + oLT: "LT", + oGT: "GT", + oEQ: "EQ", + oNOT: "NOT", + + // 0x10 range - bit ops + oAND: "AND", + oOR: "OR", + oXOR: "XOR", + oBYTE: "BYTE", + + // 0x20 range - crypto + oSHA3: "SHA3", + + // 0x30 range - closure state + oADDRESS: "ADDRESS", oBALANCE: "BALANCE", - oMKTX: "MKTX", - oSUICIDE: "SUICIDE", - + oORIGIN: "ORIGIN", + oCALLER: "CALLER", + oCALLVALUE: "CALLVALUE", + oCALLDATA: "CALLDATA", + oCALLDATASIZE: "CALLDATASIZE", + oRETURNDATASIZE: "RETURNDATASIZE", + oTXGASPRICE: "TXGASPRICE", + + // 0x40 range - block operations + oPREVHASH: "PREVHASH", + oPREVNONCE: "PREVNONCE", + oCOINBASE: "COINBASE", + oTIMESTAMP: "TIMESTAMP", + oNUMBER: "NUMBER", + oDIFFICULTY: "DIFFICULTY", + oGASLIMIT: "GASLIMIT", + + // 0x50 range - 'storage' and execution + oPUSH: "PUSH", + oPOP: "POP", + oDUP: "DUP", + oSWAP: "SWAP", + oMLOAD: "MLOAD", + oMSTORE: "MSTORE", + oMSTORE8: "MSTORE8", + oSLOAD: "SLOAD", + oSSTORE: "SSTORE", + oJUMP: "JUMP", + oJUMPI: "JUMPI", + oPC: "PC", + oMEMSIZE: "MEMSIZE", + + // 0x60 range - closures + oCREATE: "CREATE", oCALL: "CALL", oRETURN: "RETURN", } @@ -189,61 +209,26 @@ func (st *Stack) Print() { fmt.Println("#############") } -////////////// TODO this will eventually become the main stack once the big ints are removed from the VM -type ValueStack struct { - data []*ethutil.Value -} - -func NewValueStack() *ValueStack { - return &ValueStack{} -} - -func (st *ValueStack) Pop() *ethutil.Value { - s := len(st.data) - - str := st.data[s-1] - st.data = st.data[:s-1] - - return str -} - -func (st *ValueStack) Popn() (*ethutil.Value, *ethutil.Value) { - s := len(st.data) - - ints := st.data[s-2:] - st.data = st.data[:s-2] - - return ints[0], ints[1] -} - -func (st *ValueStack) Peek() *ethutil.Value { - s := len(st.data) - - str := st.data[s-1] - - return str +type Memory struct { + store []byte } -func (st *ValueStack) Peekn() (*ethutil.Value, *ethutil.Value) { - s := len(st.data) - - ints := st.data[s-2:] - - return ints[0], ints[1] -} - -func (st *ValueStack) Push(d *ethutil.Value) { - st.data = append(st.data, d) -} - -func (st *ValueStack) Print() { - fmt.Println("### STACK ###") - if len(st.data) > 0 { - for i, val := range st.data { - fmt.Printf("%-3d %v\n", i, val) +func (m *Memory) Set(offset, size int64, value []byte) { + totSize := offset + size + lenSize := int64(len(m.store)) + if totSize > lenSize { + // Calculate the diff between the sizes + diff := totSize - lenSize + if diff > 0 { + // Create a new empty slice and append it + newSlice := make([]byte, diff+1) + // Resize slice + m.store = append(m.store, newSlice...) } - } else { - fmt.Println("-- empty --") } - fmt.Println("#############") + copy(m.store[offset:offset+size+1], value) +} + +func (m *Memory) Get(offset, size int64) []byte { + return m.store[offset : offset+size] } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index e67f0f680..14686b217 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -306,8 +306,8 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo }() */ + /*TODO to be fixed and replaced by the new vm vm := &Vm{} - //vm.Process(contract, block.state, RuntimeVars{ vm.Process(contract, sm.procState, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, @@ -319,4 +319,5 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo txValue: tx.Value, txData: tx.Data, }) + */ } diff --git a/ethchain/vm.go b/ethchain/vm.go index 2fa78a748..6479409f8 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -1,12 +1,12 @@ package ethchain import ( - "bytes" + _ "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" - "github.com/obscuren/secp256k1-go" + _ "github.com/obscuren/secp256k1-go" "log" - "math" + _ "math" "math/big" ) @@ -45,7 +45,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } // Memory for the current closure - var mem []byte + mem := &Memory{} // New stack (should this be shared?) stack := NewStack() // Instruction pointer @@ -86,19 +86,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { case oMSTORE: // Store the value at stack top-1 in to memory at location stack top // Pop value of the stack val, mStart := stack.Popn() - // Ensure that memory is large enough to hold the data - // If it isn't resize the memory slice so that it may hold the value - bytesLen := big.NewInt(32) - totSize := new(big.Int).Add(mStart, bytesLen) - lenSize := big.NewInt(int64(len(mem))) - if totSize.Cmp(lenSize) > 0 { - // Calculate the diff between the sizes - diff := new(big.Int).Sub(totSize, lenSize) - // Create a new empty slice and append it - newSlice := make([]byte, diff.Int64()+1) - mem = append(mem, newSlice...) - } - copy(mem[mStart.Int64():mStart.Int64()+bytesLen.Int64()+1], ethutil.BigToBytes(val, 256)) + mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() @@ -116,23 +104,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { closure := NewClosure(closure, contract, vm.state, gas, value) // Executer the closure and get the return value (if any) ret := closure.Call(vm, nil) - - // Ensure that memory is large enough to hold the returned data - // If it isn't resize the memory slice so that it may hold the value - totSize := new(big.Int).Add(retOffset, retSize) - lenSize := big.NewInt(int64(len(mem))) - if totSize.Cmp(lenSize) > 0 { - // Calculate the diff between the sizes - diff := new(big.Int).Sub(totSize, lenSize) - // Create a new empty slice and append it - newSlice := make([]byte, diff.Int64()+1) - mem = append(mem, newSlice...) - } - // Copy over the returned values to the memory given the offset and size - copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: size, offset := stack.Popn() - ret := mem[offset.Int64() : offset.Int64()+size.Int64()+1] + ret := mem.Get(offset.Int64(), size.Int64()) return closure.Return(ret) } @@ -141,6 +116,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } } +/* // Old VM code func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { vm.mem = make(map[string]*big.Int) @@ -507,6 +483,7 @@ out: state.UpdateContract(addr, contract) } +*/ func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) -- cgit v1.2.3 From 7705b23f248156878d00c301fbbadafedaf7e3d2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 23:17:53 +0100 Subject: Removed caller from tx and added "callership" to account. Transactions can no longer serve as callers. Accounts are now the initial callee of closures. Transactions now serve as transport to call closures. --- ethchain/address.go | 24 ++++++++++++++++-------- ethchain/block.go | 2 +- ethchain/closure.go | 4 ++-- ethchain/state.go | 4 ++-- ethchain/transaction.go | 9 --------- ethchain/vm.go | 4 ++++ ethchain/vm_test.go | 13 ++++++------- 7 files changed, 31 insertions(+), 29 deletions(-) (limited to 'ethchain') diff --git a/ethchain/address.go b/ethchain/address.go index f1f27a1a5..9c6acbe08 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -6,19 +6,20 @@ import ( ) type Account struct { - Amount *big.Int - Nonce uint64 + Address []byte + Amount *big.Int + Nonce uint64 } -func NewAccount(amount *big.Int) *Account { - return &Account{Amount: amount, Nonce: 0} +func NewAccount(address []byte, amount *big.Int) *Account { + return &Account{address, amount, 0} } -func NewAccountFromData(data []byte) *Account { - address := &Account{} - address.RlpDecode(data) +func NewAccountFromData(address, data []byte) *Account { + account := &Account{Address: address} + account.RlpDecode(data) - return address + return account } func (a *Account) AddFee(fee *big.Int) { @@ -29,6 +30,13 @@ func (a *Account) AddFunds(funds *big.Int) { a.Amount.Add(a.Amount, funds) } +// Implements Callee +func (a *Account) ReturnGas(value *big.Int, state *State) { + // Return the value back to the sender + a.AddFunds(value) + state.UpdateAccount(a.Address, a) +} + func (a *Account) RlpEncode() []byte { return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) } diff --git a/ethchain/block.go b/ethchain/block.go index 20af73ba2..1f63c2c9e 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -142,7 +142,7 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { data := block.state.trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) - ether := NewAccountFromData([]byte(data)) + ether := NewAccountFromData(block.Coinbase, []byte(data)) base = new(big.Int) ether.Amount = base.Add(ether.Amount, fee) diff --git a/ethchain/closure.go b/ethchain/closure.go index 204fbce06..9453ce22c 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -26,7 +26,7 @@ type Closure struct { gas *big.Int val *big.Int - args []byte + Args []byte } // Create a new closure for the given data items @@ -45,7 +45,7 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { } func (c *Closure) Call(vm *Vm, args []byte) []byte { - c.args = args + c.Args = args return vm.RunClosure(c) } diff --git a/ethchain/state.go b/ethchain/state.go index b84d60c6c..b6750d62d 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -86,9 +86,9 @@ func (s *State) UpdateContract(addr []byte, contract *Contract) { func (s *State) GetAccount(addr []byte) (account *Account) { data := s.trie.Get(string(addr)) if data == "" { - account = NewAccount(big.NewInt(0)) + account = NewAccount(addr, big.NewInt(0)) } else { - account = NewAccountFromData([]byte(data)) + account = NewAccountFromData(addr, []byte(data)) } return diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 07e7ea970..57df9cdc4 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -29,15 +29,6 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { return &tx } -// Implements Callee -func (tx *Transaction) ReturnGas(value *big.Int, state *State) { - // Return the value back to the sender - sender := tx.Sender() - account := state.GetAccount(sender) - account.AddFunds(value) - state.UpdateAccount(sender, account) -} - // XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { return NewTransactionFromBytes(data) diff --git a/ethchain/vm.go b/ethchain/vm.go index 6479409f8..3d85e2c09 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -87,6 +87,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + + case oCALLDATA: + offset := stack.Pop() + mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 654ddb566..30c8a110e 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -133,10 +133,10 @@ func TestRun3(t *testing.T) { state.UpdateContract(addr, contract) callerScript := Compile([]string{ - "PUSH", "62", // REND - "PUSH", "0", // RSTART - "PUSH", "22", // MEND - "PUSH", "15", // MSTART + "PUSH", "62", // ret size + "PUSH", "0", // ret offset + "PUSH", "32", // arg size + "PUSH", "63", // arg offset "PUSH", "1000", /// Gas "PUSH", "0", /// value "PUSH", string(addr), // Sender @@ -144,10 +144,9 @@ func TestRun3(t *testing.T) { }) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) callerAddr := callerTx.Hash()[12:] - executer := NewTransaction(ContractAddr, ethutil.Big("10000"), nil) - executer.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) - callerClosure := NewClosure(executer, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) + account := NewAccount(ContractAddr, big.NewInt(10000000)) + callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ address: callerAddr, -- cgit v1.2.3 From f567f89b994bf28f908410223084a6702d05d156 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 23:38:16 +0100 Subject: Added address to account and contract Contract and account now both have an address field or method for the sake of simplicity. --- ethchain/closure.go | 1 + ethchain/contract.go | 38 +++++++++++++++++++++++++------------- ethchain/state.go | 7 ++++--- ethchain/vm.go | 7 +++---- ethchain/vm_test.go | 11 +++++------ 5 files changed, 38 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 9453ce22c..0eef866d0 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -15,6 +15,7 @@ type ClosureBody interface { Callee ethutil.RlpEncodable GetMem(int64) *ethutil.Value + Address() []byte } // Basic inline closure object which implement the 'closure' interface diff --git a/ethchain/contract.go b/ethchain/contract.go index 10c5e2df6..93d2b68ba 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -9,26 +9,22 @@ type Contract struct { Amount *big.Int Nonce uint64 //state *ethutil.Trie - state *State + state *State + address []byte } -func NewContract(Amount *big.Int, root []byte) *Contract { - contract := &Contract{Amount: Amount, Nonce: 0} +func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { + contract := &Contract{address: address, Amount: Amount, Nonce: 0} contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) return contract } -func (c *Contract) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) -} - -func (c *Contract) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) +func NewContractFromBytes(address, data []byte) *Contract { + contract := &Contract{address: address} + contract.RlpDecode(data) - c.Amount = decoder.Get(0).BigInt() - c.Nonce = decoder.Get(1).Uint() - c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + return contract } func (c *Contract) Addr(addr []byte) *ethutil.Value { @@ -54,13 +50,29 @@ func (c *Contract) ReturnGas(val *big.Int, state *State) { c.Amount.Add(c.Amount, val) } +func (c *Contract) Address() []byte { + return c.address +} + +func (c *Contract) RlpEncode() []byte { + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) +} + +func (c *Contract) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + c.Amount = decoder.Get(0).BigInt() + c.Nonce = decoder.Get(1).Uint() + c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) +} + func MakeContract(tx *Transaction, state *State) *Contract { // Create contract if there's no recipient if tx.IsContract() { addr := tx.Hash()[12:] value := tx.Value - contract := NewContract(value, []byte("")) + contract := NewContract(addr, value, []byte("")) state.trie.Update(string(addr), string(contract.RlpEncode())) for i, val := range tx.Data { if len(val) > 0 { diff --git a/ethchain/state.go b/ethchain/state.go index b6750d62d..c9b35da21 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -63,8 +63,7 @@ func (s *State) GetContract(addr []byte) *Contract { } // build contract - contract := &Contract{} - contract.RlpDecode([]byte(data)) + contract := NewContractFromBytes(addr, []byte(data)) // Check if there's a cached state for this contract cachedState := s.states[string(addr)] @@ -78,7 +77,9 @@ func (s *State) GetContract(addr []byte) *Contract { return contract } -func (s *State) UpdateContract(addr []byte, contract *Contract) { +func (s *State) UpdateContract(contract *Contract) { + addr := contract.Address() + s.states[string(addr)] = contract.state s.trie.Update(string(addr), string(contract.RlpEncode())) } diff --git a/ethchain/vm.go b/ethchain/vm.go index 3d85e2c09..ba19231cc 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -23,14 +23,12 @@ type Vm struct { } type RuntimeVars struct { - address []byte + origin []byte blockNumber uint64 - sender []byte prevHash []byte coinbase []byte time int64 diff *big.Int - txValue *big.Int txData []string } @@ -108,6 +106,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { closure := NewClosure(closure, contract, vm.state, gas, value) // Executer the closure and get the return value (if any) ret := closure.Call(vm, nil) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: size, offset := stack.Popn() @@ -501,7 +500,7 @@ func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, tx := NewTransaction(addr, value, dataItems) if tx.IsContract() { contract := MakeContract(tx, state) - state.UpdateContract(tx.Hash()[12:], contract) + state.UpdateContract(contract) } else { account := state.GetAccount(tx.Recipient) account.Amount.Add(account.Amount, tx.Value) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 30c8a110e..1dca5cfb7 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -130,7 +130,7 @@ func TestRun3(t *testing.T) { addr := tx.Hash()[12:] fmt.Printf("addr contract %x\n", addr) contract := MakeContract(tx, state) - state.UpdateContract(addr, contract) + state.UpdateContract(contract) callerScript := Compile([]string{ "PUSH", "62", // ret size @@ -143,21 +143,20 @@ func TestRun3(t *testing.T) { "CALL", }) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) - callerAddr := callerTx.Hash()[12:] + // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ - address: callerAddr, + origin: account.Address, blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), time: 1, diff: big.NewInt(256), - txValue: big.NewInt(10000), - txData: nil, + // XXX Tx data? Could be just an argument to the closure instead + txData: nil, }) callerClosure.Call(vm, nil) } -- cgit v1.2.3 From 9cf8ce9ef82bfb37fea92bbea6a8d326af00adc8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 00:04:31 +0100 Subject: New tx methods and added new vm to state manager --- ethchain/state_manager.go | 16 +++++++--------- ethchain/transaction.go | 21 +++++++++++++++------ 2 files changed, 22 insertions(+), 15 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 14686b217..50c777349 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -305,19 +305,17 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo } }() */ - - /*TODO to be fixed and replaced by the new vm - vm := &Vm{} - vm.Process(contract, sm.procState, RuntimeVars{ - address: tx.Hash()[12:], + caller := sm.procState.GetAccount(tx.Sender()) + closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) + vm := NewVm(sm.procState, RuntimeVars{ + origin: caller.Address, 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, + // XXX Tx data? Could be just an argument to the closure instead + txData: nil, }) - */ + closure.Call(vm, nil) } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 57df9cdc4..3b07c81d4 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -13,22 +13,31 @@ type Transaction struct { Nonce uint64 Recipient []byte Value *big.Int + Gas *big.Int + Gasprice *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 = data + tx := Transaction{Recipient: to, Value: value, Nonce: 0, Data: data} return &tx } +func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { + return &Transaction{Value: value, Gasprice: gasprice, Data: data} +} + +func NewContractMessageTx(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { + return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} +} + +func NewTx(to []byte, value *big.Int, data []string) *Transaction { + return &Transaction{Recipient: to, Value: value, Gasprice: big.NewInt(0), Gas: big.NewInt(0), Nonce: 0, Data: data} +} + // XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { return NewTransactionFromBytes(data) -- cgit v1.2.3 From fa1db8d2dcbc12fd9b343e6572c541d92fe7cb55 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 11:54:36 +0100 Subject: Implemented closure arguments --- ethchain/stack.go | 28 ++++++-- ethchain/vm.go | 184 +++++++++++++++++++++++++++++++++++++++++++++++++--- ethchain/vm_test.go | 29 +++++++-- 3 files changed, 220 insertions(+), 21 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index 429c31d08..c75d02dda 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -68,12 +68,16 @@ const ( oJUMP = 0x59 oJUMPI = 0x5a oPC = 0x5b - oMEMSIZE = 0x5c + oMSIZE = 0x5c // 0x60 range - closures oCREATE = 0x60 oCALL = 0x61 oRETURN = 0x62 + + // 0x70 range - other + oLOG = 0x70 // XXX Unofficial + oSUICIDE = 0x7f ) // Since the opcodes aren't all in order we can't use a regular slice @@ -136,12 +140,16 @@ var opCodeToString = map[OpCode]string{ oJUMP: "JUMP", oJUMPI: "JUMPI", oPC: "PC", - oMEMSIZE: "MEMSIZE", + oMSIZE: "MSIZE", // 0x60 range - closures oCREATE: "CREATE", oCALL: "CALL", oRETURN: "RETURN", + + // 0x70 range - other + oLOG: "LOG", + oSUICIDE: "SUICIDE", } func (o OpCode) String() string { @@ -215,20 +223,30 @@ type Memory struct { func (m *Memory) Set(offset, size int64, value []byte) { totSize := offset + size - lenSize := int64(len(m.store)) + lenSize := int64(len(m.store) - 1) if totSize > lenSize { // Calculate the diff between the sizes diff := totSize - lenSize if diff > 0 { // Create a new empty slice and append it - newSlice := make([]byte, diff+1) + newSlice := make([]byte, diff-1) // Resize slice m.store = append(m.store, newSlice...) } } - copy(m.store[offset:offset+size+1], value) + copy(m.store[offset:offset+size], value) } func (m *Memory) Get(offset, size int64) []byte { return m.store[offset : offset+size] } + +func (m *Memory) Print() { + fmt.Println("### MEM ###") + if len(m.store) > 0 { + fmt.Println(m.store) + } else { + fmt.Println("-- empty --") + } + fmt.Println("###########") +} diff --git a/ethchain/vm.go b/ethchain/vm.go index ba19231cc..3d2ee4c86 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,7 +2,7 @@ package ethchain import ( _ "bytes" - "fmt" + _ "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" "log" @@ -36,6 +36,8 @@ func NewVm(state *State, vars RuntimeVars) *Vm { return &Vm{vars: vars, state: state} } +var Pow256 = ethutil.BigPow(2, 256) + func (vm *Vm) RunClosure(closure *Closure) []byte { // If the amount of gas supplied is less equal to 0 if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { @@ -48,9 +50,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { stack := NewStack() // Instruction pointer pc := int64(0) - // Current address - //addr := vars.address + // Current step count step := 0 + // The base for all big integer arithmetic + base := new(big.Int) if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") @@ -75,27 +78,171 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } switch op { + case oLOG: + stack.Print() + mem.Print() case oSTOP: // Stop the closure return closure.Return(nil) + + // 0x20 range + case oADD: + x, y := stack.Popn() + // (x + y) % 2 ** 256 + base.Add(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + stack.Push(base) + case oSUB: + x, y := stack.Popn() + // (x - y) % 2 ** 256 + base.Sub(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + stack.Push(base) + case oMUL: + x, y := stack.Popn() + // (x * y) % 2 ** 256 + base.Mul(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + stack.Push(base) + case oDIV: + x, y := stack.Popn() + // floor(x / y) + base.Div(x, y) + // Pop result back on the stack + stack.Push(base) + case oSDIV: + x, y := 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 + stack.Push(z) + case oMOD: + x, y := stack.Popn() + base.Mod(x, y) + stack.Push(base) + case oSMOD: + x, y := 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 + stack.Push(z) + case oEXP: + x, y := stack.Popn() + base.Exp(x, y, Pow256) + + stack.Push(base) + case oNEG: + base.Sub(Pow256, stack.Pop()) + stack.Push(base) + case oLT: + x, y := stack.Popn() + // x < y + if x.Cmp(y) < 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case oGT: + x, y := stack.Popn() + // x > y + if x.Cmp(y) > 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case oNOT: + x, y := stack.Popn() + // x != y + if x.Cmp(y) != 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + + // 0x10 range + case oAND: + case oOR: + case oXOR: + case oBYTE: + + // 0x20 range + case oSHA3: + + // 0x30 range + case oADDRESS: + case oBALANCE: + case oORIGIN: + case oCALLER: + case oCALLVALUE: + case oCALLDATA: + offset := stack.Pop() + mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) + case oCALLDATASIZE: + case oRETURNDATASIZE: + case oTXGASPRICE: + + // 0x40 range + case oPREVHASH: + case oPREVNONCE: + case oCOINBASE: + case oTIMESTAMP: + case oNUMBER: + case oDIFFICULTY: + case oGASLIMIT: + + // 0x50 range case oPUSH: // Push PC+1 on to the stack pc++ val := closure.GetMem(pc).BigInt() stack.Push(val) + case oPOP: + case oDUP: + case oSWAP: + case oMLOAD: + offset := stack.Pop() + stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) case oMSTORE: // Store the value at stack top-1 in to memory at location stack top // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + case oMSTORE8: + case oSLOAD: + case oSSTORE: + case oJUMP: + case oJUMPI: + case oPC: + case oMSIZE: - case oCALLDATA: - offset := stack.Pop() - mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) + // 0x60 range case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() // Pop input size and offset inSize, inOffset := stack.Popn() - // TODO remove me. - fmt.Sprintln(inSize, inOffset) + // Get the arguments from the memory + args := mem.Get(inOffset.Int64(), inSize.Int64()) // Pop gas and value of the stack. gas, value := stack.Popn() // Closure addr @@ -105,7 +252,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // Create a new callable closure closure := NewClosure(closure, contract, vm.state, gas, value) // Executer the closure and get the return value (if any) - ret := closure.Call(vm, nil) + ret := closure.Call(vm, args) mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: @@ -113,6 +260,25 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { ret := mem.Get(offset.Int64(), size.Int64()) return closure.Return(ret) + case oSUICIDE: + /* + recAddr := stack.Pop().Bytes() + // Purge all memory + deletedMemory := contract.state.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), "") + + ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) + break out + */ + default: + ethutil.Config.Log.Debugln("Invalid opcode", op) } pc++ diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 1dca5cfb7..ce8c7a4de 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,6 +1,7 @@ package ethchain import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" @@ -119,11 +120,13 @@ func TestRun3(t *testing.T) { "PUSH", "300", "PUSH", "0", "MSTORE", - "PUSH", "300", - "PUSH", "31", - "MSTORE", - "PUSH", "62", + + "PUSH", "32", + "CALLDATA", + + "PUSH", "64", "PUSH", "0", + "LOG", "RETURN", }) tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) @@ -133,14 +136,21 @@ func TestRun3(t *testing.T) { state.UpdateContract(contract) callerScript := Compile([]string{ - "PUSH", "62", // ret size + "PUSH", "1337", // Argument + "PUSH", "65", // argument mem offset + "MSTORE", + "PUSH", "64", // ret size "PUSH", "0", // ret offset + "PUSH", "32", // arg size - "PUSH", "63", // arg offset + "PUSH", "65", // arg offset "PUSH", "1000", /// Gas "PUSH", "0", /// value "PUSH", string(addr), // Sender "CALL", + "PUSH", "64", + "PUSH", "0", + "RETURN", }) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) @@ -158,5 +168,10 @@ func TestRun3(t *testing.T) { // XXX Tx data? Could be just an argument to the closure instead txData: nil, }) - callerClosure.Call(vm, nil) + ret := callerClosure.Call(vm, nil) + + exp := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 57} + if bytes.Compare(ret, exp) != 0 { + t.Errorf("expected return value to be %v, got %v", exp, ret) + } } -- cgit v1.2.3 From 2ea4c632d1673b762c1af11582364d9faa08c413 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 14:47:55 +0100 Subject: Closure return, arguments fixed. Added proper tests --- ethchain/address.go | 10 ++++++--- ethchain/closure.go | 24 ++++++++++++++-------- ethchain/stack.go | 52 +++++++++++++++++++++++------------------------ ethchain/state_manager.go | 2 +- ethchain/vm.go | 33 +++++++++++++++++++++++++----- ethchain/vm_test.go | 3 +-- 6 files changed, 79 insertions(+), 45 deletions(-) (limited to 'ethchain') diff --git a/ethchain/address.go b/ethchain/address.go index 9c6acbe08..0b3ef7c05 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -6,7 +6,7 @@ import ( ) type Account struct { - Address []byte + address []byte Amount *big.Int Nonce uint64 } @@ -16,7 +16,7 @@ func NewAccount(address []byte, amount *big.Int) *Account { } func NewAccountFromData(address, data []byte) *Account { - account := &Account{Address: address} + account := &Account{address: address} account.RlpDecode(data) return account @@ -30,11 +30,15 @@ func (a *Account) AddFunds(funds *big.Int) { a.Amount.Add(a.Amount, funds) } +func (a *Account) Address() []byte { + return a.address +} + // Implements Callee func (a *Account) ReturnGas(value *big.Int, state *State) { // Return the value back to the sender a.AddFunds(value) - state.UpdateAccount(a.Address, a) + state.UpdateAccount(a.address, a) } func (a *Account) RlpEncode() []byte { diff --git a/ethchain/closure.go b/ethchain/closure.go index 0eef866d0..f8e692f61 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -9,13 +9,13 @@ import ( type Callee interface { ReturnGas(*big.Int, *State) + Address() []byte } type ClosureBody interface { Callee ethutil.RlpEncodable GetMem(int64) *ethutil.Value - Address() []byte } // Basic inline closure object which implement the 'closure' interface @@ -24,8 +24,8 @@ type Closure struct { object ClosureBody State *State - gas *big.Int - val *big.Int + Gas *big.Int + Value *big.Int Args []byte } @@ -45,6 +45,10 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { return m } +func (c *Closure) Address() []byte { + return c.object.Address() +} + func (c *Closure) Call(vm *Vm, args []byte) []byte { c.Args = args @@ -56,9 +60,9 @@ func (c *Closure) Return(ret []byte) []byte { // If no callee is present return it to // the origin (i.e. contract or tx) if c.callee != nil { - c.callee.ReturnGas(c.gas, c.State) + c.callee.ReturnGas(c.Gas, c.State) } else { - c.object.ReturnGas(c.gas, c.State) + c.object.ReturnGas(c.Gas, c.State) // TODO incase it's a POST contract we gotta serialise the contract again. // But it's not yet defined } @@ -69,9 +73,13 @@ func (c *Closure) Return(ret []byte) []byte { // Implement the Callee interface func (c *Closure) ReturnGas(gas *big.Int, state *State) { // Return the gas to the closure - c.gas.Add(c.gas, gas) + c.Gas.Add(c.Gas, gas) +} + +func (c *Closure) Object() ClosureBody { + return c.object } -func (c *Closure) GetGas() *big.Int { - return c.gas +func (c *Closure) Callee() Callee { + return c.callee } diff --git a/ethchain/stack.go b/ethchain/stack.go index c75d02dda..b64b759fd 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -36,24 +36,22 @@ const ( oSHA3 = 0x20 // 0x30 range - closure state - oADDRESS = 0x30 - oBALANCE = 0x31 - oORIGIN = 0x32 - oCALLER = 0x33 - oCALLVALUE = 0x34 - oCALLDATA = 0x35 - oCALLDATASIZE = 0x36 - oRETURNDATASIZE = 0x37 - oTXGASPRICE = 0x38 + oADDRESS = 0x30 + oBALANCE = 0x31 + oORIGIN = 0x32 + oCALLER = 0x33 + oCALLVALUE = 0x34 + oCALLDATA = 0x35 + oCALLDATASIZE = 0x36 + oGASPRICE = 0x37 // 0x40 range - block operations oPREVHASH = 0x40 - oPREVNONCE = 0x41 - oCOINBASE = 0x42 - oTIMESTAMP = 0x43 - oNUMBER = 0x44 - oDIFFICULTY = 0x45 - oGASLIMIT = 0x46 + oCOINBASE = 0x41 + oTIMESTAMP = 0x42 + oNUMBER = 0x43 + oDIFFICULTY = 0x44 + oGASLIMIT = 0x45 // 0x50 range - 'storage' and execution oPUSH = 0x50 @@ -108,19 +106,17 @@ var opCodeToString = map[OpCode]string{ oSHA3: "SHA3", // 0x30 range - closure state - oADDRESS: "ADDRESS", - oBALANCE: "BALANCE", - oORIGIN: "ORIGIN", - oCALLER: "CALLER", - oCALLVALUE: "CALLVALUE", - oCALLDATA: "CALLDATA", - oCALLDATASIZE: "CALLDATASIZE", - oRETURNDATASIZE: "RETURNDATASIZE", - oTXGASPRICE: "TXGASPRICE", + oADDRESS: "ADDRESS", + oBALANCE: "BALANCE", + oORIGIN: "ORIGIN", + oCALLER: "CALLER", + oCALLVALUE: "CALLVALUE", + oCALLDATA: "CALLDATA", + oCALLDATASIZE: "CALLDATASIZE", + oGASPRICE: "TXGASPRICE", // 0x40 range - block operations oPREVHASH: "PREVHASH", - oPREVNONCE: "PREVNONCE", oCOINBASE: "COINBASE", oTIMESTAMP: "TIMESTAMP", oNUMBER: "NUMBER", @@ -244,7 +240,11 @@ func (m *Memory) Get(offset, size int64) []byte { func (m *Memory) Print() { fmt.Println("### MEM ###") if len(m.store) > 0 { - fmt.Println(m.store) + addr := 0 + for i := 0; i+32 < len(m.store); i += 32 { + fmt.Printf("%03d %v\n", addr, m.store[i:i+32]) + addr++ + } } else { fmt.Println("-- empty --") } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 50c777349..3b5507740 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -308,7 +308,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ - origin: caller.Address, + origin: caller.Address(), blockNumber: block.BlockInfo().Number, prevHash: block.PrevHash, coinbase: block.Coinbase, diff --git a/ethchain/vm.go b/ethchain/vm.go index 3d2ee4c86..8b5bb93c0 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -40,7 +40,7 @@ var Pow256 = ethutil.BigPow(2, 256) func (vm *Vm) RunClosure(closure *Closure) []byte { // If the amount of gas supplied is less equal to 0 - if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { + if closure.Gas.Cmp(big.NewInt(0)) <= 0 { // TODO Do something } @@ -73,7 +73,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { fee := new(big.Int) fee.Add(fee, big.NewInt(1000)) - if closure.GetGas().Cmp(fee) < 0 { + if closure.Gas.Cmp(fee) < 0 { return closure.Return(nil) } @@ -192,25 +192,37 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x30 range case oADDRESS: + stack.Push(ethutil.BigD(closure.Object().Address())) case oBALANCE: + stack.Push(closure.Value) case oORIGIN: + stack.Push(ethutil.BigD(vm.vars.origin)) case oCALLER: + stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: + // FIXME: Original value of the call, not the current value + stack.Push(closure.Value) case oCALLDATA: offset := stack.Pop() mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) case oCALLDATASIZE: - case oRETURNDATASIZE: - case oTXGASPRICE: + stack.Push(big.NewInt(int64(len(closure.Args)))) + case oGASPRICE: + // TODO // 0x40 range case oPREVHASH: - case oPREVNONCE: + stack.Push(ethutil.BigD(vm.vars.prevHash)) case oCOINBASE: + stack.Push(ethutil.BigD(vm.vars.coinbase)) case oTIMESTAMP: + stack.Push(big.NewInt(vm.vars.time)) case oNUMBER: + stack.Push(big.NewInt(int64(vm.vars.blockNumber))) case oDIFFICULTY: + stack.Push(vm.vars.diff) case oGASLIMIT: + // TODO // 0x50 range case oPUSH: // Push PC+1 on to the stack @@ -218,8 +230,13 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { val := closure.GetMem(pc).BigInt() stack.Push(val) case oPOP: + stack.Pop() case oDUP: + stack.Push(stack.Peek()) case oSWAP: + x, y := stack.Popn() + stack.Push(y) + stack.Push(x) case oMLOAD: offset := stack.Pop() stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) @@ -228,7 +245,13 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oMSTORE8: + val, mStart := stack.Popn() + base.And(val, new(big.Int).SetInt64(0xff)) + mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) case oSLOAD: + loc := stack.Pop() + val := closure.GetMem(loc.Int64()) + stack.Push(val.BigInt()) case oSSTORE: case oJUMP: case oJUMPI: diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index ce8c7a4de..16cbf51b7 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -126,7 +126,6 @@ func TestRun3(t *testing.T) { "PUSH", "64", "PUSH", "0", - "LOG", "RETURN", }) tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) @@ -159,7 +158,7 @@ func TestRun3(t *testing.T) { callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ - origin: account.Address, + origin: account.Address(), blockNumber: 1, prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), -- cgit v1.2.3 From b52b1fca89fd56549ecc0f086d96a39d6009e568 Mon Sep 17 00:00:00 2001 From: Maran Date: Fri, 21 Mar 2014 15:06:23 +0100 Subject: Initial block reorganisation code --- ethchain/block_chain.go | 97 +++++++++++++++++++++++++++++++++++++++++++++++ ethchain/state_manager.go | 4 +- 2 files changed, 100 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 90ad4516a..6eea14652 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" "log" "math" "math/big" @@ -24,6 +25,7 @@ type BlockChain struct { func NewBlockChain(ethereum EthManager) *BlockChain { bc := &BlockChain{} bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) + bc.Ethereum = ethereum bc.setLastBlock() @@ -77,6 +79,101 @@ func (bc *BlockChain) HasBlock(hash []byte) bool { return len(data) != 0 } +// TODO: At one point we might want to save a block by prevHash in the db to optimise this... +func (bc *BlockChain) HasBlockWithPrevHash(hash []byte) bool { + block := bc.CurrentBlock + + for ; block != nil; block = bc.GetBlock(block.PrevHash) { + if bytes.Compare(hash, block.PrevHash) == 0 { + return true + } + } + return false +} + +func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { + blockDiff := new(big.Int) + + for _, uncle := range block.Uncles { + blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty) + } + blockDiff = blockDiff.Add(blockDiff, block.Difficulty) + + return blockDiff +} + +// Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one +func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) { + // 1. Calculate TD of the current chain + // 2. Calculate TD of the new chain + // Reset state to the correct one + + chainDifficulty := new(big.Int) + + // Calculate the entire chain until the block we both have + // Start with the newest block we got, all the way back to the common block we both know + for i := 0; i < (msg.Data.Len() - 1); i++ { + block := NewBlockFromRlpValue(msg.Data.Get(i)) + if bytes.Compare(block.Hash(), commonBlockHash) == 0 { + log.Println("[BCHAIN] We have found the common parent block, breaking") + break + } + chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) + } + + log.Println("[BCHAIN] Incoming chain difficulty:", chainDifficulty) + + curChainDifficulty := new(big.Int) + block := bc.CurrentBlock + + for ; block != nil; block = bc.GetBlock(block.PrevHash) { + if bytes.Compare(block.Hash(), commonBlockHash) == 0 { + log.Println("[BCHAIN] We have found the common parent block, breaking") + break + } + curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) + } + + log.Println("[BCHAIN] Current chain difficulty:", curChainDifficulty) + if chainDifficulty.Cmp(curChainDifficulty) == 1 { + log.Println("[BCHAIN] The incoming Chain beat our asses, resetting") + bc.ResetTillBlockHash(commonBlockHash) + } else { + log.Println("[BCHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + } +} +func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { + lastBlock := bc.CurrentBlock + returnTo := bc.GetBlock(hash) + + // TODO: REFACTOR TO FUNCTION, Used multiple times + bc.CurrentBlock = returnTo + bc.LastBlockHash = returnTo.Hash() + info := bc.BlockInfo(returnTo) + bc.LastBlockNumber = info.Number + // END TODO + + bc.Ethereum.StateManager().PrepareDefault(returnTo) + err := ethutil.Config.Db.Delete(lastBlock.Hash()) + if err != nil { + return err + } + + var block *Block + for ; block != nil; block = bc.GetBlock(block.PrevHash) { + if bytes.Compare(block.Hash(), hash) == 0 { + log.Println("[CHAIN] We have arrived at the the common parent block, breaking") + break + } + err = ethutil.Config.Db.Delete(block.Hash()) + if err != nil { + return err + } + } + log.Println("[CHAIN] Split chain deleted and reverted to common parent block.") + return nil +} + func (bc *BlockChain) GenesisBlock() *Block { return bc.genesisBlock } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 46d8228d9..9118db211 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -201,7 +201,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { return nil } - func (sm *StateManager) CalculateTD(block *Block) bool { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { @@ -215,6 +214,9 @@ func (sm *StateManager) CalculateTD(block *Block) bool { // The new TD will only be accepted if the new difficulty is // is greater than the previous. + fmt.Println("new block td:", td) + fmt.Println("cur block td:", sm.bc.TD) + if td.Cmp(sm.bc.TD) > 0 { // Set the new total difficulty back to the block chain sm.bc.SetTotalDifficulty(td) -- cgit v1.2.3 From 9a9e252cabdc6283d7f4e523860f0e4addf62152 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 15:27:18 +0100 Subject: Changes 'compiler' to work with any type --- ethchain/vm_test.go | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 16cbf51b7..047531e09 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -2,7 +2,6 @@ package ethchain import ( "bytes" - "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -130,27 +129,26 @@ func TestRun3(t *testing.T) { }) tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) addr := tx.Hash()[12:] - fmt.Printf("addr contract %x\n", addr) contract := MakeContract(tx, state) state.UpdateContract(contract) - callerScript := Compile([]string{ - "PUSH", "1337", // Argument - "PUSH", "65", // argument mem offset + callerScript := ethutil.Compile( + "PUSH", 1337, // Argument + "PUSH", 65, // argument mem offset "MSTORE", - "PUSH", "64", // ret size - "PUSH", "0", // ret offset - - "PUSH", "32", // arg size - "PUSH", "65", // arg offset - "PUSH", "1000", /// Gas - "PUSH", "0", /// value - "PUSH", string(addr), // Sender + "PUSH", 64, // ret size + "PUSH", 0, // ret offset + + "PUSH", 32, // arg size + "PUSH", 65, // arg offset + "PUSH", 1000, /// Gas + "PUSH", 0, /// value + "PUSH", addr, // Sender "CALL", - "PUSH", "64", - "PUSH", "0", + "PUSH", 64, + "PUSH", 0, "RETURN", - }) + ) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) // Contract addr as test address -- cgit v1.2.3 From 01c1bce9c5dfa2b2bcdf934afec3f206823f895f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 18:22:47 +0100 Subject: Removed regular ints from the virtual machine and closures --- ethchain/closure.go | 9 +++++++-- ethchain/contract.go | 9 +++++++-- ethchain/stack.go | 4 ++++ ethchain/vm.go | 21 +++++++++++++++------ 4 files changed, 33 insertions(+), 10 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index f8e692f61..2e809aa9d 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -15,7 +15,8 @@ type Callee interface { type ClosureBody interface { Callee ethutil.RlpEncodable - GetMem(int64) *ethutil.Value + GetMem(*big.Int) *ethutil.Value + SetMem(*big.Int, *ethutil.Value) } // Basic inline closure object which implement the 'closure' interface @@ -36,7 +37,7 @@ func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.I } // Retuns the x element in data slice -func (c *Closure) GetMem(x int64) *ethutil.Value { +func (c *Closure) GetMem(x *big.Int) *ethutil.Value { m := c.object.GetMem(x) if m == nil { return ethutil.EmptyValue() @@ -45,6 +46,10 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { return m } +func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { + c.object.SetMem(x, val) +} + func (c *Closure) Address() []byte { return c.object.Address() } diff --git a/ethchain/contract.go b/ethchain/contract.go index 93d2b68ba..f7ae01753 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -39,12 +39,17 @@ func (c *Contract) State() *State { return c.state } -func (c *Contract) GetMem(num int64) *ethutil.Value { - nb := ethutil.BigToBytes(big.NewInt(num), 256) +func (c *Contract) GetMem(num *big.Int) *ethutil.Value { + nb := ethutil.BigToBytes(num, 256) return c.Addr(nb) } +func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) { + addr := ethutil.BigToBytes(num, 256) + c.state.trie.Update(string(addr), string(val.Encode())) +} + // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *Contract) ReturnGas(val *big.Int, state *State) { c.Amount.Add(c.Amount, val) diff --git a/ethchain/stack.go b/ethchain/stack.go index b64b759fd..3c2899e62 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -237,6 +237,10 @@ func (m *Memory) Get(offset, size int64) []byte { return m.store[offset : offset+size] } +func (m *Memory) Len() int { + return len(m.store) +} + func (m *Memory) Print() { fmt.Println("### MEM ###") if len(m.store) > 0 { diff --git a/ethchain/vm.go b/ethchain/vm.go index 8b5bb93c0..bc3a9edaf 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -49,7 +49,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // New stack (should this be shared?) stack := NewStack() // Instruction pointer - pc := int64(0) + pc := big.NewInt(0) // Current step count step := 0 // The base for all big integer arithmetic @@ -226,7 +226,8 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x50 range case oPUSH: // Push PC+1 on to the stack - pc++ + pc.Add(pc, ethutil.Big1) + val := closure.GetMem(pc).BigInt() stack.Push(val) case oPOP: @@ -250,14 +251,22 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) case oSLOAD: loc := stack.Pop() - val := closure.GetMem(loc.Int64()) + val := closure.GetMem(loc) stack.Push(val.BigInt()) case oSSTORE: + val, loc := stack.Popn() + closure.SetMem(loc, ethutil.NewValue(val)) case oJUMP: + pc = stack.Pop() case oJUMPI: + pos, cond := stack.Popn() + if cond.Cmp(big.NewInt(0)) > 0 { + pc = pos + } case oPC: + stack.Push(pc) case oMSIZE: - + stack.Push(big.NewInt(int64(mem.Len()))) // 0x60 range case oCALL: // Pop return size and offset @@ -304,7 +313,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { ethutil.Config.Log.Debugln("Invalid opcode", op) } - pc++ + pc.Add(pc, ethutil.Big1) } } @@ -682,7 +691,7 @@ func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, j := int64(0) dataItems := make([]string, int(length.Uint64())) for i := from.Int64(); i < length.Int64(); i++ { - dataItems[j] = contract.GetMem(j).Str() + dataItems[j] = contract.GetMem(big.NewInt(j)).Str() j++ } -- cgit v1.2.3 From 6a86c517c4f4b372cad0ae1d92e926a482eac5ba Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 22 Mar 2014 11:47:27 +0100 Subject: Removed old VM code --- ethchain/state.go | 4 + ethchain/vm.go | 369 ------------------------------------------------------ 2 files changed, 4 insertions(+), 369 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index c9b35da21..1860647f2 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -149,6 +149,10 @@ func (s *State) Put(key, object []byte) { s.trie.Update(string(key), string(object)) } +func (s *State) Root() interface{} { + return s.trie.Root +} + // Script compilation functions // Compiles strings to machine code func Compile(code []string) (script []string) { diff --git a/ethchain/vm.go b/ethchain/vm.go index bc3a9edaf..126592b25 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -317,375 +317,6 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } } -/* -// Old VM code -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 := int64(0) - - if contract == nil { - fmt.Println("Contract not found") - return - } - - Pow256 := ethutil.BigPow(2, 256) - - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("# 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("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 { - ethutil.Config.Log.Debugf("%-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 := contract.Addr(x.Bytes()) - 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 := vm.stack.Pop().Int64() - // 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 = x.Int64() - 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.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), "") - - ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) - break out - default: - fmt.Printf("Invalid OPCODE: %x\n", op) - } - ethutil.Config.Log.Debugln("") - //vm.stack.Print() - pc++ - } - - state.UpdateContract(addr, contract) -} -*/ - func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) j := int64(0) -- cgit v1.2.3 From 274d5cc91c45349ec8d7a1f5a20ef29896b38b2e Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 24 Mar 2014 10:24:06 +0100 Subject: FindCanonicalChain returns true or false when we are on the Canonical chain or not --- ethchain/block_chain.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6eea14652..f25f0ca5a 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -103,7 +103,8 @@ func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { } // Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one -func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) { +// Return true if we are the using the canonical chain false if not +func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) bool { // 1. Calculate TD of the current chain // 2. Calculate TD of the new chain // Reset state to the correct one @@ -138,8 +139,10 @@ func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byt if chainDifficulty.Cmp(curChainDifficulty) == 1 { log.Println("[BCHAIN] The incoming Chain beat our asses, resetting") bc.ResetTillBlockHash(commonBlockHash) + return false } else { log.Println("[BCHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + return true } } func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { -- cgit v1.2.3 From ec6ec62dd4f3c4132c79b33fc20467ba98c16f10 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 24 Mar 2014 10:56:52 +0100 Subject: Remove some xtra logs --- ethchain/dagger.go | 4 ++-- ethchain/state_manager.go | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index a80a9d421..9d2df4069 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -29,14 +29,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - log.Println("[pow] Received reactor event; breaking out.") + log.Println("[POW] Received reactor event; breaking out.") return nil default: i++ if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - log.Println("Hashing @", int64(hashes), "khash") + log.Println("[POW] Hashing @", int64(hashes), "khash") } sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 5692a1d88..d907141a4 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -214,9 +214,6 @@ func (sm *StateManager) CalculateTD(block *Block) bool { // The new TD will only be accepted if the new difficulty is // is greater than the previous. - fmt.Println("new block td:", td) - fmt.Println("cur block td:", sm.bc.TD) - if td.Cmp(sm.bc.TD) > 0 { // Set the new total difficulty back to the block chain sm.bc.SetTotalDifficulty(td) -- cgit v1.2.3 From e0b6091d7ef709902f534c1a4b57151f0171e03c Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Mar 2014 13:20:34 +0100 Subject: Test fixes and removed old code. Added VM gas fees --- ethchain/stack.go | 8 +-- ethchain/vm.go | 48 +++++++++++++++-- ethchain/vm_test.go | 147 ++++++++++++++++------------------------------------ 3 files changed, 94 insertions(+), 109 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index 3c2899e62..57165c432 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -202,7 +202,7 @@ func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } func (st *Stack) Print() { - fmt.Println("### STACK ###") + fmt.Println("### stack ###") if len(st.data) > 0 { for i, val := range st.data { fmt.Printf("%-3d %v\n", i, val) @@ -242,15 +242,15 @@ func (m *Memory) Len() int { } func (m *Memory) Print() { - fmt.Println("### MEM ###") + fmt.Printf("### mem %d bytes ###\n", len(m.store)) if len(m.store) > 0 { addr := 0 - for i := 0; i+32 < len(m.store); i += 32 { + for i := 0; i+32 <= len(m.store); i += 32 { fmt.Printf("%03d %v\n", addr, m.store[i:i+32]) addr++ } } else { fmt.Println("-- empty --") } - fmt.Println("###########") + fmt.Println("####################") } diff --git a/ethchain/vm.go b/ethchain/vm.go index 126592b25..9b6807925 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -10,6 +10,17 @@ import ( "math/big" ) +var ( + GasStep = big.NewInt(1) + GasSha = big.NewInt(20) + GasSLoad = big.NewInt(20) + GasSStore = big.NewInt(100) + GasBalance = big.NewInt(20) + GasCreate = big.NewInt(100) + GasCall = big.NewInt(20) + GasMemory = big.NewInt(1) +) + type Vm struct { txPool *TxPool // Stack for processing contracts @@ -70,10 +81,41 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } // TODO Get each instruction cost properly - fee := new(big.Int) - fee.Add(fee, big.NewInt(1000)) + gas := new(big.Int) + useGas := func(amount *big.Int) { + gas.Add(gas, amount) + } + + switch op { + case oSHA3: + useGas(GasSha) + case oSLOAD: + useGas(GasSLoad) + case oSSTORE: + var mult *big.Int + y, x := stack.Peekn() + val := closure.GetMem(x) + if val.IsEmpty() && len(y.Bytes()) > 0 { + mult = ethutil.Big2 + } else if !val.IsEmpty() && len(y.Bytes()) == 0 { + mult = ethutil.Big0 + } else { + mult = ethutil.Big1 + } + useGas(base.Mul(mult, GasSStore)) + case oBALANCE: + useGas(GasBalance) + case oCREATE: + useGas(GasCreate) + case oCALL: + useGas(GasCall) + case oMLOAD, oMSIZE, oMSTORE8, oMSTORE: + useGas(GasMemory) + default: + useGas(GasStep) + } - if closure.Gas.Cmp(fee) < 0 { + if closure.Gas.Cmp(gas) < 0 { return closure.Return(nil) } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 047531e09..308a65432 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -2,113 +2,15 @@ package ethchain import ( "bytes" + "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/mutan" "math/big" + "strings" "testing" ) -/* - -func TestRun(t *testing.T) { - InitFees() - - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "TXSENDER", - "SUICIDE", - }) - - tx := NewTransaction(ContractAddr, big.NewInt(1e17), script) - fmt.Printf("contract addr %x\n", tx.Hash()[12:]) - contract := MakeContract(tx, state) - vm := &Vm{} - - vm.Process(contract, state, RuntimeVars{ - address: tx.Hash()[12:], - blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - txValue: tx.Value, - txData: tx.Data, - }) -} - -func TestRun1(t *testing.T) { - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "PUSH", "0", - "PUSH", "0", - "TXSENDER", - "PUSH", "10000000", - "MKTX", - }) - fmt.Println(ethutil.NewValue(script)) - - tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) - fmt.Printf("contract addr %x\n", tx.Hash()[12:]) - contract := MakeContract(tx, state) - vm := &Vm{} - - vm.Process(contract, state, RuntimeVars{ - address: tx.Hash()[12:], - blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - txValue: tx.Value, - txData: tx.Data, - }) -} - -func TestRun2(t *testing.T) { - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "PUSH", "0", - "PUSH", "0", - "TXSENDER", - "PUSH", "10000000", - "MKTX", - }) - fmt.Println(ethutil.NewValue(script)) - - tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) - fmt.Printf("contract addr %x\n", tx.Hash()[12:]) - contract := MakeContract(tx, state) - vm := &Vm{} - - vm.Process(contract, state, RuntimeVars{ - address: tx.Hash()[12:], - blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - txValue: tx.Value, - txData: tx.Data, - }) -} -*/ - -// XXX Full stack test func TestRun3(t *testing.T) { ethutil.ReadConfig("") @@ -132,7 +34,7 @@ func TestRun3(t *testing.T) { contract := MakeContract(tx, state) state.UpdateContract(contract) - callerScript := ethutil.Compile( + callerScript := ethutil.Assemble( "PUSH", 1337, // Argument "PUSH", 65, // argument mem offset "MSTORE", @@ -172,3 +74,44 @@ func TestRun3(t *testing.T) { t.Errorf("expected return value to be %v, got %v", exp, ret) } } + +func TestRun4(t *testing.T) { + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + mutan.NewCompiler().Compile(strings.NewReader(` +a = 1337 +c = 1 +[0] = 50 +d = [0] +`)) + + asm := mutan.NewCompiler().Compile(strings.NewReader(` + a = 3 + 3 + [1000] = a + [1000] +`)) + asm = append(asm, "LOG") + fmt.Println(asm) + + callerScript := ethutil.Assemble(asm...) + callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) + + // Contract addr as test address + account := NewAccount(ContractAddr, big.NewInt(10000000)) + callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) + + vm := NewVm(state, RuntimeVars{ + origin: account.Address(), + blockNumber: 1, + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + // XXX Tx data? Could be just an argument to the closure instead + txData: nil, + }) + callerClosure.Call(vm, nil) +} -- cgit v1.2.3 From 6253d109389d49e47772597de24cd11874b91338 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 24 Mar 2014 15:04:29 +0100 Subject: initial testcode for canonical chain --- ethchain/block_chain.go | 35 ++++++++++------- ethchain/block_chain_test.go | 92 ++++++++++++++++++++++++++++++++++++++++++++ ethchain/state_manager.go | 3 ++ 3 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 ethchain/block_chain_test.go (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index f25f0ca5a..0e3601a4b 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -24,7 +24,7 @@ type BlockChain struct { func NewBlockChain(ethereum EthManager) *BlockChain { bc := &BlockChain{} - bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) + bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis)) bc.Ethereum = ethereum bc.setLastBlock() @@ -101,10 +101,18 @@ func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { return blockDiff } +func (bc *BlockChain) FindCanonicalChainFromMsg(msg *ethwire.Msg, commonBlockHash []byte) bool { + var blocks []*Block + for i := 0; i < (msg.Data.Len() - 1); i++ { + block := NewBlockFromRlpValue(msg.Data.Get(i)) + blocks = append(blocks, block) + } + return bc.FindCanonicalChain(blocks, commonBlockHash) +} // Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one // Return true if we are the using the canonical chain false if not -func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) bool { +func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte) bool { // 1. Calculate TD of the current chain // 2. Calculate TD of the new chain // Reset state to the correct one @@ -113,35 +121,35 @@ func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byt // Calculate the entire chain until the block we both have // Start with the newest block we got, all the way back to the common block we both know - for i := 0; i < (msg.Data.Len() - 1); i++ { - block := NewBlockFromRlpValue(msg.Data.Get(i)) + for _, block := range blocks { if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[BCHAIN] We have found the common parent block, breaking") + log.Println("[CHAIN] We have found the common parent block, breaking") break } chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[BCHAIN] Incoming chain difficulty:", chainDifficulty) + log.Println("[CHAIN] Incoming chain difficulty:", chainDifficulty) curChainDifficulty := new(big.Int) block := bc.CurrentBlock - - for ; block != nil; block = bc.GetBlock(block.PrevHash) { + for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { + i++ if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[BCHAIN] We have found the common parent block, breaking") + log.Println("[CHAIN] We have found the common parent block, breaking") break } + log.Println("CHECKING BLOGK:", i) curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[BCHAIN] Current chain difficulty:", curChainDifficulty) + log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - log.Println("[BCHAIN] The incoming Chain beat our asses, resetting") + log.Println("[CHAIN] The incoming Chain beat our asses, resetting") bc.ResetTillBlockHash(commonBlockHash) return false } else { - log.Println("[BCHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + log.Println("[CHAIN] Our chain showed the incoming chain who is boss. Ignoring.") return true } } @@ -286,6 +294,7 @@ func (bc *BlockChain) Add(block *Block) { bc.LastBlockHash = block.Hash() encodedBlock := block.RlpEncode() + log.Println(encodedBlock) ethutil.Config.Db.Put(block.Hash(), encodedBlock) ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) } @@ -296,7 +305,7 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block { return nil } - return NewBlockFromData(data) + return NewBlockFromBytes(data) } func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go new file mode 100644 index 000000000..736247e83 --- /dev/null +++ b/ethchain/block_chain_test.go @@ -0,0 +1,92 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" + "testing" +) + +// Implement our EthTest Manager +type TestManager struct { + stateManager *StateManager + reactor *ethutil.ReactorEngine + + txPool *TxPool + blockChain *BlockChain + Blocks []*Block +} + +func (s *TestManager) BlockChain() *BlockChain { + return s.blockChain +} + +func (tm *TestManager) TxPool() *TxPool { + return tm.txPool +} + +func (tm *TestManager) StateManager() *StateManager { + return tm.stateManager +} + +func (tm *TestManager) Reactor() *ethutil.ReactorEngine { + return tm.reactor +} +func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { + fmt.Println("Broadcast not implemented") +} + +func NewTestManager() *TestManager { + ethutil.ReadConfig(".ethtest") + + db, err := ethdb.NewMemDatabase() + if err != nil { + fmt.Println("Could not create mem-db, failing") + return nil + } + ethutil.Config.Db = db + + testManager := &TestManager{} + testManager.reactor = ethutil.NewReactorEngine() + + testManager.txPool = NewTxPool(testManager) + testManager.blockChain = NewBlockChain(testManager) + testManager.stateManager = NewStateManager(testManager) + + // Start the tx pool + testManager.txPool.Start() + + return testManager +} +func (tm *TestManager) AddFakeBlock(blk []byte) error { + block := NewBlockFromBytes(blk) + tm.Blocks = append(tm.Blocks, block) + tm.StateManager().PrepareDefault(block) + err := tm.StateManager().ProcessBlock(block, false) + return err +} +func (tm *TestManager) CreateChain1() error { + err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 32, 251, 128, 160, 4, 10, 11, 225, 132, 86, 146, 227, 229, 137, 164, 245, 16, 139, 219, 12, 251, 178, 154, 168, 210, 18, 84, 40, 250, 41, 124, 92, 169, 242, 246, 180, 192, 192}) + err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 222, 229, 152, 228, 200, 163, 244, 144, 120, 18, 203, 253, 195, 185, 105, 131, 163, 226, 116, 40, 140, 68, 249, 198, 221, 152, 121, 0, 124, 11, 180, 125, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 224, 4, 132, 83, 48, 36, 250, 128, 160, 79, 58, 51, 246, 238, 249, 210, 253, 136, 83, 71, 134, 49, 114, 190, 189, 242, 78, 100, 238, 101, 84, 204, 176, 198, 25, 139, 151, 60, 84, 51, 126, 192, 192}) + err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 68, 52, 33, 210, 160, 189, 217, 255, 78, 37, 196, 217, 94, 247, 166, 169, 224, 199, 102, 110, 85, 213, 45, 13, 173, 106, 4, 103, 151, 195, 38, 86, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 208, 12, 132, 83, 48, 38, 206, 128, 160, 65, 147, 32, 128, 177, 198, 131, 57, 57, 68, 135, 65, 198, 178, 138, 43, 25, 135, 92, 174, 208, 119, 103, 225, 26, 207, 243, 31, 225, 29, 173, 119, 192, 192}) + return err +} +func (tm *TestManager) CreateChain2() error { + err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 40, 35, 128, 160, 162, 214, 119, 207, 212, 186, 64, 47, 14, 186, 98, 118, 203, 79, 172, 205, 33, 206, 225, 177, 225, 194, 98, 188, 63, 219, 13, 151, 47, 32, 204, 27, 192, 192}) + err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 0, 210, 76, 6, 13, 18, 219, 190, 18, 250, 23, 178, 198, 117, 254, 85, 14, 74, 104, 116, 56, 144, 116, 172, 14, 3, 236, 99, 248, 228, 142, 91, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 255, 252, 132, 83, 48, 40, 74, 128, 160, 185, 20, 138, 2, 210, 15, 71, 144, 89, 167, 94, 155, 148, 118, 170, 157, 122, 70, 70, 114, 50, 221, 231, 8, 132, 167, 115, 239, 44, 245, 41, 226, 192, 192}) + return err +} + +func TestBlockChainReorg(t *testing.T) { + testManager := NewTestManager() + testManager.CreateChain1() + testManager2 := NewTestManager() + testManager2.CreateChain2() + + // This fails because we keep resetting the DB + block := testManager.BlockChain().GetBlock(testManager.BlockChain().CurrentBlock.PrevHash) + fmt.Println(block) + //testManager.BlockChain().FindCanonicalChain(testManager2.Blocks, testManager.BlockChain().GenesisBlock().Hash()) + +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index d907141a4..140b0efd0 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -144,6 +144,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { hash := block.Hash() if sm.bc.HasBlock(hash) { + fmt.Println("[SM] We already have this block, ignoring") return nil } @@ -158,12 +159,14 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Block validation if err := sm.ValidateBlock(block); err != nil { + fmt.Println("[SM] Error validating block:", err) return err } // I'm not sure, but I don't know if there should be thrown // any errors at this time. if err := sm.AccumelateRewards(block); err != nil { + fmt.Println("[SM] Error accumulating reward", err) return err } -- cgit v1.2.3 From 43cad6901620ca077e43f195cc5ae4d1c8edb2d0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 15:42:39 +0100 Subject: Reworked transaction constructors --- ethchain/keypair.go | 3 +++ ethchain/transaction.go | 66 +++++++++++++++++++++++++++++++++++++++---------- ethchain/vm.go | 3 ++- 3 files changed, 58 insertions(+), 14 deletions(-) (limited to 'ethchain') diff --git a/ethchain/keypair.go b/ethchain/keypair.go index 9fdc95972..9daaedbee 100644 --- a/ethchain/keypair.go +++ b/ethchain/keypair.go @@ -34,6 +34,7 @@ func (k *KeyPair) Account() *Account { // Create transaction, creates a new and signed transaction, ready for processing func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { + /* TODO tx := NewTransaction(receiver, value, data) tx.Nonce = k.account.Nonce @@ -41,6 +42,8 @@ func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Tran tx.Sign(k.PrivateKey) return tx + */ + return nil } func (k *KeyPair) RlpEncode() []byte { diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 3b07c81d4..695071251 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -18,16 +18,21 @@ type Transaction struct { Data []string v byte r, s []byte + + // Indicates whether this tx is a contract creation transaction + contractCreation bool } +/* func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { tx := Transaction{Recipient: to, Value: value, Nonce: 0, Data: data} return &tx } +*/ func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { - return &Transaction{Value: value, Gasprice: gasprice, Data: data} + return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true} } func NewContractMessageTx(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { @@ -38,10 +43,12 @@ func NewTx(to []byte, value *big.Int, data []string) *Transaction { return &Transaction{Recipient: to, Value: value, Gasprice: big.NewInt(0), Gas: big.NewInt(0), Nonce: 0, Data: data} } +/* // XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { return NewTransactionFromBytes(data) } +*/ func NewTransactionFromBytes(data []byte) *Transaction { tx := &Transaction{} @@ -148,19 +155,52 @@ func (tx *Transaction) RlpDecode(data []byte) { tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) } +// [ NONCE, VALUE, GASPRICE, TO, GAS, DATA, V, R, S ] 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() + tx.Value = decoder.Get(1).BigInt() + tx.Gasprice = decoder.Get(2).BigInt() + + // If the 4th item is a list(slice) this tx + // is a contract creation tx + if decoder.Get(3).IsSlice() { + d := decoder.Get(3) + tx.Data = make([]string, d.Len()) + for i := 0; i < d.Len(); i++ { + tx.Data[i] = d.Get(i).Str() + } + + tx.v = byte(decoder.Get(4).Uint()) + tx.r = decoder.Get(5).Bytes() + tx.s = decoder.Get(6).Bytes() + tx.contractCreation = true + } else { + tx.Recipient = decoder.Get(3).Bytes() + tx.Gas = decoder.Get(4).BigInt() + + d := decoder.Get(5) + tx.Data = make([]string, d.Len()) + for i := 0; i < d.Len(); i++ { + tx.Data[i] = d.Get(i).Str() + } + + tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() } - - // TODO something going wrong here - tx.v = byte(decoder.Get(4).Uint()) - tx.r = decoder.Get(5).Bytes() - tx.s = decoder.Get(6).Bytes() + /* + 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() + } + + tx.v = byte(decoder.Get(4).Uint()) + tx.r = decoder.Get(5).Bytes() + tx.s = decoder.Get(6).Bytes() + */ } diff --git a/ethchain/vm.go b/ethchain/vm.go index 9b6807925..aefc8ff0c 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,7 +5,6 @@ import ( _ "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" - "log" _ "math" "math/big" ) @@ -359,6 +358,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } } +/* func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) j := int64(0) @@ -395,3 +395,4 @@ func contractMemory(state *State, contractAddr []byte, memAddr *big.Int) *big.In return decoder.BigInt() } +*/ -- cgit v1.2.3 From 00c5f9b9a67a6ab6f2850b756804dfa6efd8a824 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 19:49:47 +0100 Subject: Updated transaction model Changed the behaviour of decoding rlp data. Something is considered to be creating a contract if the 4th item is a list. Changed constructors. --- ethchain/transaction.go | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 695071251..d71f9c7f7 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -2,6 +2,7 @@ package ethchain import ( "bytes" + "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -23,33 +24,14 @@ type Transaction struct { contractCreation bool } -/* -func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { - tx := Transaction{Recipient: to, Value: value, Nonce: 0, Data: data} - - return &tx -} -*/ - func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true} } -func NewContractMessageTx(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { +func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} } -func NewTx(to []byte, value *big.Int, data []string) *Transaction { - return &Transaction{Recipient: to, Value: value, Gasprice: big.NewInt(0), Gas: big.NewInt(0), Nonce: 0, Data: data} -} - -/* -// XXX Deprecated -func NewTransactionFromData(data []byte) *Transaction { - return NewTransactionFromBytes(data) -} -*/ - func NewTransactionFromBytes(data []byte) *Transaction { tx := &Transaction{} tx.RlpDecode(data) @@ -131,16 +113,13 @@ func (tx *Transaction) Sign(privk []byte) error { } 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, + data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice} + + if !tx.contractCreation { + data = append(data, tx.Recipient, tx.Gas) } + + return append(data, ethutil.NewSliceValue(tx.Data).Slice(), tx.v, tx.r, tx.s) } func (tx *Transaction) RlpValue() *ethutil.Value { @@ -156,14 +135,16 @@ func (tx *Transaction) RlpDecode(data []byte) { } // [ NONCE, VALUE, GASPRICE, TO, GAS, DATA, V, R, S ] +//["" "\x03\xe8" "" "\xaa" "\x03\xe8" [] '\x1c' "\x10C\x15\xfc\xe5\xd0\t\xe4\r\xe7\xefa\xf5aE\xd6\x14\xaed\xb5.\xf5\x18\xa1S_j\xe0A\xdc5U" "dQ\nqy\xf8\x17+\xbf\xd7Jx\xda-\xcb\xd7\xcfQ\x1bI\xb8_9\b\x80\xeaë“Ži|\x1f"] func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { + fmt.Println(decoder) tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() tx.Gasprice = decoder.Get(2).BigInt() // If the 4th item is a list(slice) this tx // is a contract creation tx - if decoder.Get(3).IsSlice() { + if decoder.Get(3).IsList() { d := decoder.Get(3) tx.Data = make([]string, d.Len()) for i := 0; i < d.Len(); i++ { @@ -173,6 +154,7 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.v = byte(decoder.Get(4).Uint()) tx.r = decoder.Get(5).Bytes() tx.s = decoder.Get(6).Bytes() + tx.contractCreation = true } else { tx.Recipient = decoder.Get(3).Bytes() -- cgit v1.2.3 From 56a58ad70db22b0714a8f81fe31eaedc2a1e8e0d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 22:02:39 +0100 Subject: Removed debug and comments --- ethchain/transaction.go | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index d71f9c7f7..af27fe639 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -2,7 +2,6 @@ package ethchain import ( "bytes" - "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -134,10 +133,7 @@ func (tx *Transaction) RlpDecode(data []byte) { tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) } -// [ NONCE, VALUE, GASPRICE, TO, GAS, DATA, V, R, S ] -//["" "\x03\xe8" "" "\xaa" "\x03\xe8" [] '\x1c' "\x10C\x15\xfc\xe5\xd0\t\xe4\r\xe7\xefa\xf5aE\xd6\x14\xaed\xb5.\xf5\x18\xa1S_j\xe0A\xdc5U" "dQ\nqy\xf8\x17+\xbf\xd7Jx\xda-\xcb\xd7\xcfQ\x1bI\xb8_9\b\x80\xeaë“Ži|\x1f"] func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { - fmt.Println(decoder) tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() tx.Gasprice = decoder.Get(2).BigInt() @@ -170,19 +166,4 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() } - /* - 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() - } - - tx.v = byte(decoder.Get(4).Uint()) - tx.r = decoder.Get(5).Bytes() - tx.s = decoder.Get(6).Bytes() - */ } -- cgit v1.2.3 From 3c3431d111ae8ba7f03349f93c9b191fcdf92254 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 23:17:14 +0100 Subject: Fixed IsContract method to use the contractCreation flag --- ethchain/transaction.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index af27fe639..9fdf55b4d 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,7 +1,6 @@ package ethchain import ( - "bytes" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -62,7 +61,7 @@ func (tx *Transaction) Hash() []byte { } func (tx *Transaction) IsContract() bool { - return bytes.Compare(tx.Recipient, ContractAddr) == 0 + return tx.contractCreation } func (tx *Transaction) Signature(key []byte) []byte { -- cgit v1.2.3 From 75e6406c1f1034dbf96aca28193d7e1e0653db50 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 23:17:23 +0100 Subject: Fixed tests --- ethchain/vm_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 308a65432..5acc47659 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -29,7 +29,7 @@ func TestRun3(t *testing.T) { "PUSH", "0", "RETURN", }) - tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) addr := tx.Hash()[12:] contract := MakeContract(tx, state) state.UpdateContract(contract) @@ -51,7 +51,7 @@ func TestRun3(t *testing.T) { "PUSH", 0, "RETURN", ) - callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) @@ -84,20 +84,20 @@ func TestRun4(t *testing.T) { mutan.NewCompiler().Compile(strings.NewReader(` a = 1337 c = 1 -[0] = 50 -d = [0] +store[0] = 50 +d = store[0] `)) - asm := mutan.NewCompiler().Compile(strings.NewReader(` + asm, _ := mutan.NewCompiler().Compile(strings.NewReader(` a = 3 + 3 - [1000] = a - [1000] + stotre[1000] = a + store[1000] `)) asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) - callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) -- cgit v1.2.3 From 60fd2f3521471b300107847271f4df2919f1b0d4 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Thu, 27 Mar 2014 23:25:03 +0100 Subject: Update vm_test.go store ... --- ethchain/vm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 5acc47659..c802420cb 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -90,7 +90,7 @@ d = store[0] asm, _ := mutan.NewCompiler().Compile(strings.NewReader(` a = 3 + 3 - stotre[1000] = a + store[1000] = a store[1000] `)) asm = append(asm, "LOG") -- cgit v1.2.3 From b888652201277ab86e9e8c280e75e23ced5e3d38 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Mar 2014 11:20:07 +0100 Subject: Added missing GetTx (0x16) wire message --- ethchain/transaction_pool.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index fdc386303..4a4f2e809 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -207,7 +207,7 @@ func (pool *TxPool) QueueTransaction(tx *Transaction) { pool.queueChan <- tx } -func (pool *TxPool) Flush() []*Transaction { +func (pool *TxPool) CurrentTransactions() []*Transaction { pool.mutex.Lock() defer pool.mutex.Unlock() @@ -221,6 +221,12 @@ func (pool *TxPool) Flush() []*Transaction { i++ } + return txList +} + +func (pool *TxPool) Flush() []*Transaction { + txList := pool.CurrentTransactions() + // Recreate a new list all together // XXX Is this the fastest way? pool.pool = list.New() -- cgit v1.2.3 From 6625b6ffbdb93a47de2187198d6e826fb32c1ba6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 30 Mar 2014 12:58:37 +0200 Subject: Changed to new mutan API --- ethchain/state_manager.go | 26 +++++++++++++------------- ethchain/vm_test.go | 27 +++++++++++++++------------ 2 files changed, 28 insertions(+), 25 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3b5507740..5c693442b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -100,16 +100,21 @@ func (sm *StateManager) MakeContract(tx *Transaction) { } } +// Apply transactions uses the transaction passed to it and applies them onto +// the current processing state. func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { // If there's no recipient, it's a contract + // Check if this is a contract creation traction and if so + // create a contract of this tx. if tx.IsContract() { sm.MakeContract(tx) - //XXX block.MakeContract(tx) } else { + // Figure out if the address this transaction was sent to is a + // contract or an actual account. In case of a contract, we process that + // contract instead of moving funds between accounts. if contract := sm.procState.GetContract(tx.Recipient); contract != nil { - //XXX if contract := block.state.GetContract(tx.Recipient); contract != nil { sm.ProcessContract(contract, tx, block) } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block) @@ -172,14 +177,12 @@ func (sm *StateManager) ProcessBlock(block *Block) error { // if !sm.compState.Cmp(sm.procState) if !sm.compState.Cmp(sm.procState) { - //XXX return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, sm.bc.CurrentBlock.State().trie.Root) return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) } // Calculate the new total difficulty and sync back to the db if sm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - //XXX sm.bc.CurrentBlock.Sync() sm.procState.Sync() // Broadcast the valid block back to the wire @@ -273,12 +276,10 @@ func CalculateUncleReward(block *Block) *big.Int { func (sm *StateManager) AccumelateRewards(block *Block) error { // Get the coinbase rlp data - //XXX addr := processor.state.GetAccount(block.Coinbase) addr := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - //XXX processor.state.UpdateAccount(block.Coinbase, addr) sm.procState.UpdateAccount(block.Coinbase, addr) for _, uncle := range block.Uncles { @@ -298,13 +299,12 @@ func (sm *StateManager) Stop() { func (sm *StateManager) ProcessContract(contract *Contract, 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) + } + }() + caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index c802420cb..589f0bf4a 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -81,18 +81,21 @@ func TestRun4(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - mutan.NewCompiler().Compile(strings.NewReader(` -a = 1337 -c = 1 -store[0] = 50 -d = store[0] -`)) - - asm, _ := mutan.NewCompiler().Compile(strings.NewReader(` - a = 3 + 3 - store[1000] = a - store[1000] -`)) + mutan.Compile(strings.NewReader(` + a = 1337 + c = 1 + store[0] = 50 + d = store[0] + `), false) + + asm, err := mutan.Compile(strings.NewReader(` + a = 3 + 3 + store[1000] = a + store[1000] + `), false) + if err != nil { + fmt.Println(err) + } asm = append(asm, "LOG") fmt.Println(asm) -- cgit v1.2.3 From 205e33bc831bb44f41dc899ae41bbfe0e44ddc5d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 30 Mar 2014 18:55:51 +0200 Subject: Fixed bug in stack to expand beyond expectations. Fixed EQ and NOT opcode --- ethchain/stack.go | 14 +++++++++----- ethchain/vm.go | 20 ++++++++++++++------ ethchain/vm_test.go | 21 +++++++++------------ 3 files changed, 32 insertions(+), 23 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index 57165c432..e3fc4b684 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -173,21 +173,25 @@ func NewStack() *Stack { } func (st *Stack) Pop() *big.Int { - str := st.data[0] - st.data = st.data[1:] + str := st.data[len(st.data)-1] + + copy(st.data[:len(st.data)-1], st.data[:len(st.data)-1]) + st.data = st.data[:len(st.data)-1] return str } func (st *Stack) Popn() (*big.Int, *big.Int) { - ints := st.data[:2] - st.data = st.data[2:] + ints := st.data[len(st.data)-2:] + + copy(st.data[:len(st.data)-2], st.data[:len(st.data)-2]) + st.data = st.data[:len(st.data)-2] return ints[0], ints[1] } func (st *Stack) Peek() *big.Int { - str := st.data[0] + str := st.data[len(st.data)-1] return str } diff --git a/ethchain/vm.go b/ethchain/vm.go index aefc8ff0c..18b7fe607 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,7 +2,7 @@ package ethchain import ( _ "bytes" - _ "fmt" + "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" _ "math" @@ -213,10 +213,17 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } else { stack.Push(ethutil.BigFalse) } - case oNOT: + case oEQ: x, y := stack.Popn() - // x != y - if x.Cmp(y) != 0 { + // x == y + if x.Cmp(y) == 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case oNOT: + x := stack.Pop() + if x.Cmp(ethutil.BigFalse) == 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) @@ -300,8 +307,8 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { case oJUMP: pc = stack.Pop() case oJUMPI: - pos, cond := stack.Popn() - if cond.Cmp(big.NewInt(0)) > 0 { + cond, pos := stack.Popn() + if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos } case oPC: @@ -314,6 +321,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { retSize, retOffset := stack.Popn() // Pop input size and offset inSize, inOffset := stack.Popn() + fmt.Println(inSize, inOffset) // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) // Pop gas and value of the stack. diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 589f0bf4a..e3880d26e 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,7 +1,7 @@ package ethchain import ( - "bytes" + _ "bytes" "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" @@ -11,6 +11,7 @@ import ( "testing" ) +/* func TestRun3(t *testing.T) { ethutil.ReadConfig("") @@ -73,7 +74,7 @@ func TestRun3(t *testing.T) { if bytes.Compare(ret, exp) != 0 { t.Errorf("expected return value to be %v, got %v", exp, ret) } -} +}*/ func TestRun4(t *testing.T) { ethutil.ReadConfig("") @@ -81,17 +82,13 @@ func TestRun4(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - mutan.Compile(strings.NewReader(` - a = 1337 - c = 1 - store[0] = 50 - d = store[0] - `), false) - asm, err := mutan.Compile(strings.NewReader(` - a = 3 + 3 - store[1000] = a - store[1000] + a = 10 + b = 10 + if a == b { + b = 1000 + c = 10 + } `), false) if err != nil { fmt.Println(err) -- cgit v1.2.3 From 7cc28c8b469ba8df8bad1e3bbbba7fbd99b88535 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 30 Mar 2014 22:03:08 +0200 Subject: Added storage test --- ethchain/vm_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index e3880d26e..2a02bcf4c 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -86,14 +86,22 @@ func TestRun4(t *testing.T) { a = 10 b = 10 if a == b { - b = 1000 c = 10 + if c == 10 { + d = 1000 + e = 10 + } } + + store[0] = 20 + test = store[0] + store[a] = 20 + f = store[400] `), false) if err != nil { fmt.Println(err) } - asm = append(asm, "LOG") + //asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) -- cgit v1.2.3 From 7277c420479239fbea78417e42c43ee0162c2728 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 31 Mar 2014 01:03:28 +0200 Subject: Fixed some state issues --- ethchain/state_manager.go | 6 +++--- ethchain/transaction.go | 3 ++- ethchain/vm.go | 2 ++ ethchain/vm_test.go | 2 -- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 5c693442b..d9831d49f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -82,7 +82,7 @@ func (sm *StateManager) WatchAddr(addr []byte) *AccountState { func (sm *StateManager) GetAddrState(addr []byte) *AccountState { account := sm.addrStateStore.Get(addr) if account == nil { - a := sm.bc.CurrentBlock.state.GetAccount(addr) + a := sm.procState.GetAccount(addr) account = &AccountState{Nonce: a.Nonce, Account: a} } @@ -128,9 +128,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // The prepare function, prepares the state manager for the next // "ProcessBlock" action. -func (sm *StateManager) Prepare(processer *State, comparative *State) { +func (sm *StateManager) Prepare(processor *State, comparative *State) { sm.compState = comparative - sm.procState = processer + sm.procState = processor } // Default prepare function diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 9fdf55b4d..506e3c159 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -116,8 +116,9 @@ func (tx *Transaction) RlpData() interface{} { if !tx.contractCreation { data = append(data, tx.Recipient, tx.Gas) } + d := ethutil.NewSliceValue(tx.Data).Slice() - return append(data, ethutil.NewSliceValue(tx.Data).Slice(), tx.v, tx.r, tx.s) + return append(data, d, tx.v, tx.r, tx.s) } func (tx *Transaction) RlpValue() *ethutil.Value { diff --git a/ethchain/vm.go b/ethchain/vm.go index 18b7fe607..98aaa603a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -115,6 +115,8 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } if closure.Gas.Cmp(gas) < 0 { + ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) + return closure.Return(nil) } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 2a02bcf4c..838f12f56 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -94,9 +94,7 @@ func TestRun4(t *testing.T) { } store[0] = 20 - test = store[0] store[a] = 20 - f = store[400] `), false) if err != nil { fmt.Println(err) -- cgit v1.2.3 From 5f49a659c36dbfb8c330ddc3d4565c19a9a936b5 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 31 Mar 2014 12:54:37 +0200 Subject: More blockchain testing --- ethchain/block_chain.go | 13 +++++++++++-- ethchain/block_chain_test.go | 35 +++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 0e3601a4b..8c03eec38 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -126,6 +126,7 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] We have found the common parent block, breaking") break } + log.Println("Checking incoming blocks:") chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } @@ -139,13 +140,20 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] We have found the common parent block, breaking") break } - log.Println("CHECKING BLOGK:", i) + anOtherBlock := bc.GetBlock(block.PrevHash) + if anOtherBlock == nil { + // We do not want to count the genesis block for difficulty since that's not being sent + log.Println("[CHAIN] At genesis block, breaking") + break + } + log.Printf("CHECKING OUR OWN BLOCKS: %x", block.Hash()) + log.Printf("%x", bc.GenesisBlock().Hash()) curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - log.Println("[CHAIN] The incoming Chain beat our asses, resetting") + log.Printf("[CHAIN] The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) bc.ResetTillBlockHash(commonBlockHash) return false } else { @@ -165,6 +173,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { // END TODO bc.Ethereum.StateManager().PrepareDefault(returnTo) + err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { return err diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 736247e83..30eb62266 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -78,15 +78,38 @@ func (tm *TestManager) CreateChain2() error { return err } -func TestBlockChainReorg(t *testing.T) { +func TestNegativeBlockChainReorg(t *testing.T) { + // We are resetting the database between creation so we need to cache our information + testManager2 := NewTestManager() + testManager2.CreateChain2() + tm2Blocks := testManager2.Blocks + testManager := NewTestManager() testManager.CreateChain1() + oldState := testManager.BlockChain().CurrentBlock.State() + + if testManager.BlockChain().FindCanonicalChain(tm2Blocks, testManager.BlockChain().GenesisBlock().Hash()) != true { + t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.") + } + if testManager.BlockChain().CurrentBlock.State() != oldState { + t.Error("I expected the top state to be the same as it was as before the reorg") + } + +} + +func TestPositiveBlockChainReorg(t *testing.T) { + testManager := NewTestManager() + testManager.CreateChain1() + tm1Blocks := testManager.Blocks + testManager2 := NewTestManager() testManager2.CreateChain2() + oldState := testManager2.BlockChain().CurrentBlock.State() - // This fails because we keep resetting the DB - block := testManager.BlockChain().GetBlock(testManager.BlockChain().CurrentBlock.PrevHash) - fmt.Println(block) - //testManager.BlockChain().FindCanonicalChain(testManager2.Blocks, testManager.BlockChain().GenesisBlock().Hash()) - + if testManager2.BlockChain().FindCanonicalChain(tm1Blocks, testManager.BlockChain().GenesisBlock().Hash()) == true { + t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.") + } + if testManager2.BlockChain().CurrentBlock.State() == oldState { + t.Error("I expected the top state to have been modified but it was not") + } } -- cgit v1.2.3 From 7d0348e4baf45197ca506070e06e756a4ba6ccf6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Apr 2014 10:41:30 +0200 Subject: Handle contract messages --- ethchain/state_manager.go | 18 +++++++++++++----- ethchain/transaction_pool.go | 12 +++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index d9831d49f..95e46e41d 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -114,13 +114,18 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Figure out if the address this transaction was sent to is a // contract or an actual account. In case of a contract, we process that // contract instead of moving funds between accounts. + var err error if contract := sm.procState.GetContract(tx.Recipient); contract != nil { - sm.ProcessContract(contract, tx, block) - } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block) - if err != nil { - ethutil.Config.Log.Infoln("[STATE]", err) + err = sm.Ethereum.TxPool().ProcessTransaction(tx, sm.procState, true) + if err == nil { + sm.ProcessContract(contract, tx, block) } + } else { + err = sm.Ethereum.TxPool().ProcessTransaction(tx, sm.procState, false) + } + + if err != nil { + ethutil.Config.Log.Infoln("[STATE]", err) } } } @@ -318,4 +323,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo txData: nil, }) closure.Call(vm, nil) + + // Update the account (refunds) + sm.procState.UpdateAccount(tx.Sender(), caller) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 4a4f2e809..66828adfb 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -90,7 +90,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { defer func() { if r := recover(); r != nil { log.Println(r) @@ -98,7 +98,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } }() // Get the sender - sender := block.state.GetAccount(tx.Sender()) + sender := state.GetAccount(tx.Sender()) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. @@ -116,13 +116,15 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } // Get the receiver - receiver := block.state.GetAccount(tx.Recipient) + receiver := state.GetAccount(tx.Recipient) 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 if toContract { + 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) @@ -130,10 +132,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error // Add the amount to receivers account which should conclude this transaction receiver.Amount.Add(receiver.Amount, tx.Value) - block.state.UpdateAccount(tx.Recipient, receiver) + state.UpdateAccount(tx.Recipient, receiver) } - block.state.UpdateAccount(tx.Sender(), sender) + state.UpdateAccount(tx.Sender(), sender) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) -- cgit v1.2.3 From 3558dd5ed4e14f124f04e2bf72fc3b989dff9e77 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 1 Apr 2014 14:42:48 +0200 Subject: Finalize blockchain reverting test --- ethchain/block_chain.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 8c03eec38..a8d9793d6 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -163,14 +163,20 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte } func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { lastBlock := bc.CurrentBlock - returnTo := bc.GetBlock(hash) - - // TODO: REFACTOR TO FUNCTION, Used multiple times - bc.CurrentBlock = returnTo - bc.LastBlockHash = returnTo.Hash() - info := bc.BlockInfo(returnTo) - bc.LastBlockNumber = info.Number - // END TODO + var returnTo *Block + // Reset to Genesis if that's all the origin there is. + if bytes.Compare(hash, bc.genesisBlock.Hash()) == 0 { + returnTo = bc.genesisBlock + bc.CurrentBlock = bc.genesisBlock + bc.LastBlockHash = bc.genesisBlock.Hash() + bc.LastBlockNumber = 1 + } else { + returnTo = bc.GetBlock(hash) + bc.CurrentBlock = returnTo + bc.LastBlockHash = returnTo.Hash() + info := bc.BlockInfo(returnTo) + bc.LastBlockNumber = info.Number + } bc.Ethereum.StateManager().PrepareDefault(returnTo) -- cgit v1.2.3 From 782910eaa76bb31be4c2bcd0f4505b8085acb57c Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 1 Apr 2014 15:54:29 +0200 Subject: Small tweaks --- ethchain/block_chain.go | 3 --- 1 file changed, 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index a8d9793d6..f621965ae 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -146,8 +146,6 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] At genesis block, breaking") break } - log.Printf("CHECKING OUR OWN BLOCKS: %x", block.Hash()) - log.Printf("%x", bc.GenesisBlock().Hash()) curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } @@ -309,7 +307,6 @@ func (bc *BlockChain) Add(block *Block) { bc.LastBlockHash = block.Hash() encodedBlock := block.RlpEncode() - log.Println(encodedBlock) ethutil.Config.Db.Put(block.Hash(), encodedBlock) ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) } -- cgit v1.2.3 From 90bb512f420f204f50ba451a4a25682ca8443746 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 5 Apr 2014 10:49:07 +0200 Subject: Update --- ethchain/vm_test.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 838f12f56..85ec4c693 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -83,18 +83,23 @@ func TestRun4(t *testing.T) { state := NewState(ethutil.NewTrie(db, "")) asm, err := mutan.Compile(strings.NewReader(` - a = 10 - b = 10 + int32 a = 10 + int32 b = 10 if a == b { - c = 10 + int32 c = 10 if c == 10 { - d = 1000 - e = 10 + int32 d = 1000 + int32 e = 10 } } store[0] = 20 store[a] = 20 + store[b] = this.caller() + + int8[10] ret + int8[10] arg + call(1234, 0, 100000000, arg, ret) `), false) if err != nil { fmt.Println(err) -- cgit v1.2.3 From c0a030ef0a3ce8342fda2a53cdafd50a271b4837 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 14:08:18 +0200 Subject: Added new insruction methods --- ethchain/closure.go | 5 +++++ ethchain/contract.go | 9 +++++++++ ethchain/vm.go | 26 +++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 2e809aa9d..e9cb2c8bc 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -17,6 +17,7 @@ type ClosureBody interface { ethutil.RlpEncodable GetMem(*big.Int) *ethutil.Value SetMem(*big.Int, *ethutil.Value) + GetInstr(*big.Int) *ethutil.Value } // Basic inline closure object which implement the 'closure' interface @@ -46,6 +47,10 @@ func (c *Closure) GetMem(x *big.Int) *ethutil.Value { return m } +func (c *Closure) GetInstr(x *big.Int) *ethutil.Value { + return c.object.GetInstr(x) +} + func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { c.object.SetMem(x, val) } diff --git a/ethchain/contract.go b/ethchain/contract.go index f7ae01753..f68dcf367 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -11,6 +11,7 @@ type Contract struct { //state *ethutil.Trie state *State address []byte + script []byte } func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { @@ -45,6 +46,14 @@ func (c *Contract) GetMem(num *big.Int) *ethutil.Value { return c.Addr(nb) } +func (c *Contract) GetInstr(pc *big.Int) *ethutil.Value { + if int64(len(c.script)-1) < pc.Int64() { + return ethutil.NewValue(0) + } + + return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) +} + func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) c.state.trie.Update(string(addr), string(val.Encode())) diff --git a/ethchain/vm.go b/ethchain/vm.go index 98aaa603a..b4b2177bf 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -72,7 +72,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { for { step++ // Get the memory location of pc - val := closure.GetMem(pc) + val := closure.GetInstr(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) if ethutil.Config.Debug { @@ -233,13 +233,37 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x10 range case oAND: + x, y := stack.Popn() + if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case oOR: + x, y := stack.Popn() + if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } case oXOR: + x, y := stack.Popn() + stack.Push(base.Xor(x, y)) case oBYTE: + val, th := stack.Popn() + if th.Cmp(big.NewInt(32)) < 0 { + stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64())) + } else { + stack.Push(ethutil.BigFalse) + } // 0x20 range case oSHA3: + size, offset := stack.Popn() + data := mem.Get(offset.Int64(), size.Int64()) + stack.Push(ethutil.BigD(data)) // 0x30 range case oADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) -- cgit v1.2.3 From 527a3bbc2aa9cfd26bd8419d33b50adef536067d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 14:53:20 +0200 Subject: Typo fix --- ethchain/transaction_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index a6265afd6..849909677 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -108,7 +108,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract } if sender.Nonce != tx.Nonce { - return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transactoin nonce is %d instead", sender.Nonce, tx.Nonce) + return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) } // Get the receiver -- cgit v1.2.3 From b66a99e32dd51ddd66a81141a9a37f93144935bd Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 9 Apr 2014 08:55:39 -0400 Subject: Added todo --- ethchain/block_chain.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index f621965ae..2a50ef687 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -169,6 +169,8 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { bc.LastBlockHash = bc.genesisBlock.Hash() bc.LastBlockNumber = 1 } else { + // TODO: Somehow this doesn't really give the right numbers, double check. + // TODO: Change logs into debug lines returnTo = bc.GetBlock(hash) bc.CurrentBlock = returnTo bc.LastBlockHash = returnTo.Hash() -- cgit v1.2.3 From 035f0ffb8ac95faa1742c0575cc9b5409ec54379 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 15:08:10 +0200 Subject: Reverted changes --- ethchain/state_manager.go | 4 ++-- ethchain/transaction_pool.go | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4b0ea2515..c33ba9272 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -114,12 +114,12 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // contract instead of moving funds between accounts. var err error if contract := sm.procState.GetContract(tx.Recipient); contract != nil { - err = sm.Ethereum.TxPool().ProcessTransaction(tx, sm.procState, true) + err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true) if err == nil { sm.ProcessContract(contract, tx, block) } } else { - err = sm.Ethereum.TxPool().ProcessTransaction(tx, sm.procState, false) + err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) } if err != nil { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 849909677..0bcfe6923 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -90,7 +90,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { defer func() { if r := recover(); r != nil { log.Println(r) @@ -98,7 +98,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract } }() // Get the sender - sender := state.GetAccount(tx.Sender()) + sender := block.state.GetAccount(tx.Sender()) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. @@ -112,7 +112,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract } // Get the receiver - receiver := state.GetAccount(tx.Recipient) + receiver := block.state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self @@ -128,10 +128,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract // Add the amount to receivers account which should conclude this transaction receiver.Amount.Add(receiver.Amount, tx.Value) - state.UpdateAccount(tx.Recipient, receiver) + block.state.UpdateAccount(tx.Recipient, receiver) } - state.UpdateAccount(tx.Sender(), sender) + block.state.UpdateAccount(tx.Sender(), sender) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) -- cgit v1.2.3 From 6d28bf534f0fabb5740ef035b829e5edc4dc3131 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 16:00:28 +0200 Subject: Added a length for copy --- ethchain/state_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c33ba9272..4c001a387 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -288,7 +288,7 @@ func (sm *StateManager) AccumelateRewards(block *Block) error { // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - var acc []byte + acc := make([]byte, len(block.Coinbase)) copy(acc, block.Coinbase) sm.procState.UpdateAccount(acc, addr) -- cgit v1.2.3 From 03e139d23b4350172b69d81c2c5690d0da282fb7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 16:04:36 +0200 Subject: Switched variable names --- ethchain/state_manager.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4c001a387..0f8ef19a7 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -284,13 +284,13 @@ func CalculateUncleReward(block *Block) *big.Int { func (sm *StateManager) AccumelateRewards(block *Block) error { // Get the coinbase rlp data - addr := sm.procState.GetAccount(block.Coinbase) + acc := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address - addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) + acc.AddFee(CalculateBlockReward(block, len(block.Uncles))) - acc := make([]byte, len(block.Coinbase)) - copy(acc, block.Coinbase) - sm.procState.UpdateAccount(acc, addr) + addr := make([]byte, len(block.Coinbase)) + copy(addr, block.Coinbase) + sm.procState.UpdateAccount(addr, acc) for _, uncle := range block.Uncles { uncleAddr := sm.procState.GetAccount(uncle.Coinbase) -- cgit v1.2.3 From e09f0a5f2c1e1b46226656dbac9a4ae10e0dcd14 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 12:27:54 -0400 Subject: Split code for contracts --- ethchain/closure.go | 22 ++++++++++++++-------- ethchain/contract.go | 22 ++++++++++++++-------- ethchain/state_manager.go | 2 +- ethchain/vm.go | 4 ++-- ethchain/vm_test.go | 3 ++- 5 files changed, 33 insertions(+), 20 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index e9cb2c8bc..d1fac0f43 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -12,18 +12,18 @@ type Callee interface { Address() []byte } -type ClosureBody interface { +type Reference interface { Callee ethutil.RlpEncodable GetMem(*big.Int) *ethutil.Value SetMem(*big.Int, *ethutil.Value) - GetInstr(*big.Int) *ethutil.Value } // Basic inline closure object which implement the 'closure' interface type Closure struct { callee Callee - object ClosureBody + object Reference + Script []byte State *State Gas *big.Int @@ -33,8 +33,8 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure { - return &Closure{callee, object, state, gas, val, nil} +func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, val *big.Int) *Closure { + return &Closure{callee, object, script, state, gas, val, nil} } // Retuns the x element in data slice @@ -47,8 +47,14 @@ func (c *Closure) GetMem(x *big.Int) *ethutil.Value { return m } -func (c *Closure) GetInstr(x *big.Int) *ethutil.Value { - return c.object.GetInstr(x) +func (c *Closure) Get(x *big.Int) *ethutil.Value { + return c.Gets(x, big.NewInt(1)) +} + +func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { + partial := c.Script[x.Int64() : x.Int64()+y.Int64()] + + return ethutil.NewValue(partial) } func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { @@ -86,7 +92,7 @@ func (c *Closure) ReturnGas(gas *big.Int, state *State) { c.Gas.Add(c.Gas, gas) } -func (c *Closure) Object() ClosureBody { +func (c *Closure) Object() Reference { return c.object } diff --git a/ethchain/contract.go b/ethchain/contract.go index f68dcf367..113d067a4 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -9,9 +9,10 @@ type Contract struct { Amount *big.Int Nonce uint64 //state *ethutil.Trie - state *State - address []byte - script []byte + state *State + address []byte + script []byte + initScript []byte } func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { @@ -88,12 +89,17 @@ func MakeContract(tx *Transaction, state *State) *Contract { value := tx.Value contract := NewContract(addr, value, []byte("")) state.trie.Update(string(addr), string(contract.RlpEncode())) - for i, val := range tx.Data { - if len(val) > 0 { - bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) - contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val))) + contract.script = tx.Data + contract.initScript = tx.Init + + /* + for i, val := range tx.Data { + if len(val) > 0 { + bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) + contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val))) + } } - } + */ state.trie.Update(string(addr), string(contract.RlpEncode())) return contract diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 95e46e41d..7a2a762b2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -311,7 +311,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo }() caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) + closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ origin: caller.Address(), blockNumber: block.BlockInfo().Number, diff --git a/ethchain/vm.go b/ethchain/vm.go index b4b2177bf..a6a02dc9f 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -72,7 +72,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { for { step++ // Get the memory location of pc - val := closure.GetInstr(pc) + val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) if ethutil.Config.Debug { @@ -357,7 +357,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) // Create a new callable closure - closure := NewClosure(closure, contract, vm.state, gas, value) + closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) // Executer the closure and get the return value (if any) ret := closure.Call(vm, args) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 85ec4c693..745005b09 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -112,7 +112,8 @@ func TestRun4(t *testing.T) { // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) - callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) + c := MakeContract(callerTx, state) + callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ origin: account.Address(), -- cgit v1.2.3 From 720521ed4a28c8a1b74bedd03e82bf4f887c9cb5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 12:28:16 -0400 Subject: Changed how txs define their data & added init field --- ethchain/transaction.go | 66 +++++++++++++++++--------------------------- ethchain/transaction_test.go | 53 ----------------------------------- 2 files changed, 25 insertions(+), 94 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 506e3c159..b359c9151 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -14,7 +14,8 @@ type Transaction struct { Value *big.Int Gas *big.Int Gasprice *big.Int - Data []string + Data []byte + Init []byte v byte r, s []byte @@ -22,11 +23,11 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { +func NewContractCreationTx(value, gasprice *big.Int, data []byte) *Transaction { return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true} } -func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { +func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} } @@ -45,19 +46,12 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := make([]interface{}, len(tx.Data)) - for i, val := range tx.Data { - data[i] = val + data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, string(tx.Data)} + if tx.contractCreation { + data = append(data, string(tx.Init)) } - preEnc := []interface{}{ - tx.Nonce, - tx.Recipient, - tx.Value, - data, - } - - return ethutil.Sha3Bin(ethutil.Encode(preEnc)) + return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } func (tx *Transaction) IsContract() bool { @@ -110,15 +104,17 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } +// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] +// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice} + data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, tx.Data} - if !tx.contractCreation { - data = append(data, tx.Recipient, tx.Gas) + if tx.contractCreation { + data = append(data, tx.Init) } - d := ethutil.NewSliceValue(tx.Data).Slice() + //d := ethutil.NewSliceValue(tx.Data).Slice() - return append(data, d, tx.v, tx.r, tx.s) + return append(data, tx.v, tx.r, tx.s) } func (tx *Transaction) RlpValue() *ethutil.Value { @@ -137,31 +133,19 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() tx.Gasprice = decoder.Get(2).BigInt() + tx.Gas = decoder.Get(3).BigInt() + tx.Recipient = decoder.Get(4).Bytes() + tx.Data = decoder.Get(5).Bytes() - // If the 4th item is a list(slice) this tx - // is a contract creation tx - if decoder.Get(3).IsList() { - d := decoder.Get(3) - tx.Data = make([]string, d.Len()) - for i := 0; i < d.Len(); i++ { - tx.Data[i] = d.Get(i).Str() - } - - tx.v = byte(decoder.Get(4).Uint()) - tx.r = decoder.Get(5).Bytes() - tx.s = decoder.Get(6).Bytes() - + // If the list is of length 10 it's a contract creation tx + if decoder.Len() == 10 { tx.contractCreation = true - } else { - tx.Recipient = decoder.Get(3).Bytes() - tx.Gas = decoder.Get(4).BigInt() - - d := decoder.Get(5) - tx.Data = make([]string, d.Len()) - for i := 0; i < d.Len(); i++ { - tx.Data[i] = d.Get(i).Str() - } + tx.Init = decoder.Get(6).Bytes() + tx.v = byte(decoder.Get(7).Uint()) + tx.r = decoder.Get(8).Bytes() + tx.s = decoder.Get(9).Bytes() + } else { tx.v = byte(decoder.Get(6).Uint()) tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() diff --git a/ethchain/transaction_test.go b/ethchain/transaction_test.go index a49768aea..3603fd8a7 100644 --- a/ethchain/transaction_test.go +++ b/ethchain/transaction_test.go @@ -1,54 +1 @@ package ethchain - -import ( - "encoding/hex" - "math/big" - "testing" -) - -func TestAddressRetrieval(t *testing.T) { - // TODO - // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f - key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4") - - tx := &Transaction{ - Nonce: 0, - Recipient: ZeroHash160, - Value: big.NewInt(0), - Data: nil, - } - //fmt.Printf("rlp %x\n", tx.RlpEncode()) - //fmt.Printf("sha rlp %x\n", tx.Hash()) - - tx.Sign(key) - - //fmt.Printf("hex tx key %x\n", tx.PublicKey()) - //fmt.Printf("seder %x\n", tx.Sender()) -} - -func TestAddressRetrieval2(t *testing.T) { - // TODO - // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f - key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4") - addr, _ := hex.DecodeString("944400f4b88ac9589a0f17ed4671da26bddb668b") - tx := &Transaction{ - Nonce: 0, - Recipient: addr, - Value: big.NewInt(1000), - Data: nil, - } - tx.Sign(key) - //data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7") - //tx := NewTransactionFromData(data) - /* - fmt.Println(tx.RlpValue()) - - fmt.Printf("rlp %x\n", tx.RlpEncode()) - fmt.Printf("sha rlp %x\n", tx.Hash()) - - //tx.Sign(key) - - fmt.Printf("hex tx key %x\n", tx.PublicKey()) - fmt.Printf("seder %x\n", tx.Sender()) - */ -} -- cgit v1.2.3 From 6a530ea3717e592407737c6cd2ebeba0200c9cd8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 14:40:12 -0400 Subject: Call fixed --- ethchain/closure.go | 4 ++++ ethchain/contract.go | 4 +++- ethchain/vm.go | 26 ++++++++++++++++---------- ethchain/vm_test.go | 23 ++++++++++++++++++++--- 4 files changed, 43 insertions(+), 14 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index d1fac0f43..8e57a0d03 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -52,6 +52,10 @@ func (c *Closure) Get(x *big.Int) *ethutil.Value { } func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { + if x.Int64() > int64(len(c.Script)) || y.Int64() > int64(len(c.Script)) { + return ethutil.NewValue(0) + } + partial := c.Script[x.Int64() : x.Int64()+y.Int64()] return ethutil.NewValue(partial) diff --git a/ethchain/contract.go b/ethchain/contract.go index 113d067a4..e99e413f7 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -70,7 +70,7 @@ func (c *Contract) Address() []byte { } func (c *Contract) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript}) } func (c *Contract) RlpDecode(data []byte) { @@ -79,6 +79,8 @@ func (c *Contract) RlpDecode(data []byte) { c.Amount = decoder.Get(0).BigInt() c.Nonce = decoder.Get(1).Uint() c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.script = decoder.Get(3).Bytes() + c.initScript = decoder.Get(4).Bytes() } func MakeContract(tx *Transaction, state *State) *Contract { diff --git a/ethchain/vm.go b/ethchain/vm.go index a6a02dc9f..f94425d2d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,7 +2,7 @@ package ethchain import ( _ "bytes" - "fmt" + _ "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" _ "math" @@ -301,9 +301,14 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x50 range case oPUSH: // Push PC+1 on to the stack pc.Add(pc, ethutil.Big1) + //val := closure.GetMem(pc).BigInt() + data := closure.Gets(pc, big.NewInt(32)) + val := ethutil.BigD(data.Bytes()) - val := closure.GetMem(pc).BigInt() + // Push value to stack stack.Push(val) + + pc.Add(pc, big.NewInt(31)) case oPOP: stack.Pop() case oDUP: @@ -343,17 +348,16 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { stack.Push(big.NewInt(int64(mem.Len()))) // 0x60 range case oCALL: - // Pop return size and offset - retSize, retOffset := stack.Popn() + // Closure addr + addr := stack.Pop() + // Pop gas and value of the stack. + gas, value := stack.Popn() // Pop input size and offset inSize, inOffset := stack.Popn() - fmt.Println(inSize, inOffset) + // Pop return size and offset + retSize, retOffset := stack.Popn() // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - // Pop gas and value of the stack. - gas, value := stack.Popn() - // Closure addr - addr := stack.Pop() // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) // Create a new callable closure @@ -385,7 +389,9 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { break out */ default: - ethutil.Config.Log.Debugln("Invalid opcode", op) + ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) + + return closure.Return(nil) } pc.Add(pc, ethutil.Big1) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 745005b09..65113ff57 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -83,6 +83,21 @@ func TestRun4(t *testing.T) { state := NewState(ethutil.NewTrie(db, "")) asm, err := mutan.Compile(strings.NewReader(` + int32 a = 10 + int32 b = 20 + if a > b { + int32 c = this.caller() + } + exit() + `), false) + script := ethutil.Assemble(asm...) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) + addr := tx.Hash()[12:] + contract := MakeContract(tx, state) + state.UpdateContract(contract) + fmt.Printf("%x\n", addr) + + asm, err = mutan.Compile(strings.NewReader(` int32 a = 10 int32 b = 10 if a == b { @@ -97,9 +112,9 @@ func TestRun4(t *testing.T) { store[a] = 20 store[b] = this.caller() - int8[10] ret - int8[10] arg - call(1234, 0, 100000000, arg, ret) + int8 ret = 0 + int8 arg = 10 + call(938726394128221156290138488023434115948430767407, 0, 100000000, arg, ret) `), false) if err != nil { fmt.Println(err) @@ -113,6 +128,8 @@ func TestRun4(t *testing.T) { // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) c := MakeContract(callerTx, state) + //fmt.Println(c.script[230:240]) + //fmt.Println(c.script) callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ -- cgit v1.2.3 From 969e748dce5562fc543990b6911d53ab699e393e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 15:30:14 -0400 Subject: Call fixed --- ethchain/vm_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 65113ff57..dc74422cc 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -119,7 +119,7 @@ func TestRun4(t *testing.T) { if err != nil { fmt.Println(err) } - //asm = append(asm, "LOG") + asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) @@ -128,8 +128,6 @@ func TestRun4(t *testing.T) { // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) c := MakeContract(callerTx, state) - //fmt.Println(c.script[230:240]) - //fmt.Println(c.script) callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ -- cgit v1.2.3 From 891f7259091cba0fe5e8c9370e7b0b1055b56683 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 18:14:19 -0400 Subject: Added better address format --- ethchain/stack.go | 1 + ethchain/vm.go | 11 ++++++++++- ethchain/vm_test.go | 5 +++-- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index e3fc4b684..0dadd15e5 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -55,6 +55,7 @@ const ( // 0x50 range - 'storage' and execution oPUSH = 0x50 + oPUSH20 = 0x80 oPOP = 0x51 oDUP = 0x52 oSWAP = 0x53 diff --git a/ethchain/vm.go b/ethchain/vm.go index f94425d2d..dd99ee790 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -301,7 +301,6 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x50 range case oPUSH: // Push PC+1 on to the stack pc.Add(pc, ethutil.Big1) - //val := closure.GetMem(pc).BigInt() data := closure.Gets(pc, big.NewInt(32)) val := ethutil.BigD(data.Bytes()) @@ -309,6 +308,16 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { stack.Push(val) pc.Add(pc, big.NewInt(31)) + case oPUSH20: + pc.Add(pc, ethutil.Big1) + data := closure.Gets(pc, big.NewInt(20)) + val := ethutil.BigD(data.Bytes()) + + // Push value to stack + stack.Push(val) + + pc.Add(pc, big.NewInt(19)) + case oPOP: stack.Pop() case oDUP: diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index dc74422cc..923d3526c 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -114,12 +114,13 @@ func TestRun4(t *testing.T) { int8 ret = 0 int8 arg = 10 - call(938726394128221156290138488023434115948430767407, 0, 100000000, arg, ret) + addr address = "a46df28529eb8aa8b8c025b0b413c5f4b688352f" + call(address, 0, 100000000, arg, ret) `), false) if err != nil { fmt.Println(err) } - asm = append(asm, "LOG") + //asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) -- cgit v1.2.3 From afc92fb7d799a4085d2256a7106ee9f7b9ea2f9e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 18:32:54 -0400 Subject: Added better address format --- ethchain/vm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 923d3526c..55fb71dbe 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -120,7 +120,7 @@ func TestRun4(t *testing.T) { if err != nil { fmt.Println(err) } - //asm = append(asm, "LOG") + asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) -- cgit v1.2.3 From 25dd46061fc3b732056ea87fe4a9696e160179cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 21:03:14 -0400 Subject: Added push20 --- ethchain/stack.go | 2 +- ethchain/vm_test.go | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index 0dadd15e5..d475f2f8e 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -251,7 +251,7 @@ func (m *Memory) Print() { if len(m.store) > 0 { addr := 0 for i := 0; i+32 <= len(m.store); i += 32 { - fmt.Printf("%03d %v\n", addr, m.store[i:i+32]) + fmt.Printf("%03d: % x\n", addr, m.store[i:i+32]) addr++ } } else { diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 55fb71dbe..4075dfbc6 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -98,24 +98,22 @@ func TestRun4(t *testing.T) { fmt.Printf("%x\n", addr) asm, err = mutan.Compile(strings.NewReader(` - int32 a = 10 - int32 b = 10 - if a == b { - int32 c = 10 - if c == 10 { - int32 d = 1000 - int32 e = 10 - } + // Check if there's any cash in the initial store + if store[1000] == 0 { + store[1000] = 10^20 } - store[0] = 20 - store[a] = 20 - store[b] = this.caller() + store[1001] = this.value() * 20 + store[this.origin()] = store[this.origin()] + 1000 + + if store[1001] > 20 { + store[1001] = 10^50 + } int8 ret = 0 int8 arg = 10 - addr address = "a46df28529eb8aa8b8c025b0b413c5f4b688352f" - call(address, 0, 100000000, arg, ret) + store[1002] = "a46df28529eb8aa8b8c025b0b413c5f4b688352f" + call(store[1002], 0, 100000000, arg, ret) `), false) if err != nil { fmt.Println(err) -- cgit v1.2.3 From ca747f268800590ee855b1ce593b61e95d073311 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 11 Apr 2014 08:28:30 -0400 Subject: Added the possibility for debug hooks during closure call --- ethchain/closure.go | 6 ++++-- ethchain/state_manager.go | 2 +- ethchain/vm.go | 45 +++++---------------------------------------- ethchain/vm_test.go | 2 +- 4 files changed, 11 insertions(+), 44 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 8e57a0d03..3d15f2a99 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -69,10 +69,12 @@ func (c *Closure) Address() []byte { return c.object.Address() } -func (c *Closure) Call(vm *Vm, args []byte) []byte { +type DebugHook func(op OpCode) + +func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { c.Args = args - return vm.RunClosure(c) + return vm.RunClosure(c, hook) } func (c *Closure) Return(ret []byte) []byte { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3043c3d15..111d2c019 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -327,7 +327,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo // XXX Tx data? Could be just an argument to the closure instead txData: nil, }) - closure.Call(vm, nil) + closure.Call(vm, nil, nil) // Update the account (refunds) sm.procState.UpdateAccount(tx.Sender(), caller) diff --git a/ethchain/vm.go b/ethchain/vm.go index dd99ee790..dce972cc7 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -48,7 +48,7 @@ func NewVm(state *State, vars RuntimeVars) *Vm { var Pow256 = ethutil.BigPow(2, 256) -func (vm *Vm) RunClosure(closure *Closure) []byte { +func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // If the amount of gas supplied is less equal to 0 if closure.Gas.Cmp(big.NewInt(0)) <= 0 { // TODO Do something @@ -372,7 +372,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // Create a new callable closure closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) // Executer the closure and get the return value (if any) - ret := closure.Call(vm, args) + ret := closure.Call(vm, args, hook) mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: @@ -404,44 +404,9 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } pc.Add(pc, ethutil.Big1) - } -} - -/* -func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { - ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) - j := int64(0) - dataItems := make([]string, int(length.Uint64())) - for i := from.Int64(); i < length.Int64(); i++ { - dataItems[j] = contract.GetMem(big.NewInt(j)).Str() - j++ - } - tx := NewTransaction(addr, value, dataItems) - if tx.IsContract() { - contract := MakeContract(tx, state) - state.UpdateContract(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 + if hook != nil { + hook(op) + } } - - return decoder.BigInt() } -*/ diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 4075dfbc6..5a1419c0f 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -139,5 +139,5 @@ func TestRun4(t *testing.T) { // XXX Tx data? Could be just an argument to the closure instead txData: nil, }) - callerClosure.Call(vm, nil) + callerClosure.Call(vm, nil, nil) } -- cgit v1.2.3 From 116516158da637cde50d27d600db6661732fc402 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 11 Apr 2014 13:29:57 -0400 Subject: Renamed --- ethchain/closure.go | 4 +- ethchain/contract.go | 8 ++++ ethchain/stack.go | 8 ++++ ethchain/state_manager.go | 14 +++---- ethchain/vm.go | 98 +++++++++++++++++++++++++++++++++++++---------- ethchain/vm_test.go | 29 ++++++++++---- 6 files changed, 124 insertions(+), 37 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 3d15f2a99..de2196499 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -52,7 +52,7 @@ func (c *Closure) Get(x *big.Int) *ethutil.Value { } func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { - if x.Int64() > int64(len(c.Script)) || y.Int64() > int64(len(c.Script)) { + if x.Int64() >= int64(len(c.Script)) || y.Int64() >= int64(len(c.Script)) { return ethutil.NewValue(0) } @@ -69,7 +69,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(op OpCode) +type DebugHook func(op OpCode, mem *Memory, stack *Stack) func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { c.Args = args diff --git a/ethchain/contract.go b/ethchain/contract.go index e99e413f7..af348667c 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -69,6 +69,14 @@ func (c *Contract) Address() []byte { return c.address } +func (c *Contract) Script() []byte { + return c.script +} + +func (c *Contract) Init() []byte { + return c.initScript +} + func (c *Contract) RlpEncode() []byte { return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript}) } diff --git a/ethchain/stack.go b/ethchain/stack.go index d475f2f8e..2aca0a350 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -173,6 +173,10 @@ func NewStack() *Stack { return &Stack{} } +func (st *Stack) Data() []*big.Int { + return st.data +} + func (st *Stack) Pop() *big.Int { str := st.data[len(st.data)-1] @@ -246,6 +250,10 @@ func (m *Memory) Len() int { return len(m.store) } +func (m *Memory) Data() []byte { + return m.store +} + func (m *Memory) Print() { fmt.Printf("### mem %d bytes ###\n", len(m.store)) if len(m.store) > 0 { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 111d2c019..549d59959 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -318,14 +318,14 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ - origin: caller.Address(), - blockNumber: block.BlockInfo().Number, - prevHash: block.PrevHash, - coinbase: block.Coinbase, - time: block.Time, - diff: block.Difficulty, + Origin: caller.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, // XXX Tx data? Could be just an argument to the closure instead - txData: nil, + TxData: nil, }) closure.Call(vm, nil, nil) diff --git a/ethchain/vm.go b/ethchain/vm.go index dce972cc7..fbe0d0439 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,7 +2,7 @@ package ethchain import ( _ "bytes" - _ "fmt" + "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" _ "math" @@ -33,13 +33,13 @@ type Vm struct { } type RuntimeVars struct { - origin []byte - blockNumber uint64 - prevHash []byte - coinbase []byte - time int64 - diff *big.Int - txData []string + Origin []byte + BlockNumber uint64 + PrevHash []byte + Coinbase []byte + Time int64 + Diff *big.Int + TxData []string } func NewVm(state *State, vars RuntimeVars) *Vm { @@ -65,9 +65,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // The base for all big integer arithmetic base := new(big.Int) - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("# op\n") - } + /* + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("# op\n") + } + */ for { step++ @@ -75,9 +77,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } + /* + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } + */ // TODO Get each instruction cost properly gas := new(big.Int) @@ -270,7 +274,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { case oBALANCE: stack.Push(closure.Value) case oORIGIN: - stack.Push(ethutil.BigD(vm.vars.origin)) + stack.Push(ethutil.BigD(vm.vars.Origin)) case oCALLER: stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: @@ -286,15 +290,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // 0x40 range case oPREVHASH: - stack.Push(ethutil.BigD(vm.vars.prevHash)) + stack.Push(ethutil.BigD(vm.vars.PrevHash)) case oCOINBASE: - stack.Push(ethutil.BigD(vm.vars.coinbase)) + stack.Push(ethutil.BigD(vm.vars.Coinbase)) case oTIMESTAMP: - stack.Push(big.NewInt(vm.vars.time)) + stack.Push(big.NewInt(vm.vars.Time)) case oNUMBER: - stack.Push(big.NewInt(int64(vm.vars.blockNumber))) + stack.Push(big.NewInt(int64(vm.vars.BlockNumber))) case oDIFFICULTY: - stack.Push(vm.vars.diff) + stack.Push(vm.vars.Diff) case oGASLIMIT: // TODO @@ -406,7 +410,59 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { pc.Add(pc, ethutil.Big1) if hook != nil { - hook(op) + hook(op, mem, stack) + } + } +} + +func Disassemble(script []byte) (asm []string) { + pc := new(big.Int) + for { + if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { + return + } + + // Get the memory location of pc + val := script[pc.Int64()] + // Get the opcode (it must be an opcode!) + op := OpCode(val) + + asm = append(asm, fmt.Sprintf("%v", op)) + + switch op { + case oPUSH: // Push PC+1 on to the stack + pc.Add(pc, ethutil.Big1) + data := script[pc.Int64() : pc.Int64()+32] + val := ethutil.BigD(data) + + var b []byte + if val.Int64() == 0 { + b = []byte{0} + } else { + b = val.Bytes() + } + + asm = append(asm, fmt.Sprintf("0x%x", b)) + + pc.Add(pc, big.NewInt(31)) + case oPUSH20: + pc.Add(pc, ethutil.Big1) + data := script[pc.Int64() : pc.Int64()+20] + val := ethutil.BigD(data) + var b []byte + if val.Int64() == 0 { + b = []byte{0} + } else { + b = val.Bytes() + } + + asm = append(asm, fmt.Sprintf("0x%x", b)) + + pc.Add(pc, big.NewInt(19)) } + + pc.Add(pc, ethutil.Big1) } + + return } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 5a1419c0f..a0add9532 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -130,14 +130,29 @@ func TestRun4(t *testing.T) { callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ - origin: account.Address(), - blockNumber: 1, - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), + Origin: account.Address(), + BlockNumber: 1, + PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + Time: 1, + Diff: big.NewInt(256), // XXX Tx data? Could be just an argument to the closure instead - txData: nil, + TxData: nil, }) callerClosure.Call(vm, nil, nil) } + +func TestRun5(t *testing.T) { + ethutil.ReadConfig("") + + asm, _ := mutan.Compile(strings.NewReader(` + int32 a = 10 + int32 b = 20 + if a > b { + int32 c = this.caller() + } + exit() + `), false) + script := ethutil.Assemble(asm...) + fmt.Println(Disassemble(script)) +} -- cgit v1.2.3 From 086acd122b59071255b0c1cfae569748b1d7427a Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 12 Apr 2014 00:13:42 -0400 Subject: Added pre processing of script data --- ethchain/closure.go | 2 +- ethchain/vm.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index de2196499..0fbe48f92 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -69,7 +69,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(op OpCode, mem *Memory, stack *Stack) +type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack) func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { c.Args = args diff --git a/ethchain/vm.go b/ethchain/vm.go index fbe0d0439..b88cd2861 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -312,6 +312,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(val) pc.Add(pc, big.NewInt(31)) + step++ case oPUSH20: pc.Add(pc, ethutil.Big1) data := closure.Gets(pc, big.NewInt(20)) @@ -321,7 +322,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(val) pc.Add(pc, big.NewInt(19)) - + step++ case oPOP: stack.Pop() case oDUP: @@ -410,7 +411,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { pc.Add(pc, ethutil.Big1) if hook != nil { - hook(op, mem, stack) + hook(step-1, op, mem, stack) } } } -- cgit v1.2.3 From ca13e3b1058f0d680b79dc1d9319d427a09493f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Apr 2014 16:16:38 -0400 Subject: Moved assembler stage processing to it's own file --- ethchain/asm.go | 126 ++++++++++++++++++++++++++++ ethchain/closure.go | 2 +- ethchain/stack.go | 151 +--------------------------------- ethchain/types.go | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ethchain/vm.go | 134 +++++++++++++++--------------- 5 files changed, 430 insertions(+), 213 deletions(-) create mode 100644 ethchain/asm.go create mode 100644 ethchain/types.go (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go new file mode 100644 index 000000000..5f901f8a2 --- /dev/null +++ b/ethchain/asm.go @@ -0,0 +1,126 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" + "regexp" +) + +func CompileInstr(s interface{}) ([]byte, error) { + switch s.(type) { + case string: + str := s.(string) + isOp := IsOpCode(str) + if isOp { + return []byte{OpCodes[str]}, nil + } + + num := new(big.Int) + _, success := num.SetString(str, 0) + // Assume regular bytes during compilation + if !success { + num.SetBytes([]byte(str)) + } else { + // tmp fix for 32 bytes + n := ethutil.BigToBytes(num, 256) + return n, nil + } + + return num.Bytes(), nil + case int: + num := ethutil.BigToBytes(big.NewInt(int64(s.(int))), 256) + return num, nil + case []byte: + return ethutil.BigD(s.([]byte)).Bytes(), nil + } + + return nil, nil +} + +// Script compilation functions +// Compiles strings to machine code +func Assemble(instructions ...interface{}) (script []byte) { + //script = make([]string, len(instructions)) + + for _, val := range instructions { + instr, _ := CompileInstr(val) + + //script[i] = string(instr) + script = append(script, instr...) + } + + return +} + +func Disassemble(script []byte) (asm []string) { + pc := new(big.Int) + for { + if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { + return + } + + // Get the memory location of pc + val := script[pc.Int64()] + // Get the opcode (it must be an opcode!) + op := OpCode(val) + + asm = append(asm, fmt.Sprintf("%v", op)) + + switch op { + case oPUSH: // Push PC+1 on to the stack + pc.Add(pc, ethutil.Big1) + data := script[pc.Int64() : pc.Int64()+32] + val := ethutil.BigD(data) + + var b []byte + if val.Int64() == 0 { + b = []byte{0} + } else { + b = val.Bytes() + } + + asm = append(asm, fmt.Sprintf("0x%x", b)) + + pc.Add(pc, big.NewInt(31)) + case oPUSH20: + pc.Add(pc, ethutil.Big1) + data := script[pc.Int64() : pc.Int64()+20] + val := ethutil.BigD(data) + var b []byte + if val.Int64() == 0 { + b = []byte{0} + } else { + b = val.Bytes() + } + + asm = append(asm, fmt.Sprintf("0x%x", b)) + + pc.Add(pc, big.NewInt(19)) + } + + pc.Add(pc, ethutil.Big1) + } + + return +} + +func PreProcess(data string) (mainInput, initInput string) { + reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" + mainReg := regexp.MustCompile("main" + reg) + initReg := regexp.MustCompile("init" + reg) + + main := mainReg.FindStringSubmatch(data) + if len(main) > 0 { + mainInput = main[1] + } else { + mainInput = data + } + + init := initReg.FindStringSubmatch(data) + if len(init) > 0 { + initInput = init[1] + } + + return +} diff --git a/ethchain/closure.go b/ethchain/closure.go index 0fbe48f92..0762e8f49 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -71,7 +71,7 @@ func (c *Closure) Address() []byte { type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack) -func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { +func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { c.Args = args return vm.RunClosure(c, hook) diff --git a/ethchain/stack.go b/ethchain/stack.go index 2aca0a350..288360062 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -6,153 +6,6 @@ import ( "math/big" ) -type OpCode int - -// Op codes -const ( - // 0x0 range - arithmetic ops - oSTOP = 0x00 - oADD = 0x01 - oMUL = 0x02 - oSUB = 0x03 - oDIV = 0x04 - oSDIV = 0x05 - oMOD = 0x06 - oSMOD = 0x07 - oEXP = 0x08 - oNEG = 0x09 - oLT = 0x0a - oGT = 0x0b - oEQ = 0x0c - oNOT = 0x0d - - // 0x10 range - bit ops - oAND = 0x10 - oOR = 0x11 - oXOR = 0x12 - oBYTE = 0x13 - - // 0x20 range - crypto - oSHA3 = 0x20 - - // 0x30 range - closure state - oADDRESS = 0x30 - oBALANCE = 0x31 - oORIGIN = 0x32 - oCALLER = 0x33 - oCALLVALUE = 0x34 - oCALLDATA = 0x35 - oCALLDATASIZE = 0x36 - oGASPRICE = 0x37 - - // 0x40 range - block operations - oPREVHASH = 0x40 - oCOINBASE = 0x41 - oTIMESTAMP = 0x42 - oNUMBER = 0x43 - oDIFFICULTY = 0x44 - oGASLIMIT = 0x45 - - // 0x50 range - 'storage' and execution - oPUSH = 0x50 - oPUSH20 = 0x80 - oPOP = 0x51 - oDUP = 0x52 - oSWAP = 0x53 - oMLOAD = 0x54 - oMSTORE = 0x55 - oMSTORE8 = 0x56 - oSLOAD = 0x57 - oSSTORE = 0x58 - oJUMP = 0x59 - oJUMPI = 0x5a - oPC = 0x5b - oMSIZE = 0x5c - - // 0x60 range - closures - oCREATE = 0x60 - oCALL = 0x61 - oRETURN = 0x62 - - // 0x70 range - other - oLOG = 0x70 // XXX Unofficial - oSUICIDE = 0x7f -) - -// Since the opcodes aren't all in order we can't use a regular slice -var opCodeToString = map[OpCode]string{ - // 0x0 range - arithmetic ops - oSTOP: "STOP", - oADD: "ADD", - oMUL: "MUL", - oSUB: "SUB", - oDIV: "DIV", - oSDIV: "SDIV", - oMOD: "MOD", - oSMOD: "SMOD", - oEXP: "EXP", - oNEG: "NEG", - oLT: "LT", - oGT: "GT", - oEQ: "EQ", - oNOT: "NOT", - - // 0x10 range - bit ops - oAND: "AND", - oOR: "OR", - oXOR: "XOR", - oBYTE: "BYTE", - - // 0x20 range - crypto - oSHA3: "SHA3", - - // 0x30 range - closure state - oADDRESS: "ADDRESS", - oBALANCE: "BALANCE", - oORIGIN: "ORIGIN", - oCALLER: "CALLER", - oCALLVALUE: "CALLVALUE", - oCALLDATA: "CALLDATA", - oCALLDATASIZE: "CALLDATASIZE", - oGASPRICE: "TXGASPRICE", - - // 0x40 range - block operations - oPREVHASH: "PREVHASH", - oCOINBASE: "COINBASE", - oTIMESTAMP: "TIMESTAMP", - oNUMBER: "NUMBER", - oDIFFICULTY: "DIFFICULTY", - oGASLIMIT: "GASLIMIT", - - // 0x50 range - 'storage' and execution - oPUSH: "PUSH", - oPOP: "POP", - oDUP: "DUP", - oSWAP: "SWAP", - oMLOAD: "MLOAD", - oMSTORE: "MSTORE", - oMSTORE8: "MSTORE8", - oSLOAD: "SLOAD", - oSSTORE: "SSTORE", - oJUMP: "JUMP", - oJUMPI: "JUMPI", - oPC: "PC", - oMSIZE: "MSIZE", - - // 0x60 range - closures - oCREATE: "CREATE", - oCALL: "CALL", - oRETURN: "RETURN", - - // 0x70 range - other - oLOG: "LOG", - oSUICIDE: "SUICIDE", -} - -func (o OpCode) String() string { - return opCodeToString[o] -} - type OpType int const ( @@ -177,6 +30,10 @@ func (st *Stack) Data() []*big.Int { return st.data } +func (st *Stack) Len() int { + return len(st.data) +} + func (st *Stack) Pop() *big.Int { str := st.data[len(st.data)-1] diff --git a/ethchain/types.go b/ethchain/types.go new file mode 100644 index 000000000..24aad82c3 --- /dev/null +++ b/ethchain/types.go @@ -0,0 +1,230 @@ +package ethchain + +type OpCode int + +// Op codes +const ( + // 0x0 range - arithmetic ops + oSTOP = 0x00 + oADD = 0x01 + oMUL = 0x02 + oSUB = 0x03 + oDIV = 0x04 + oSDIV = 0x05 + oMOD = 0x06 + oSMOD = 0x07 + oEXP = 0x08 + oNEG = 0x09 + oLT = 0x0a + oGT = 0x0b + oEQ = 0x0c + oNOT = 0x0d + + // 0x10 range - bit ops + oAND = 0x10 + oOR = 0x11 + oXOR = 0x12 + oBYTE = 0x13 + + // 0x20 range - crypto + oSHA3 = 0x20 + + // 0x30 range - closure state + oADDRESS = 0x30 + oBALANCE = 0x31 + oORIGIN = 0x32 + oCALLER = 0x33 + oCALLVALUE = 0x34 + oCALLDATA = 0x35 + oCALLDATASIZE = 0x36 + oGASPRICE = 0x37 + + // 0x40 range - block operations + oPREVHASH = 0x40 + oCOINBASE = 0x41 + oTIMESTAMP = 0x42 + oNUMBER = 0x43 + oDIFFICULTY = 0x44 + oGASLIMIT = 0x45 + + // 0x50 range - 'storage' and execution + oPUSH = 0x50 + oPUSH20 = 0x80 + oPOP = 0x51 + oDUP = 0x52 + oSWAP = 0x53 + oMLOAD = 0x54 + oMSTORE = 0x55 + oMSTORE8 = 0x56 + oSLOAD = 0x57 + oSSTORE = 0x58 + oJUMP = 0x59 + oJUMPI = 0x5a + oPC = 0x5b + oMSIZE = 0x5c + + // 0x60 range - closures + oCREATE = 0x60 + oCALL = 0x61 + oRETURN = 0x62 + + // 0x70 range - other + oLOG = 0x70 // XXX Unofficial + oSUICIDE = 0x7f +) + +// Since the opcodes aren't all in order we can't use a regular slice +var opCodeToString = map[OpCode]string{ + // 0x0 range - arithmetic ops + oSTOP: "STOP", + oADD: "ADD", + oMUL: "MUL", + oSUB: "SUB", + oDIV: "DIV", + oSDIV: "SDIV", + oMOD: "MOD", + oSMOD: "SMOD", + oEXP: "EXP", + oNEG: "NEG", + oLT: "LT", + oGT: "GT", + oEQ: "EQ", + oNOT: "NOT", + + // 0x10 range - bit ops + oAND: "AND", + oOR: "OR", + oXOR: "XOR", + oBYTE: "BYTE", + + // 0x20 range - crypto + oSHA3: "SHA3", + + // 0x30 range - closure state + oADDRESS: "ADDRESS", + oBALANCE: "BALANCE", + oORIGIN: "ORIGIN", + oCALLER: "CALLER", + oCALLVALUE: "CALLVALUE", + oCALLDATA: "CALLDATA", + oCALLDATASIZE: "CALLDATASIZE", + oGASPRICE: "TXGASPRICE", + + // 0x40 range - block operations + oPREVHASH: "PREVHASH", + oCOINBASE: "COINBASE", + oTIMESTAMP: "TIMESTAMP", + oNUMBER: "NUMBER", + oDIFFICULTY: "DIFFICULTY", + oGASLIMIT: "GASLIMIT", + + // 0x50 range - 'storage' and execution + oPUSH: "PUSH", + oPOP: "POP", + oDUP: "DUP", + oSWAP: "SWAP", + oMLOAD: "MLOAD", + oMSTORE: "MSTORE", + oMSTORE8: "MSTORE8", + oSLOAD: "SLOAD", + oSSTORE: "SSTORE", + oJUMP: "JUMP", + oJUMPI: "JUMPI", + oPC: "PC", + oMSIZE: "MSIZE", + + // 0x60 range - closures + oCREATE: "CREATE", + oCALL: "CALL", + oRETURN: "RETURN", + + // 0x70 range - other + oLOG: "LOG", + oSUICIDE: "SUICIDE", +} + +func (o OpCode) String() string { + return opCodeToString[o] +} + +// Op codes for assembling +var OpCodes = map[string]byte{ + // 0x0 range - arithmetic ops + "STOP": 0x00, + "ADD": 0x01, + "MUL": 0x02, + "SUB": 0x03, + "DIV": 0x04, + "SDIV": 0x05, + "MOD": 0x06, + "SMOD": 0x07, + "EXP": 0x08, + "NEG": 0x09, + "LT": 0x0a, + "GT": 0x0b, + "EQ": 0x0c, + "NOT": 0x0d, + + // 0x10 range - bit ops + "AND": 0x10, + "OR": 0x11, + "XOR": 0x12, + "BYTE": 0x13, + + // 0x20 range - crypto + "SHA3": 0x20, + + // 0x30 range - closure state + "ADDRESS": 0x30, + "BALANCE": 0x31, + "ORIGIN": 0x32, + "CALLER": 0x33, + "CALLVALUE": 0x34, + "CALLDATA": 0x35, + "CALLDATASIZE": 0x36, + "GASPRICE": 0x38, + + // 0x40 range - block operations + "PREVHASH": 0x40, + "COINBASE": 0x41, + "TIMESTAMP": 0x42, + "NUMBER": 0x43, + "DIFFICULTY": 0x44, + "GASLIMIT": 0x45, + + // 0x50 range - 'storage' and execution + "PUSH": 0x50, + + "PUSH20": 0x80, + + "POP": 0x51, + "DUP": 0x52, + "SWAP": 0x53, + "MLOAD": 0x54, + "MSTORE": 0x55, + "MSTORE8": 0x56, + "SLOAD": 0x57, + "SSTORE": 0x58, + "JUMP": 0x59, + "JUMPI": 0x5a, + "PC": 0x5b, + "MSIZE": 0x5c, + + // 0x60 range - closures + "CREATE": 0x60, + "CALL": 0x61, + "RETURN": 0x62, + + // 0x70 range - other + "LOG": 0x70, + "SUICIDE": 0x7f, +} + +func IsOpCode(s string) bool { + for key, _ := range OpCodes { + if key == s { + return true + } + } + return false +} diff --git a/ethchain/vm.go b/ethchain/vm.go index b88cd2861..33d667457 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -48,7 +48,19 @@ func NewVm(state *State, vars RuntimeVars) *Vm { var Pow256 = ethutil.BigPow(2, 256) -func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { +var isRequireError = false + +func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err error) { + // Recover from any require exception + defer func() { + if r := recover(); r != nil && isRequireError { + fmt.Println(r) + + ret = closure.Return(nil) + err = fmt.Errorf("%v", r) + } + }() + // If the amount of gas supplied is less equal to 0 if closure.Gas.Cmp(big.NewInt(0)) <= 0 { // TODO Do something @@ -58,6 +70,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { mem := &Memory{} // New stack (should this be shared?) stack := NewStack() + require := func(m int) { + if stack.Len()-1 > m { + isRequireError = true + panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) + } + } + // Instruction pointer pc := big.NewInt(0) // Current step count @@ -121,7 +140,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { if closure.Gas.Cmp(gas) < 0 { ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) - return closure.Return(nil) + return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } switch op { @@ -129,10 +148,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Print() mem.Print() case oSTOP: // Stop the closure - return closure.Return(nil) + return closure.Return(nil), nil - // 0x20 range + // 0x20 range case oADD: + require(2) x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) @@ -140,6 +160,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oSUB: + require(2) x, y := stack.Popn() // (x - y) % 2 ** 256 base.Sub(x, y) @@ -147,6 +168,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oMUL: + require(2) x, y := stack.Popn() // (x * y) % 2 ** 256 base.Mul(x, y) @@ -154,12 +176,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oDIV: + require(2) x, y := stack.Popn() // floor(x / y) base.Div(x, y) // Pop result back on the stack stack.Push(base) case oSDIV: + require(2) x, y := stack.Popn() // n > 2**255 if x.Cmp(Pow256) > 0 { @@ -176,10 +200,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Push result on to the stack stack.Push(z) case oMOD: + require(2) x, y := stack.Popn() base.Mod(x, y) stack.Push(base) case oSMOD: + require(2) x, y := stack.Popn() // n > 2**255 if x.Cmp(Pow256) > 0 { @@ -196,14 +222,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Push result on to the stack stack.Push(z) case oEXP: + require(2) x, y := stack.Popn() base.Exp(x, y, Pow256) stack.Push(base) case oNEG: + require(1) base.Sub(Pow256, stack.Pop()) stack.Push(base) case oLT: + require(2) x, y := stack.Popn() // x < y if x.Cmp(y) < 0 { @@ -212,6 +241,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oGT: + require(2) x, y := stack.Popn() // x > y if x.Cmp(y) > 0 { @@ -220,6 +250,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oEQ: + require(2) x, y := stack.Popn() // x == y if x.Cmp(y) == 0 { @@ -228,6 +259,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oNOT: + require(1) x := stack.Pop() if x.Cmp(ethutil.BigFalse) == 0 { stack.Push(ethutil.BigTrue) @@ -235,8 +267,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } - // 0x10 range + // 0x10 range case oAND: + require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { stack.Push(ethutil.BigTrue) @@ -245,6 +278,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { } case oOR: + require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { stack.Push(ethutil.BigTrue) @@ -252,9 +286,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oXOR: + require(2) x, y := stack.Popn() stack.Push(base.Xor(x, y)) case oBYTE: + require(2) val, th := stack.Popn() if th.Cmp(big.NewInt(32)) < 0 { stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64())) @@ -262,13 +298,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } - // 0x20 range + // 0x20 range case oSHA3: + require(2) size, offset := stack.Popn() data := mem.Get(offset.Int64(), size.Int64()) stack.Push(ethutil.BigD(data)) - // 0x30 range + // 0x30 range case oADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) case oBALANCE: @@ -281,6 +318,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // FIXME: Original value of the call, not the current value stack.Push(closure.Value) case oCALLDATA: + require(1) offset := stack.Pop() mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) case oCALLDATASIZE: @@ -288,7 +326,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { case oGASPRICE: // TODO - // 0x40 range + // 0x40 range case oPREVHASH: stack.Push(ethutil.BigD(vm.vars.PrevHash)) case oCOINBASE: @@ -300,7 +338,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { case oDIFFICULTY: stack.Push(vm.vars.Diff) case oGASLIMIT: - // TODO + // TODO // 0x50 range case oPUSH: // Push PC+1 on to the stack @@ -324,34 +362,44 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { pc.Add(pc, big.NewInt(19)) step++ case oPOP: + require(1) stack.Pop() case oDUP: + require(1) stack.Push(stack.Peek()) case oSWAP: + require(2) x, y := stack.Popn() stack.Push(y) stack.Push(x) case oMLOAD: + require(1) offset := stack.Pop() stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) case oMSTORE: // Store the value at stack top-1 in to memory at location stack top + require(2) // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oMSTORE8: + require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) case oSLOAD: + require(1) loc := stack.Pop() val := closure.GetMem(loc) stack.Push(val.BigInt()) case oSSTORE: + require(2) val, loc := stack.Popn() closure.SetMem(loc, ethutil.NewValue(val)) case oJUMP: + require(1) pc = stack.Pop() case oJUMPI: + require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos @@ -360,8 +408,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(pc) case oMSIZE: stack.Push(big.NewInt(int64(mem.Len()))) - // 0x60 range + // 0x60 range + case oCREATE: case oCALL: + require(8) // Closure addr addr := stack.Pop() // Pop gas and value of the stack. @@ -377,14 +427,20 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Create a new callable closure closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) // Executer the closure and get the return value (if any) - ret := closure.Call(vm, args, hook) + ret, err := closure.Call(vm, args, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) + } mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: + require(2) size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) - return closure.Return(ret) + return closure.Return(ret), nil case oSUICIDE: /* recAddr := stack.Pop().Bytes() @@ -405,7 +461,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) - return closure.Return(nil) + return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } pc.Add(pc, ethutil.Big1) @@ -415,55 +471,3 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { } } } - -func Disassemble(script []byte) (asm []string) { - pc := new(big.Int) - for { - if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { - return - } - - // Get the memory location of pc - val := script[pc.Int64()] - // Get the opcode (it must be an opcode!) - op := OpCode(val) - - asm = append(asm, fmt.Sprintf("%v", op)) - - switch op { - case oPUSH: // Push PC+1 on to the stack - pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+32] - val := ethutil.BigD(data) - - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() - } - - asm = append(asm, fmt.Sprintf("0x%x", b)) - - pc.Add(pc, big.NewInt(31)) - case oPUSH20: - pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+20] - val := ethutil.BigD(data) - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() - } - - asm = append(asm, fmt.Sprintf("0x%x", b)) - - pc.Add(pc, big.NewInt(19)) - } - - pc.Add(pc, ethutil.Big1) - } - - return -} -- cgit v1.2.3 From 9c6aca78933c14ca107da30c4690808950718368 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 16 Apr 2014 04:06:51 +0200 Subject: Merged accounts and contracts in to StateObject * Account removed * Contract removed * Address state changed to CachedStateObject * Added StateObject --- ethchain/address.go | 76 -------------------- ethchain/address_test.go | 8 --- ethchain/block.go | 7 +- ethchain/block_chain.go | 6 +- ethchain/contract.go | 119 ------------------------------- ethchain/keypair.go | 4 +- ethchain/state.go | 65 +++++------------ ethchain/state_manager.go | 54 ++++++--------- ethchain/state_object.go | 162 +++++++++++++++++++++++++++++++++++++++++++ ethchain/transaction.go | 4 +- ethchain/transaction_pool.go | 14 ++-- 11 files changed, 219 insertions(+), 300 deletions(-) delete mode 100644 ethchain/address.go delete mode 100644 ethchain/address_test.go delete mode 100644 ethchain/contract.go create mode 100644 ethchain/state_object.go (limited to 'ethchain') diff --git a/ethchain/address.go b/ethchain/address.go deleted file mode 100644 index 0b3ef7c05..000000000 --- a/ethchain/address.go +++ /dev/null @@ -1,76 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/eth-go/ethutil" - "math/big" -) - -type Account struct { - address []byte - Amount *big.Int - Nonce uint64 -} - -func NewAccount(address []byte, amount *big.Int) *Account { - return &Account{address, amount, 0} -} - -func NewAccountFromData(address, data []byte) *Account { - account := &Account{address: address} - account.RlpDecode(data) - - return account -} - -func (a *Account) AddFee(fee *big.Int) { - a.AddFunds(fee) -} - -func (a *Account) AddFunds(funds *big.Int) { - a.Amount.Add(a.Amount, funds) -} - -func (a *Account) Address() []byte { - return a.address -} - -// Implements Callee -func (a *Account) ReturnGas(value *big.Int, state *State) { - // Return the value back to the sender - a.AddFunds(value) - state.UpdateAccount(a.address, a) -} - -func (a *Account) RlpEncode() []byte { - return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) -} - -func (a *Account) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - a.Amount = decoder.Get(0).BigInt() - a.Nonce = decoder.Get(1).Uint() -} - -type AddrStateStore struct { - states map[string]*AccountState -} - -func NewAddrStateStore() *AddrStateStore { - return &AddrStateStore{states: make(map[string]*AccountState)} -} - -func (s *AddrStateStore) Add(addr []byte, account *Account) *AccountState { - state := &AccountState{Nonce: account.Nonce, Account: account} - s.states[string(addr)] = state - return state -} - -func (s *AddrStateStore) Get(addr []byte) *AccountState { - return s.states[string(addr)] -} - -type AccountState struct { - Nonce uint64 - Account *Account -} diff --git a/ethchain/address_test.go b/ethchain/address_test.go deleted file mode 100644 index 161e1b251..000000000 --- a/ethchain/address_test.go +++ /dev/null @@ -1,8 +0,0 @@ -package ethchain - -import ( - "testing" -) - -func TestAddressState(t *testing.T) { -} diff --git a/ethchain/block.go b/ethchain/block.go index 732739c1b..8c93947fb 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -142,12 +142,13 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { data := block.state.trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) - ether := NewAccountFromData(block.Coinbase, []byte(data)) + account := NewStateObjectFromBytes(block.Coinbase, []byte(data)) base = new(big.Int) - ether.Amount = base.Add(ether.Amount, fee) + account.Amount = base.Add(account.Amount, fee) - block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) + //block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) + block.state.UpdateStateObject(account) return true } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2a50ef687..d65c38fe4 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -262,9 +262,9 @@ func AddTestNetFunds(block *Block) { } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) - addr := block.state.GetAccount(codedAddr) - addr.Amount = ethutil.BigPow(2, 200) - block.state.UpdateAccount(codedAddr, addr) + account := block.state.GetAccount(codedAddr) + account.Amount = ethutil.BigPow(2, 200) + block.state.UpdateStateObject(account) } } diff --git a/ethchain/contract.go b/ethchain/contract.go deleted file mode 100644 index af348667c..000000000 --- a/ethchain/contract.go +++ /dev/null @@ -1,119 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/eth-go/ethutil" - "math/big" -) - -type Contract struct { - Amount *big.Int - Nonce uint64 - //state *ethutil.Trie - state *State - address []byte - script []byte - initScript []byte -} - -func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { - contract := &Contract{address: address, Amount: Amount, Nonce: 0} - contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) - - return contract -} - -func NewContractFromBytes(address, data []byte) *Contract { - contract := &Contract{address: address} - contract.RlpDecode(data) - - return contract -} - -func (c *Contract) Addr(addr []byte) *ethutil.Value { - return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) -} - -func (c *Contract) SetAddr(addr []byte, value interface{}) { - c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) -} - -func (c *Contract) State() *State { - return c.state -} - -func (c *Contract) GetMem(num *big.Int) *ethutil.Value { - nb := ethutil.BigToBytes(num, 256) - - return c.Addr(nb) -} - -func (c *Contract) GetInstr(pc *big.Int) *ethutil.Value { - if int64(len(c.script)-1) < pc.Int64() { - return ethutil.NewValue(0) - } - - return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) -} - -func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) { - addr := ethutil.BigToBytes(num, 256) - c.state.trie.Update(string(addr), string(val.Encode())) -} - -// Return the gas back to the origin. Used by the Virtual machine or Closures -func (c *Contract) ReturnGas(val *big.Int, state *State) { - c.Amount.Add(c.Amount, val) -} - -func (c *Contract) Address() []byte { - return c.address -} - -func (c *Contract) Script() []byte { - return c.script -} - -func (c *Contract) Init() []byte { - return c.initScript -} - -func (c *Contract) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript}) -} - -func (c *Contract) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - c.Amount = decoder.Get(0).BigInt() - c.Nonce = decoder.Get(1).Uint() - c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) - c.script = decoder.Get(3).Bytes() - c.initScript = decoder.Get(4).Bytes() -} - -func MakeContract(tx *Transaction, state *State) *Contract { - // Create contract if there's no recipient - if tx.IsContract() { - addr := tx.Hash()[12:] - - value := tx.Value - contract := NewContract(addr, value, []byte("")) - state.trie.Update(string(addr), string(contract.RlpEncode())) - contract.script = tx.Data - contract.initScript = tx.Init - - /* - for i, val := range tx.Data { - if len(val) > 0 { - bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) - contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val))) - } - } - */ - state.trie.Update(string(addr), string(contract.RlpEncode())) - - return contract - } - - return nil -} diff --git a/ethchain/keypair.go b/ethchain/keypair.go index 9daaedbee..a5af791d0 100644 --- a/ethchain/keypair.go +++ b/ethchain/keypair.go @@ -10,7 +10,7 @@ type KeyPair struct { PublicKey []byte // The associated account - account *Account + account *StateObject state *State } @@ -24,7 +24,7 @@ func (k *KeyPair) Address() []byte { return ethutil.Sha3Bin(k.PublicKey[1:])[12:] } -func (k *KeyPair) Account() *Account { +func (k *KeyPair) Account() *StateObject { if k.account == nil { k.account = k.state.GetAccount(k.Address()) } diff --git a/ethchain/state.go b/ethchain/state.go index 1860647f2..655848932 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -47,23 +47,14 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } -func (s *State) GetContract(addr []byte) *Contract { +func (s *State) GetContract(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { return nil } - // Whet get contract is called the retrieved value might - // be an account. The StateManager uses this to check - // to see if the address a tx was sent to is a contract - // or an account - value := ethutil.NewValueFromBytes([]byte(data)) - if value.Len() == 2 { - return nil - } - // build contract - contract := NewContractFromBytes(addr, []byte(data)) + contract := NewStateObjectFromBytes(addr, []byte(data)) // Check if there's a cached state for this contract cachedState := s.states[string(addr)] @@ -77,28 +68,17 @@ func (s *State) GetContract(addr []byte) *Contract { return contract } -func (s *State) UpdateContract(contract *Contract) { - addr := contract.Address() - - s.states[string(addr)] = contract.state - s.trie.Update(string(addr), string(contract.RlpEncode())) -} - -func (s *State) GetAccount(addr []byte) (account *Account) { +func (s *State) GetAccount(addr []byte) (account *StateObject) { data := s.trie.Get(string(addr)) if data == "" { account = NewAccount(addr, big.NewInt(0)) } else { - account = NewAccountFromData(addr, []byte(data)) + account = NewStateObjectFromBytes(addr, []byte(data)) } return } -func (s *State) UpdateAccount(addr []byte, account *Account) { - s.trie.Update(string(addr), string(account.RlpEncode())) -} - func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } @@ -119,7 +99,7 @@ const ( // Returns the object stored at key and the type stored at key // Returns nil if nothing is stored -func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { +func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { // Fetch data from the trie data := s.trie.Get(string(key)) // Returns the nil type, indicating nothing could be retrieved. @@ -145,34 +125,21 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { return val, typ } -func (s *State) Put(key, object []byte) { - s.trie.Update(string(key), string(object)) -} +// Updates any given state object +func (s *State) UpdateStateObject(object *StateObject) { + addr := object.Address() -func (s *State) Root() interface{} { - return s.trie.Root -} - -// Script compilation functions -// Compiles strings to machine code -func Compile(code []string) (script []string) { - script = make([]string, len(code)) - for i, val := range code { - instr, _ := ethutil.CompileInstr(val) - - script[i] = string(instr) + if object.state != nil { + s.states[string(addr)] = object.state } - return + s.trie.Update(string(addr), string(object.RlpEncode())) } -func CompileToValues(code []string) (script []*ethutil.Value) { - script = make([]*ethutil.Value, len(code)) - for i, val := range code { - instr, _ := ethutil.CompileInstr(val) - - script[i] = ethutil.NewValue(instr) - } +func (s *State) Put(key, object []byte) { + s.trie.Update(string(key), string(object)) +} - return +func (s *State) Root() interface{} { + return s.trie.Root } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 549d59959..5e30d7280 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -30,7 +30,7 @@ type StateManager struct { bc *BlockChain // States for addresses. You can watch any address // at any given time - addrStateStore *AddrStateStore + stateObjectCache *StateObjectCache // Stack for processing contracts stack *Stack @@ -54,12 +54,12 @@ type StateManager struct { func NewStateManager(ethereum EthManager) *StateManager { sm := &StateManager{ - stack: NewStack(), - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Ethereum: ethereum, - addrStateStore: NewAddrStateStore(), - bc: ethereum.BlockChain(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Ethereum: ethereum, + stateObjectCache: NewStateObjectCache(), + bc: ethereum.BlockChain(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm @@ -70,18 +70,18 @@ func (sm *StateManager) ProcState() *State { } // Watches any given address and puts it in the address state store -func (sm *StateManager) WatchAddr(addr []byte) *AccountState { +func (sm *StateManager) WatchAddr(addr []byte) *CachedStateObject { //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) account := sm.procState.GetAccount(addr) - return sm.addrStateStore.Add(addr, account) + return sm.stateObjectCache.Add(addr, account) } -func (sm *StateManager) GetAddrState(addr []byte) *AccountState { - account := sm.addrStateStore.Get(addr) +func (sm *StateManager) GetAddrState(addr []byte) *CachedStateObject { + account := sm.stateObjectCache.Get(addr) if account == nil { a := sm.procState.GetAccount(addr) - account = &AccountState{Nonce: a.Nonce, Account: a} + account = &CachedStateObject{Nonce: a.Nonce, Object: a} } return account @@ -116,7 +116,7 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { if contract := sm.procState.GetContract(tx.Recipient); contract != nil { err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true) if err == nil { - sm.ProcessContract(contract, tx, block) + sm.EvalScript(contract.Script(), contract, tx, block) } } else { err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) @@ -180,7 +180,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { return err } - // if !sm.compState.Cmp(sm.procState) if !sm.compState.Cmp(sm.procState) { return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) } @@ -190,9 +189,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Sync the current block's state to the database and cancelling out the deferred Undo sm.procState.Sync() - // Broadcast the valid block back to the wire - //sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) - // Add the block to the chain sm.bc.Add(block) @@ -282,22 +278,20 @@ func CalculateUncleReward(block *Block) *big.Int { } func (sm *StateManager) AccumelateRewards(block *Block) error { - - // Get the coinbase rlp data - acc := sm.procState.GetAccount(block.Coinbase) + // Get the account associated with the coinbase + account := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address - acc.AddFee(CalculateBlockReward(block, len(block.Uncles))) + account.AddAmount(CalculateBlockReward(block, len(block.Uncles))) addr := make([]byte, len(block.Coinbase)) copy(addr, block.Coinbase) - sm.procState.UpdateAccount(addr, acc) + sm.procState.UpdateStateObject(account) for _, uncle := range block.Uncles { - uncleAddr := sm.procState.GetAccount(uncle.Coinbase) - uncleAddr.AddFee(CalculateUncleReward(uncle)) + uncleAccount := sm.procState.GetAccount(uncle.Coinbase) + uncleAccount.AddAmount(CalculateUncleReward(uncle)) - //processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) - sm.procState.UpdateAccount(uncle.Coinbase, uncleAddr) + sm.procState.UpdateStateObject(uncleAccount) } return nil @@ -307,7 +301,7 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, block *Block) { +func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { // Recovering function in case the VM had any errors defer func() { if r := recover(); r != nil { @@ -316,7 +310,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo }() caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value) + closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ Origin: caller.Address(), BlockNumber: block.BlockInfo().Number, @@ -324,11 +318,9 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, - // XXX Tx data? Could be just an argument to the closure instead - TxData: nil, }) closure.Call(vm, nil, nil) // Update the account (refunds) - sm.procState.UpdateAccount(tx.Sender(), caller) + sm.procState.UpdateStateObject(caller) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go new file mode 100644 index 000000000..8b4de0c4f --- /dev/null +++ b/ethchain/state_object.go @@ -0,0 +1,162 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type StateObject struct { + // Address of the object + address []byte + // Shared attributes + Amount *big.Int + Nonce uint64 + // Contract related attributes + state *State + script []byte + initScript []byte +} + +func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { + contract := &StateObject{address: address, Amount: Amount, Nonce: 0} + contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) + + return contract +} + +// Returns a newly created account +func NewAccount(address []byte, amount *big.Int) *StateObject { + account := &StateObject{address: address, Amount: amount, Nonce: 0} + + return account +} + +func NewStateObjectFromBytes(address, data []byte) *StateObject { + object := &StateObject{address: address} + object.RlpDecode(data) + + return object +} + +func (c *StateObject) Addr(addr []byte) *ethutil.Value { + return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) +} + +func (c *StateObject) SetAddr(addr []byte, value interface{}) { + c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) +} + +func (c *StateObject) State() *State { + return c.state +} + +func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { + nb := ethutil.BigToBytes(num, 256) + + return c.Addr(nb) +} + +func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { + if int64(len(c.script)-1) < pc.Int64() { + return ethutil.NewValue(0) + } + + return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) +} + +func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { + addr := ethutil.BigToBytes(num, 256) + c.state.trie.Update(string(addr), string(val.Encode())) +} + +// Return the gas back to the origin. Used by the Virtual machine or Closures +func (c *StateObject) ReturnGas(val *big.Int, state *State) { + c.AddAmount(val) +} + +func (c *StateObject) AddAmount(amount *big.Int) { + c.Amount.Add(c.Amount, amount) +} + +func (c *StateObject) SubAmount(amount *big.Int) { + c.Amount.Sub(c.Amount, amount) +} + +func (c *StateObject) Address() []byte { + return c.address +} + +func (c *StateObject) Script() []byte { + return c.script +} + +func (c *StateObject) Init() []byte { + return c.initScript +} + +func (c *StateObject) RlpEncode() []byte { + var root interface{} + if c.state != nil { + root = c.state.trie.Root + } else { + root = nil + } + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, c.script}) +} + +func (c *StateObject) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + c.Amount = decoder.Get(0).BigInt() + c.Nonce = decoder.Get(1).Uint() + c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.script = decoder.Get(3).Bytes() +} + +func MakeContract(tx *Transaction, state *State) *StateObject { + // Create contract if there's no recipient + if tx.IsContract() { + // FIXME + addr := tx.Hash()[12:] + + value := tx.Value + contract := NewContract(addr, value, []byte("")) + state.UpdateStateObject(contract) + + contract.script = tx.Data + contract.initScript = tx.Init + + state.UpdateStateObject(contract) + + return contract + } + + return nil +} + +// The cached state and state object cache are helpers which will give you somewhat +// control over the nonce. When creating new transactions you're interested in the 'next' +// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions. +type StateObjectCache struct { + cachedObjects map[string]*CachedStateObject +} + +func NewStateObjectCache() *StateObjectCache { + return &StateObjectCache{cachedObjects: make(map[string]*CachedStateObject)} +} + +func (s *StateObjectCache) Add(addr []byte, object *StateObject) *CachedStateObject { + state := &CachedStateObject{Nonce: object.Nonce, Object: object} + s.cachedObjects[string(addr)] = state + + return state +} + +func (s *StateObjectCache) Get(addr []byte) *CachedStateObject { + return s.cachedObjects[string(addr)] +} + +type CachedStateObject struct { + Nonce uint64 + Object *StateObject +} diff --git a/ethchain/transaction.go b/ethchain/transaction.go index b359c9151..78044e840 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -23,8 +23,8 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gasprice *big.Int, data []byte) *Transaction { - return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true} +func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { + return &Transaction{Value: value, Gasprice: gasprice, Data: script, Init: init, contractCreation: true} } func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 0bcfe6923..5cdda17e2 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -118,20 +118,20 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // 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)) + sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) } else if toContract { - sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat)) + sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) } else { // Subtract the amount from the senders account - sender.Amount.Sub(sender.Amount, totAmount) + sender.SubAmount(totAmount) // Add the amount to receivers account which should conclude this transaction - receiver.Amount.Add(receiver.Amount, tx.Value) + receiver.AddAmount(tx.Value) - block.state.UpdateAccount(tx.Recipient, receiver) + block.state.UpdateStateObject(receiver) } - block.state.UpdateAccount(tx.Sender(), sender) + block.state.UpdateStateObject(sender) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) @@ -151,7 +151,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Get the sender accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) - sender := accountState.Account + sender := accountState.Object totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) // Make sure there's enough in the sender's account. Having insufficient -- cgit v1.2.3 From c5729d7ecc564f8eff6df565173a4f5cc6c43cb0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 16 Apr 2014 04:07:52 +0200 Subject: comments --- ethchain/asm.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 5f901f8a2..a6c85cb60 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -106,6 +106,7 @@ func Disassemble(script []byte) (asm []string) { } func PreProcess(data string) (mainInput, initInput string) { + // Regexp for parsing anything between brackets reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" mainReg := regexp.MustCompile("main" + reg) initReg := regexp.MustCompile("init" + reg) -- cgit v1.2.3 From a96c8c8af969665cc0c357eef81d43b5b7285dfe Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Apr 2014 13:41:07 +0200 Subject: Added proper gas handling --- ethchain/closure.go | 5 +++-- ethchain/state_manager.go | 3 ++- ethchain/transaction.go | 12 ++++++------ ethchain/vm.go | 9 +++++---- ethchain/vm_test.go | 17 ++++++++++------- 5 files changed, 26 insertions(+), 20 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 0762e8f49..5c508179e 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -27,14 +27,15 @@ type Closure struct { State *State Gas *big.Int + Price *big.Int Value *big.Int Args []byte } // Create a new closure for the given data items -func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, val *big.Int) *Closure { - return &Closure{callee, object, script, state, gas, val, nil} +func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure { + return &Closure{callee, object, script, state, gas, price, val, nil} } // Retuns the x element in data slice diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 5e30d7280..75a78e9f3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -310,7 +310,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans }() caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.Value) + closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ Origin: caller.Address(), BlockNumber: block.BlockInfo().Number, @@ -318,6 +318,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, + //Price: tx.GasPrice, }) closure.Call(vm, nil, nil) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 78044e840..1e43a2bae 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -13,7 +13,7 @@ type Transaction struct { Recipient []byte Value *big.Int Gas *big.Int - Gasprice *big.Int + GasPrice *big.Int Data []byte Init []byte v byte @@ -24,11 +24,11 @@ type Transaction struct { } func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { - return &Transaction{Value: value, Gasprice: gasprice, Data: script, Init: init, contractCreation: true} + return &Transaction{Value: value, GasPrice: gasprice, Data: script, Init: init, contractCreation: true} } func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} + return &Transaction{Recipient: to, Value: value, GasPrice: gasprice, Gas: gas, Data: data} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -46,7 +46,7 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, string(tx.Data)} + data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, string(tx.Data)} if tx.contractCreation { data = append(data, string(tx.Init)) } @@ -107,7 +107,7 @@ func (tx *Transaction) Sign(privk []byte) error { // [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] // [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} if tx.contractCreation { data = append(data, tx.Init) @@ -132,7 +132,7 @@ func (tx *Transaction) RlpDecode(data []byte) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() - tx.Gasprice = decoder.Get(2).BigInt() + tx.GasPrice = decoder.Get(2).BigInt() tx.Gas = decoder.Get(3).BigInt() tx.Recipient = decoder.Get(4).Bytes() tx.Data = decoder.Get(5).Bytes() diff --git a/ethchain/vm.go b/ethchain/vm.go index 33d667457..85aefa685 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -71,7 +71,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // New stack (should this be shared?) stack := NewStack() require := func(m int) { - if stack.Len()-1 > m { + if stack.Len() < m { isRequireError = true panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) } @@ -105,7 +105,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // TODO Get each instruction cost properly gas := new(big.Int) useGas := func(amount *big.Int) { - gas.Add(gas, amount) + gas.Add(gas, new(big.Int).Mul(amount, closure.Price)) } switch op { @@ -142,6 +142,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + closure.Gas.Sub(closure.Gas, gas) switch op { case oLOG: @@ -411,7 +412,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // 0x60 range case oCREATE: case oCALL: - require(8) + require(7) // Closure addr addr := stack.Pop() // Pop gas and value of the stack. @@ -425,7 +426,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index a0add9532..f66f2a896 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -91,10 +91,10 @@ func TestRun4(t *testing.T) { exit() `), false) script := ethutil.Assemble(asm...) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script, nil) addr := tx.Hash()[12:] contract := MakeContract(tx, state) - state.UpdateContract(contract) + state.UpdateStateObject(contract) fmt.Printf("%x\n", addr) asm, err = mutan.Compile(strings.NewReader(` @@ -122,12 +122,13 @@ func TestRun4(t *testing.T) { fmt.Println(asm) callerScript := ethutil.Assemble(asm...) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript, nil) // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) + fmt.Println(account) c := MakeContract(callerTx, state) - callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) + callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), big.NewInt(10), big.NewInt(0)) vm := NewVm(state, RuntimeVars{ Origin: account.Address(), @@ -136,10 +137,12 @@ func TestRun4(t *testing.T) { Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), Time: 1, Diff: big.NewInt(256), - // XXX Tx data? Could be just an argument to the closure instead - TxData: nil, }) - callerClosure.Call(vm, nil, nil) + _, e := callerClosure.Call(vm, nil, nil) + if e != nil { + fmt.Println("error", e) + } + fmt.Println(account) } func TestRun5(t *testing.T) { -- cgit v1.2.3 From 6930260962f4c6d1fe11d07a10300da96886ecd6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 20 Apr 2014 01:31:01 +0200 Subject: Updated VM --- ethchain/closure.go | 10 ++++------ ethchain/state_object.go | 22 ++++++++++++++++++-- ethchain/vm.go | 52 +++++++++++++++++++++++++++++++++--------------- ethchain/vm_test.go | 41 +++++++++++++++++++++++++++----------- 4 files changed, 89 insertions(+), 36 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 5c508179e..defd8b5c8 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -8,7 +8,7 @@ import ( ) type Callee interface { - ReturnGas(*big.Int, *State) + ReturnGas(*big.Int, *big.Int, *State) Address() []byte } @@ -83,18 +83,16 @@ func (c *Closure) Return(ret []byte) []byte { // If no callee is present return it to // the origin (i.e. contract or tx) if c.callee != nil { - c.callee.ReturnGas(c.Gas, c.State) + c.callee.ReturnGas(c.Gas, c.Price, c.State) } else { - c.object.ReturnGas(c.Gas, c.State) - // TODO incase it's a POST contract we gotta serialise the contract again. - // But it's not yet defined + c.object.ReturnGas(c.Gas, c.Price, c.State) } return ret } // Implement the Callee interface -func (c *Closure) ReturnGas(gas *big.Int, state *State) { +func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { // Return the gas to the closure c.Gas.Add(c.Gas, gas) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8b4de0c4f..f562e5b04 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -70,8 +71,9 @@ func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { } // Return the gas back to the origin. Used by the Virtual machine or Closures -func (c *StateObject) ReturnGas(val *big.Int, state *State) { - c.AddAmount(val) +func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { + remainder := new(big.Int).Mul(gas, price) + c.AddAmount(remainder) } func (c *StateObject) AddAmount(amount *big.Int) { @@ -82,18 +84,33 @@ func (c *StateObject) SubAmount(amount *big.Int) { c.Amount.Sub(c.Amount, amount) } +func (c *StateObject) ConvertGas(gas, price *big.Int) error { + total := new(big.Int).Mul(gas, price) + if total.Cmp(c.Amount) > 0 { + return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total) + } + + c.SubAmount(total) + + return nil +} + +// Returns the address of the contract/account func (c *StateObject) Address() []byte { return c.address } +// Returns the main script body func (c *StateObject) Script() []byte { return c.script } +// Returns the initialization script func (c *StateObject) Init() []byte { return c.initScript } +// State object encoding methods func (c *StateObject) RlpEncode() []byte { var root interface{} if c.state != nil { @@ -113,6 +130,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.script = decoder.Get(3).Bytes() } +// Converts an transaction in to a state object func MakeContract(tx *Transaction, state *State) *StateObject { // Create contract if there's no recipient if tx.IsContract() { diff --git a/ethchain/vm.go b/ethchain/vm.go index 85aefa685..c249adfeb 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -102,10 +102,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } */ - // TODO Get each instruction cost properly gas := new(big.Int) useGas := func(amount *big.Int) { - gas.Add(gas, new(big.Int).Mul(amount, closure.Price)) + gas.Add(gas, amount) } switch op { @@ -142,6 +141,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + + // Sub the amount of gas from the remaining closure.Gas.Sub(closure.Gas, gas) switch op { @@ -157,7 +158,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) - base.Mod(base, Pow256) // Pop result back on the stack stack.Push(base) case oSUB: @@ -165,7 +165,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x - y) % 2 ** 256 base.Sub(x, y) - base.Mod(base, Pow256) // Pop result back on the stack stack.Push(base) case oMUL: @@ -173,7 +172,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x * y) % 2 ** 256 base.Mul(x, y) - base.Mod(base, Pow256) // Pop result back on the stack stack.Push(base) case oDIV: @@ -325,7 +323,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) case oGASPRICE: - // TODO + stack.Push(closure.Price) // 0x40 range case oPREVHASH: @@ -339,7 +337,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oDIFFICULTY: stack.Push(vm.vars.Diff) case oGASLIMIT: - // TODO + // TODO + stack.Push(big.NewInt(0)) // 0x50 range case oPUSH: // Push PC+1 on to the stack @@ -399,11 +398,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oJUMP: require(1) pc = stack.Pop() + // Reduce pc by one because of the increment that's at the end of this for loop + pc.Sub(pc, ethutil.Big1) case oJUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos + pc.Sub(pc, ethutil.Big1) } case oPC: stack.Push(pc) @@ -421,21 +423,39 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro inSize, inOffset := stack.Popn() // Pop return size and offset retSize, retOffset := stack.Popn() + // Make sure there's enough gas + if closure.Gas.Cmp(gas) < 0 { + stack.Push(ethutil.BigFalse) + + break + } // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) - // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) - // Executer the closure and get the return value (if any) - ret, err := closure.Call(vm, args, hook) - if err != nil { - stack.Push(ethutil.BigFalse) + + if contract != nil { + // Prepay for the gas + // If gas is set to 0 use all remaining gas for the next call + if gas.Cmp(big.NewInt(0)) == 0 { + gas = closure.Gas + } + closure.Gas.Sub(closure.Gas, gas) + // Create a new callable closure + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) + // Executer the closure and get the return value (if any) + ret, err := closure.Call(vm, args, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) + } + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { - stack.Push(ethutil.BigTrue) + ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) + stack.Push(ethutil.BigFalse) } - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: require(2) size, offset := stack.Popn() diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index f66f2a896..cca9b876a 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -86,9 +86,9 @@ func TestRun4(t *testing.T) { int32 a = 10 int32 b = 20 if a > b { - int32 c = this.caller() + int32 c = this.Caller() } - exit() + Exit() `), false) script := ethutil.Assemble(asm...) tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script, nil) @@ -103,8 +103,9 @@ func TestRun4(t *testing.T) { store[1000] = 10^20 } - store[1001] = this.value() * 20 - store[this.origin()] = store[this.origin()] + 1000 + + store[1001] = this.Value() * 20 + store[this.Origin()] = store[this.Origin()] + 1000 if store[1001] > 20 { store[1001] = 10^50 @@ -112,8 +113,18 @@ func TestRun4(t *testing.T) { int8 ret = 0 int8 arg = 10 - store[1002] = "a46df28529eb8aa8b8c025b0b413c5f4b688352f" - call(store[1002], 0, 100000000, arg, ret) + Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) + + big t + for int8 i = 0; i < 10; i++ { + t = i + } + + if 10 > 20 { + int8 shouldnt = 2 + } else { + int8 should = 1 + } `), false) if err != nil { fmt.Println(err) @@ -125,10 +136,17 @@ func TestRun4(t *testing.T) { callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript, nil) // Contract addr as test address + gas := big.NewInt(1000) + gasPrice := big.NewInt(10) account := NewAccount(ContractAddr, big.NewInt(10000000)) - fmt.Println(account) + fmt.Println("account.Amount =", account.Amount) c := MakeContract(callerTx, state) - callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), big.NewInt(10), big.NewInt(0)) + e := account.ConvertGas(gas, gasPrice) + if e != nil { + fmt.Println(err) + } + fmt.Println("account.Amount =", account.Amount) + callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0)) vm := NewVm(state, RuntimeVars{ Origin: account.Address(), @@ -138,11 +156,11 @@ func TestRun4(t *testing.T) { Time: 1, Diff: big.NewInt(256), }) - _, e := callerClosure.Call(vm, nil, nil) + _, e = callerClosure.Call(vm, nil, nil) if e != nil { fmt.Println("error", e) } - fmt.Println(account) + fmt.Println("account.Amount =", account.Amount) } func TestRun5(t *testing.T) { @@ -156,6 +174,5 @@ func TestRun5(t *testing.T) { } exit() `), false) - script := ethutil.Assemble(asm...) - fmt.Println(Disassemble(script)) + ethutil.Assemble(asm...) } -- cgit v1.2.3 From 61cd1594b52514244efcb47bd93722aaec0fe456 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 11:50:38 +0200 Subject: Fixed gas, price & value setters on initialization --- ethchain/closure.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index defd8b5c8..f8135c514 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -35,7 +35,15 @@ type Closure struct { // Create a new closure for the given data items func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure { - return &Closure{callee, object, script, state, gas, price, val, nil} + c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} + + // In most cases gas, price and value are pointers to transaction objects + // and we don't want the transaction's values to change. + c.Gas = new(big.Int).Set(gas) + c.Price = new(big.Int).Set(price) + c.Value = new(big.Int).Set(val) + + return c } // Retuns the x element in data slice -- cgit v1.2.3 From 3a9a252f6e44abb0f45f57a46c0fa91e2f73c545 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 11:51:04 +0200 Subject: Fixed minor issue with gas and added state object init --- ethchain/state_manager.go | 53 ++++++++++++++++++++++++++++++++++++++------ ethchain/transaction.go | 14 ++++++------ ethchain/transaction_pool.go | 4 +--- ethchain/types.go | 6 ++--- ethchain/vm.go | 24 +++++++++----------- 5 files changed, 68 insertions(+), 33 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 75a78e9f3..23da77fae 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -91,23 +91,60 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeContract(tx *Transaction) { +func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { contract := MakeContract(tx, sm.procState) if contract != nil { sm.procState.states[string(tx.Hash()[12:])] = contract.state + + return contract } + + return nil } // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { + // Process each transaction/contract + for _, tx := range txs { + fmt.Printf("Processing Tx: %x\n", tx.Hash()) + // If there's no recipient, it's a contract + // Check if this is a contract creation traction and if so + // create a contract of this tx. + if tx.IsContract() { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + if err == nil { + contract := sm.MakeContract(tx) + if contract != nil { + sm.EvalScript(contract.Init(), contract, tx, block) + } else { + ethutil.Config.Log.Infoln("[STATE] Unable to create contract") + } + } else { + ethutil.Config.Log.Infoln("[STATE] contract create:", err) + } + } else { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + contract := sm.procState.GetContract(tx.Recipient) + if err == nil && len(contract.Script()) > 0 { + sm.EvalScript(contract.Script(), contract, tx, block) + } else if err != nil { + ethutil.Config.Log.Infoln("[STATE] process:", err) + } + } + } // Process each transaction/contract for _, tx := range txs { // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. if tx.IsContract() { - sm.MakeContract(tx) + contract := sm.MakeContract(tx) + if contract != nil { + sm.EvalScript(contract.Init(), contract, tx, block) + } else { + ethutil.Config.Log.Infoln("[STATE] Unable to create contract") + } } else { // Figure out if the address this transaction was sent to is a // contract or an actual account. In case of a contract, we process that @@ -303,11 +340,13 @@ func (sm *StateManager) Stop() { func (sm *StateManager) EvalScript(script []byte, object *StateObject, 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) + } + }() + */ caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 1e43a2bae..421f26c98 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -23,12 +23,12 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { - return &Transaction{Value: value, GasPrice: gasprice, Data: script, Init: init, contractCreation: true} +func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte, init []byte) *Transaction { + return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, Init: init, contractCreation: true} } -func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, GasPrice: gasprice, Gas: gas, Data: data} +func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -46,9 +46,10 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, string(tx.Data)} + data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + if tx.contractCreation { - data = append(data, string(tx.Init)) + data = append(data, tx.Init) } return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) @@ -112,7 +113,6 @@ func (tx *Transaction) RlpData() interface{} { if tx.contractCreation { data = append(data, tx.Init) } - //d := ethutil.NewSliceValue(tx.Data).Slice() return append(data, tx.v, tx.r, tx.s) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 5cdda17e2..957381ac7 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -104,7 +104,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // 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("[TXPL] Insufficient amount in sender's account") + return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } if sender.Nonce != tx.Nonce { @@ -119,8 +119,6 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { // Subtract the fee sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) - } else if toContract { - sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) } else { // Subtract the amount from the senders account sender.SubAmount(totAmount) diff --git a/ethchain/types.go b/ethchain/types.go index 24aad82c3..827d4f27f 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -35,7 +35,7 @@ const ( oORIGIN = 0x32 oCALLER = 0x33 oCALLVALUE = 0x34 - oCALLDATA = 0x35 + oCALLDATALOAD = 0x35 oCALLDATASIZE = 0x36 oGASPRICE = 0x37 @@ -106,7 +106,7 @@ var opCodeToString = map[OpCode]string{ oORIGIN: "ORIGIN", oCALLER: "CALLER", oCALLVALUE: "CALLVALUE", - oCALLDATA: "CALLDATA", + oCALLDATALOAD: "CALLDATALOAD", oCALLDATASIZE: "CALLDATASIZE", oGASPRICE: "TXGASPRICE", @@ -180,7 +180,7 @@ var OpCodes = map[string]byte{ "ORIGIN": 0x32, "CALLER": 0x33, "CALLVALUE": 0x34, - "CALLDATA": 0x35, + "CALLDATALOAD": 0x35, "CALLDATASIZE": 0x36, "GASPRICE": 0x38, diff --git a/ethchain/vm.go b/ethchain/vm.go index c249adfeb..33541cb3b 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -84,11 +84,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // The base for all big integer arithmetic base := new(big.Int) - /* - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("# op\n") - } - */ + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("# op\n") + } for { step++ @@ -96,11 +94,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - /* - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } - */ + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } gas := new(big.Int) useGas := func(amount *big.Int) { @@ -316,10 +312,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLVALUE: // FIXME: Original value of the call, not the current value stack.Push(closure.Value) - case oCALLDATA: + case oCALLDATALOAD: require(1) - offset := stack.Pop() - mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) + offset := stack.Pop().Int64() + val := closure.Args[offset : offset+31] + + stack.Push(ethutil.BigD(val)) case oCALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) case oGASPRICE: -- cgit v1.2.3 From f7d4e3cd6b276e4d66abe89b4f1b2dfa2faf90df Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 15:52:50 +0200 Subject: Copy over bytes from previous root Copy over instead of directly using the previous root. This is order to avoid resetting problems --- ethchain/block.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 8c93947fb..c9197c69a 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -80,6 +80,9 @@ func CreateBlock(root interface{}, extra string, txes []*Transaction) *Block { + // Copy over the bytes + copiedRoot := ethutil.NewValue(root).Bytes() + block := &Block{ // Slice of transactions to include in this block transactions: txes, @@ -95,7 +98,7 @@ func CreateBlock(root interface{}, block.SetTransactions(txes) block.SetUncles([]*Block{}) - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) + block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, copiedRoot)) for _, tx := range txes { block.MakeContract(tx) -- cgit v1.2.3 From c81804444f69ae1653d54551d8555ff924651cd9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 15:53:53 +0200 Subject: Call initial closure with proper tx argument --- ethchain/block_chain.go | 1 + ethchain/state_manager.go | 33 +-------------------------------- ethchain/vm.go | 4 +++- 3 files changed, 5 insertions(+), 33 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index d65c38fe4..08886c9cd 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -46,6 +46,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { hash = bc.LastBlockHash lastBlockTime = bc.CurrentBlock.Time } + block := CreateBlock( root, hash, diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 23da77fae..668a44c3f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -133,37 +133,6 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { } } } - // Process each transaction/contract - for _, tx := range txs { - // If there's no recipient, it's a contract - // Check if this is a contract creation traction and if so - // create a contract of this tx. - if tx.IsContract() { - contract := sm.MakeContract(tx) - if contract != nil { - sm.EvalScript(contract.Init(), contract, tx, block) - } else { - ethutil.Config.Log.Infoln("[STATE] Unable to create contract") - } - } else { - // Figure out if the address this transaction was sent to is a - // contract or an actual account. In case of a contract, we process that - // contract instead of moving funds between accounts. - var err error - if contract := sm.procState.GetContract(tx.Recipient); contract != nil { - err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true) - if err == nil { - sm.EvalScript(contract.Script(), contract, tx, block) - } - } else { - err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - } - - if err != nil { - ethutil.Config.Log.Infoln("[STATE]", err) - } - } - } } // The prepare function, prepares the state manager for the next @@ -359,7 +328,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans Diff: block.Difficulty, //Price: tx.GasPrice, }) - closure.Call(vm, nil, nil) + closure.Call(vm, tx.Data, nil) // Update the account (refunds) sm.procState.UpdateStateObject(caller) diff --git a/ethchain/vm.go b/ethchain/vm.go index 33541cb3b..90b591f50 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -53,11 +53,12 @@ var isRequireError = false func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err error) { // Recover from any require exception defer func() { - if r := recover(); r != nil && isRequireError { + if r := recover(); r != nil /*&& isRequireError*/ { fmt.Println(r) ret = closure.Return(nil) err = fmt.Errorf("%v", r) + fmt.Println("vm err", err) } }() @@ -315,6 +316,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLDATALOAD: require(1) offset := stack.Pop().Int64() + fmt.Println(closure.Args) val := closure.Args[offset : offset+31] stack.Push(ethutil.BigD(val)) -- cgit v1.2.3 From 1c85d8c66b9db23687b0446b4a7e97e3e61fe188 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Apr 2014 00:00:50 +0200 Subject: Minor improvements and bug fixes * Fixed VM base bug --- ethchain/state.go | 4 ++-- ethchain/state_manager.go | 2 ++ ethchain/transaction_pool.go | 8 ++++---- ethchain/vm.go | 6 ++++-- 4 files changed, 12 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 655848932..fa63accf8 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -34,12 +34,12 @@ func (s *State) Reset() { // Syncs the trie and all siblings func (s *State) Sync() { - s.trie.Sync() - // Sync all nested states for _, state := range s.states { state.Sync() } + + s.trie.Sync() } // Purges the current trie. diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 668a44c3f..29c3cd16b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -117,6 +117,7 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { contract := sm.MakeContract(tx) if contract != nil { sm.EvalScript(contract.Init(), contract, tx, block) + fmt.Printf("state root of contract %x\n", contract.State().Root()) } else { ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } @@ -332,4 +333,5 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(caller) + sm.procState.UpdateStateObject(object) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 957381ac7..91fad2635 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -100,6 +100,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // Get the sender sender := block.state.GetAccount(tx.Sender()) + if sender.Nonce != tx.Nonce { + return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) + } + // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) @@ -107,10 +111,6 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } - if sender.Nonce != tx.Nonce { - return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) - } - // Get the receiver receiver := block.state.GetAccount(tx.Recipient) sender.Nonce += 1 diff --git a/ethchain/vm.go b/ethchain/vm.go index 90b591f50..7df63b181 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -82,14 +82,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc := big.NewInt(0) // Current step count step := 0 - // The base for all big integer arithmetic - base := new(big.Int) if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } for { + // The base for all big integer arithmetic + base := new(big.Int) + step++ // Get the memory location of pc val := closure.Get(pc) @@ -390,6 +391,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + fmt.Printf("load %x = %v\n", loc.Bytes(), val.BigInt()) stack.Push(val.BigInt()) case oSSTORE: require(2) -- cgit v1.2.3 From ee7c16a8d977389c63ef60ea6c5eaff11e150ca4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Apr 2014 13:30:57 +0200 Subject: Fixed Base problem and sload/sstore --- ethchain/vm.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 7df63b181..bc4c65d03 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -121,7 +121,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { mult = ethutil.Big1 } - useGas(base.Mul(mult, GasSStore)) + useGas(new(big.Int).Mul(mult, GasSStore)) case oBALANCE: useGas(GasBalance) case oCREATE: @@ -156,6 +156,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) + fmt.Println(x, y, base) // Pop result back on the stack stack.Push(base) case oSUB: @@ -317,8 +318,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLDATALOAD: require(1) offset := stack.Pop().Int64() - fmt.Println(closure.Args) - val := closure.Args[offset : offset+31] + val := closure.Args[offset : offset+32] + fmt.Println(ethutil.BigD(val)) stack.Push(ethutil.BigD(val)) case oCALLDATASIZE: -- cgit v1.2.3 From f3818478e2601df1d9cfc9cc36b021366f870856 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Apr 2014 13:48:33 +0200 Subject: Removed debug & unused functions --- ethchain/block.go | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index c9197c69a..d95ebf4b5 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -116,11 +116,6 @@ func (block *Block) HashNoNonce() []byte { return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) } -func (block *Block) PrintHash() { - fmt.Println(block) - fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce}))) -} - func (block *Block) State() *State { return block.state } @@ -182,26 +177,6 @@ func (block *Block) MakeContract(tx *Transaction) { } /////// 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)) -- cgit v1.2.3 From 0f93da400ab7fd238eb7286f14c229d780f73636 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 01:47:55 +0200 Subject: Added new state object change echanism --- ethchain/state_manager.go | 33 ++++++++++++++++------- ethchain/state_object.go | 67 +++++++++++++++++++++++++---------------------- ethchain/vm.go | 6 +++-- 3 files changed, 63 insertions(+), 43 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 29c3cd16b..1ab58386a 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -50,6 +50,10 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State + + // It's generally know that a map is faster for small lookups than arrays + // we'll eventually have to make a decision if the map grows too large + watchedAddresses map[string]bool } func NewStateManager(ethereum EthManager) *StateManager { @@ -60,6 +64,7 @@ func NewStateManager(ethereum EthManager) *StateManager { Ethereum: ethereum, stateObjectCache: NewStateObjectCache(), bc: ethereum.BlockChain(), + watchedAddresses: make(map[string]bool), } sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm @@ -309,18 +314,9 @@ func (sm *StateManager) Stop() { } func (sm *StateManager) EvalScript(script []byte, object *StateObject, 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) - } - }() - */ - caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) - vm := NewVm(sm.procState, RuntimeVars{ + vm := NewVm(sm.procState, sm, RuntimeVars{ Origin: caller.Address(), BlockNumber: block.BlockInfo().Number, PrevHash: block.PrevHash, @@ -333,5 +329,22 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(caller) + sm.Changed(caller) sm.procState.UpdateStateObject(object) + sm.Changed(object) +} + +// Watch a specific address +func (sm *StateManager) Watch(addr []byte) { + if !sm.watchedAddresses[string(addr)] { + sm.watchedAddresses[string(addr)] = true + } +} + +// The following objects are used when changing a value and using the "watched" attribute +// to determine whether the reactor should be used to notify any subscribers on the address +func (sm *StateManager) Changed(stateObject *StateObject) { + if sm.watchedAddresses[string(stateObject.Address())] { + sm.Ethereum.Reactor().Post("addressChanged", stateObject) + } } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index f562e5b04..8d86ef44e 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -18,6 +18,28 @@ type StateObject struct { initScript []byte } +// Converts an transaction in to a state object +func MakeContract(tx *Transaction, state *State) *StateObject { + // Create contract if there's no recipient + if tx.IsContract() { + // FIXME + addr := tx.Hash()[12:] + + value := tx.Value + contract := NewContract(addr, value, []byte("")) + state.UpdateStateObject(contract) + + contract.script = tx.Data + contract.initScript = tx.Init + + state.UpdateStateObject(contract) + + return contract + } + + return nil +} + func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { contract := &StateObject{address: address, Amount: Amount, Nonce: 0} contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) @@ -39,6 +61,10 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { return object } +func (c *StateObject) State() *State { + return c.state +} + func (c *StateObject) Addr(addr []byte) *ethutil.Value { return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) } @@ -47,8 +73,10 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *StateObject) State() *State { - return c.state +func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { + addr := ethutil.BigToBytes(num, 256) + c.SetAddr(addr, val) + //c.state.trie.Update(string(addr), string(val.Encode())) } func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { @@ -65,11 +93,6 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) } -func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { - addr := ethutil.BigToBytes(num, 256) - c.state.trie.Update(string(addr), string(val.Encode())) -} - // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { remainder := new(big.Int).Mul(gas, price) @@ -77,11 +100,15 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { } func (c *StateObject) AddAmount(amount *big.Int) { - c.Amount.Add(c.Amount, amount) + c.SetAmount(new(big.Int).Add(c.Amount, amount)) } func (c *StateObject) SubAmount(amount *big.Int) { - c.Amount.Sub(c.Amount, amount) + c.SetAmount(new(big.Int).Sub(c.Amount, amount)) +} + +func (c *StateObject) SetAmount(amount *big.Int) { + c.Amount = amount } func (c *StateObject) ConvertGas(gas, price *big.Int) error { @@ -130,28 +157,6 @@ func (c *StateObject) RlpDecode(data []byte) { c.script = decoder.Get(3).Bytes() } -// Converts an transaction in to a state object -func MakeContract(tx *Transaction, state *State) *StateObject { - // Create contract if there's no recipient - if tx.IsContract() { - // FIXME - addr := tx.Hash()[12:] - - value := tx.Value - contract := NewContract(addr, value, []byte("")) - state.UpdateStateObject(contract) - - contract.script = tx.Data - contract.initScript = tx.Init - - state.UpdateStateObject(contract) - - return contract - } - - return nil -} - // The cached state and state object cache are helpers which will give you somewhat // control over the nonce. When creating new transactions you're interested in the 'next' // nonce rather than the current nonce. This to avoid creating invalid-nonce transactions. diff --git a/ethchain/vm.go b/ethchain/vm.go index bc4c65d03..93557007d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -30,6 +30,8 @@ type Vm struct { vars RuntimeVars state *State + + stateManager *StateManager } type RuntimeVars struct { @@ -42,8 +44,8 @@ type RuntimeVars struct { TxData []string } -func NewVm(state *State, vars RuntimeVars) *Vm { - return &Vm{vars: vars, state: state} +func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { + return &Vm{vars: vars, state: state, stateManager: stateManager} } var Pow256 = ethutil.BigPow(2, 256) -- cgit v1.2.3 From d3a159ad3d6842ffb137fc1df48a54703345faa4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 01:54:45 +0200 Subject: Fixed tests --- ethchain/vm_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index cca9b876a..75a4f5afb 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -91,7 +91,7 @@ func TestRun4(t *testing.T) { Exit() `), false) script := ethutil.Assemble(asm...) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script, nil) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) addr := tx.Hash()[12:] contract := MakeContract(tx, state) state.UpdateStateObject(contract) @@ -133,7 +133,7 @@ func TestRun4(t *testing.T) { fmt.Println(asm) callerScript := ethutil.Assemble(asm...) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript, nil) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil) // Contract addr as test address gas := big.NewInt(1000) @@ -148,7 +148,7 @@ func TestRun4(t *testing.T) { fmt.Println("account.Amount =", account.Amount) callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0)) - vm := NewVm(state, RuntimeVars{ + vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), BlockNumber: 1, PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), -- cgit v1.2.3 From ca6e3f6defae958cece52ee7d26ca1b53b0adebb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 02:06:25 +0200 Subject: Notify of changes --- ethchain/vm.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 93557007d..a4b4d351b 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -56,8 +56,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Recover from any require exception defer func() { if r := recover(); r != nil /*&& isRequireError*/ { - fmt.Println(r) - ret = closure.Return(nil) err = fmt.Errorf("%v", r) fmt.Println("vm err", err) @@ -158,7 +156,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) - fmt.Println(x, y, base) // Pop result back on the stack stack.Push(base) case oSUB: @@ -321,7 +318,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) offset := stack.Pop().Int64() val := closure.Args[offset : offset+32] - fmt.Println(ethutil.BigD(val)) stack.Push(ethutil.BigD(val)) case oCALLDATASIZE: @@ -394,7 +390,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) - fmt.Printf("load %x = %v\n", loc.Bytes(), val.BigInt()) stack.Push(val.BigInt()) case oSSTORE: require(2) @@ -452,8 +447,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro ret, err := closure.Call(vm, args, hook) if err != nil { stack.Push(ethutil.BigFalse) + // Reset the changes applied this object + //contract.State().Reset() } else { stack.Push(ethutil.BigTrue) + // Notify of the changes + vm.stateManager.Changed(contract) } mem.Set(retOffset.Int64(), retSize.Int64(), ret) -- cgit v1.2.3 From 05d2d8f27d0bea5b20be9bc3b4a259a12298ecab Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 02:11:00 +0200 Subject: Actually convert gas --- ethchain/state_manager.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1ab58386a..628ab6a27 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -314,10 +314,17 @@ func (sm *StateManager) Stop() { } func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { - caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) + account := sm.procState.GetAccount(tx.Sender()) + + err := account.ConvertGas(tx.Gas, tx.GasPrice) + if err != nil { + ethutil.Config.Log.Debugln(err) + return + } + + closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) vm := NewVm(sm.procState, sm, RuntimeVars{ - Origin: caller.Address(), + Origin: account.Address(), BlockNumber: block.BlockInfo().Number, PrevHash: block.PrevHash, Coinbase: block.Coinbase, @@ -328,8 +335,8 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans closure.Call(vm, tx.Data, nil) // Update the account (refunds) - sm.procState.UpdateStateObject(caller) - sm.Changed(caller) + sm.procState.UpdateStateObject(account) + sm.Changed(account) sm.procState.UpdateStateObject(object) sm.Changed(object) } -- cgit v1.2.3 From 16e52327a4baa5547c38965fce53b3ff40b98173 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 16:50:44 +0200 Subject: Upped version number --- ethchain/closure.go | 23 ++++++++++++++------- ethchain/stack.go | 12 +++++++++++ ethchain/state.go | 29 ++++++++++++++++++++++++++ ethchain/state_object.go | 4 ++++ ethchain/vm.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 112 insertions(+), 10 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index f8135c514..57abaa91e 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -8,21 +8,24 @@ import ( ) type Callee interface { - ReturnGas(*big.Int, *big.Int, *State) - Address() []byte } type Reference interface { Callee - ethutil.RlpEncodable +} + +type ClosureRef interface { + ReturnGas(*big.Int, *big.Int, *State) + Address() []byte GetMem(*big.Int) *ethutil.Value SetMem(*big.Int, *ethutil.Value) + N() *big.Int } // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee Callee - object Reference + callee ClosureRef + object ClosureRef Script []byte State *State @@ -34,7 +37,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure { +func NewClosure(callee, object ClosureRef, script []byte, state *State, gas, price, val *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects @@ -105,10 +108,14 @@ func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { c.Gas.Add(c.Gas, gas) } -func (c *Closure) Object() Reference { +func (c *Closure) Object() ClosureRef { return c.object } -func (c *Closure) Callee() Callee { +func (c *Closure) Callee() ClosureRef { return c.callee } + +func (c *Closure) N() *big.Int { + return c.object.N() +} diff --git a/ethchain/stack.go b/ethchain/stack.go index 288360062..e9297b324 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -67,6 +67,18 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) { func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } + +func (st *Stack) Get(amount *big.Int) []*big.Int { + // offset + size <= len(data) + length := big.NewInt(int64(len(st.data))) + if amount.Cmp(length) <= 0 { + start := new(big.Int).Sub(length, amount) + return st.data[start.Int64():length.Int64()] + } + + return nil +} + func (st *Stack) Print() { fmt.Println("### stack ###") if len(st.data) > 0 { diff --git a/ethchain/state.go b/ethchain/state.go index fa63accf8..1b5655d4c 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -47,6 +47,7 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } +// XXX Deprecated func (s *State) GetContract(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { @@ -68,6 +69,32 @@ func (s *State) GetContract(addr []byte) *StateObject { return contract } +func (s *State) GetStateObject(addr []byte) *StateObject { + data := s.trie.Get(string(addr)) + if data == "" { + return nil + } + + stateObject := NewStateObjectFromBytes(addr, []byte(data)) + + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + stateObject.state = cachedStateObject + } else { + // If it isn't cached, cache the state + s.states[string(addr)] = stateObject.state + } + + return stateObject +} + +func (s *State) SetStateObject(stateObject *StateObject) { + s.states[string(stateObject.address)] = stateObject.state + + s.UpdateStateObject(stateObject) +} + func (s *State) GetAccount(addr []byte) (account *StateObject) { data := s.trie.Get(string(addr)) if data == "" { @@ -97,6 +124,7 @@ const ( UnknownTy ) +/* // Returns the object stored at key and the type stored at key // Returns nil if nothing is stored func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { @@ -124,6 +152,7 @@ func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { return val, typ } +*/ // Updates any given state object func (s *State) UpdateStateObject(object *StateObject) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8d86ef44e..8e921795d 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -65,6 +65,10 @@ func (c *StateObject) State() *State { return c.state } +func (c *StateObject) N() *big.Int { + return big.NewInt(int64(c.Nonce)) +} + func (c *StateObject) Addr(addr []byte) *ethutil.Value { return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) } diff --git a/ethchain/vm.go b/ethchain/vm.go index a4b4d351b..b983e88ff 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -20,6 +20,17 @@ var ( GasMemory = big.NewInt(1) ) +func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int { + totalGas := new(big.Int) + totalGas.Add(totalGas, GasCreate) + + txTotalBytes := new(big.Int).Add(initSize, scriptSize) + txTotalBytes.Div(txTotalBytes, ethutil.Big32) + totalGas.Add(totalGas, new(big.Int).Mul(txTotalBytes, GasSStore)) + + return totalGas +} + type Vm struct { txPool *TxPool // Stack for processing contracts @@ -125,7 +136,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oBALANCE: useGas(GasBalance) case oCREATE: - useGas(GasCreate) + require(3) + + args := stack.Get(big.NewInt(3)) + initSize := new(big.Int).Add(args[1], args[0]) + + useGas(CalculateTxGas(initSize, ethutil.Big0)) case oCALL: useGas(GasCall) case oMLOAD, oMSIZE, oMSTORE8, oMSTORE: @@ -413,6 +429,39 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(big.NewInt(int64(mem.Len()))) // 0x60 range case oCREATE: + require(3) + + value := stack.Pop() + size, offset := stack.Popn() + + // Generate a new address + addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N()) + // Create a new contract + contract := NewContract(addr, value, []byte("")) + // Set the init script + contract.initScript = mem.Get(offset.Int64(), size.Int64()) + // Transfer all remaining gas to the new + // contract so it may run the init script + gas := new(big.Int).Set(closure.Gas) + closure.Gas.Sub(closure.Gas, gas) + // Create the closure + closure := NewClosure(closure.callee, + closure.Object(), + contract.initScript, + vm.state, + gas, + closure.Price, + value) + // Call the closure and set the return value as + // main script. + closure.Script, err = closure.Call(vm, nil, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigD(addr)) + + vm.state.SetStateObject(contract) + } case oCALL: require(7) // Closure addr @@ -438,7 +487,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Prepay for the gas // If gas is set to 0 use all remaining gas for the next call if gas.Cmp(big.NewInt(0)) == 0 { - gas = closure.Gas + // Copy + gas = new(big.Int).Set(closure.Gas) } closure.Gas.Sub(closure.Gas, gas) // Create a new callable closure -- cgit v1.2.3 From bf850974f3e1794a3e2aa4ff33b527297cc50f91 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 18:00:38 +0200 Subject: Using mutan assembler stage --- ethchain/vm_test.go | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 75a4f5afb..35a7b2e3f 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -82,7 +82,7 @@ func TestRun4(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - asm, err := mutan.Compile(strings.NewReader(` + script, err := mutan.Compile(strings.NewReader(` int32 a = 10 int32 b = 20 if a > b { @@ -90,14 +90,13 @@ func TestRun4(t *testing.T) { } Exit() `), false) - script := ethutil.Assemble(asm...) tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) addr := tx.Hash()[12:] contract := MakeContract(tx, state) state.UpdateStateObject(contract) fmt.Printf("%x\n", addr) - asm, err = mutan.Compile(strings.NewReader(` + callerScript, err := mutan.Compile(strings.NewReader(` // Check if there's any cash in the initial store if store[1000] == 0 { store[1000] = 10^20 @@ -129,10 +128,7 @@ func TestRun4(t *testing.T) { if err != nil { fmt.Println(err) } - asm = append(asm, "LOG") - fmt.Println(asm) - callerScript := ethutil.Assemble(asm...) callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil) // Contract addr as test address @@ -162,17 +158,3 @@ func TestRun4(t *testing.T) { } fmt.Println("account.Amount =", account.Amount) } - -func TestRun5(t *testing.T) { - ethutil.ReadConfig("") - - asm, _ := mutan.Compile(strings.NewReader(` - int32 a = 10 - int32 b = 20 - if a > b { - int32 c = this.caller() - } - exit() - `), false) - ethutil.Assemble(asm...) -} -- cgit v1.2.3 From 5516efdfa0494e028fc3649e4a38da81c56ed598 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 18:05:30 +0200 Subject: Removed old code --- ethchain/asm.go | 68 --------------------------------------------------------- 1 file changed, 68 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index a6c85cb60..3194549ba 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -4,55 +4,8 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" - "regexp" ) -func CompileInstr(s interface{}) ([]byte, error) { - switch s.(type) { - case string: - str := s.(string) - isOp := IsOpCode(str) - if isOp { - return []byte{OpCodes[str]}, nil - } - - num := new(big.Int) - _, success := num.SetString(str, 0) - // Assume regular bytes during compilation - if !success { - num.SetBytes([]byte(str)) - } else { - // tmp fix for 32 bytes - n := ethutil.BigToBytes(num, 256) - return n, nil - } - - return num.Bytes(), nil - case int: - num := ethutil.BigToBytes(big.NewInt(int64(s.(int))), 256) - return num, nil - case []byte: - return ethutil.BigD(s.([]byte)).Bytes(), nil - } - - return nil, nil -} - -// Script compilation functions -// Compiles strings to machine code -func Assemble(instructions ...interface{}) (script []byte) { - //script = make([]string, len(instructions)) - - for _, val := range instructions { - instr, _ := CompileInstr(val) - - //script[i] = string(instr) - script = append(script, instr...) - } - - return -} - func Disassemble(script []byte) (asm []string) { pc := new(big.Int) for { @@ -104,24 +57,3 @@ func Disassemble(script []byte) (asm []string) { return } - -func PreProcess(data string) (mainInput, initInput string) { - // Regexp for parsing anything between brackets - reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" - mainReg := regexp.MustCompile("main" + reg) - initReg := regexp.MustCompile("init" + reg) - - main := mainReg.FindStringSubmatch(data) - if len(main) > 0 { - mainInput = main[1] - } else { - mainInput = data - } - - init := initReg.FindStringSubmatch(data) - if len(init) > 0 { - initInput = init[1] - } - - return -} -- cgit v1.2.3 From 38d6b67b5cfbfb63620a244ea01b5b534917128f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Apr 2014 12:36:27 +0200 Subject: Fixed state problem --- ethchain/block.go | 5 +---- ethchain/block_chain.go | 3 ++- ethchain/state_manager.go | 13 +++++++------ 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index d95ebf4b5..aac50ccb1 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -80,9 +80,6 @@ func CreateBlock(root interface{}, extra string, txes []*Transaction) *Block { - // Copy over the bytes - copiedRoot := ethutil.NewValue(root).Bytes() - block := &Block{ // Slice of transactions to include in this block transactions: txes, @@ -98,7 +95,7 @@ func CreateBlock(root interface{}, block.SetTransactions(txes) block.SetUncles([]*Block{}) - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, copiedRoot)) + block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) for _, tx := range txes { block.MakeContract(tx) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 08886c9cd..2be4cd92b 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -179,7 +179,8 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { bc.LastBlockNumber = info.Number } - bc.Ethereum.StateManager().PrepareDefault(returnTo) + // XXX Why are we resetting? This is the block chain, it has nothing to do with states + //bc.Ethereum.StateManager().PrepareDefault(returnTo) err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 628ab6a27..70d4155c3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -158,18 +158,19 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.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 sm.bc.CurrentBlock.Undo() hash := block.Hash() if sm.bc.HasBlock(hash) { - fmt.Println("[SM] We already have this block, ignoring") + fmt.Println("[STATE] We already have this block, ignoring") return nil } + // 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 sm.bc.CurrentBlock.Undo() + // 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 !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { -- cgit v1.2.3 From 21724f7ef960f0f2df0d2b0f3cccfd030a4aaee8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Apr 2014 14:43:32 +0200 Subject: Added manifest changes and changed closures --- ethchain/closure.go | 17 ++++--------- ethchain/state_manager.go | 65 ++++++++++++++++++++++++++++++++++------------- ethchain/vm.go | 7 +++-- 3 files changed, 58 insertions(+), 31 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 57abaa91e..7e911ad99 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -7,13 +7,6 @@ import ( "math/big" ) -type Callee interface { -} - -type Reference interface { - Callee -} - type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte @@ -24,8 +17,8 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee ClosureRef - object ClosureRef + callee *StateObject + object *StateObject Script []byte State *State @@ -37,7 +30,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee, object ClosureRef, script []byte, state *State, gas, price, val *big.Int) *Closure { +func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price, val *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects @@ -108,11 +101,11 @@ func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { c.Gas.Add(c.Gas, gas) } -func (c *Closure) Object() ClosureRef { +func (c *Closure) Object() *StateObject { return c.object } -func (c *Closure) Callee() ClosureRef { +func (c *Closure) Callee() *StateObject { return c.callee } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 70d4155c3..072fabc0e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -51,9 +51,7 @@ type StateManager struct { // results compState *State - // It's generally know that a map is faster for small lookups than arrays - // we'll eventually have to make a decision if the map grows too large - watchedAddresses map[string]bool + manifest *Manifest } func NewStateManager(ethereum EthManager) *StateManager { @@ -64,7 +62,7 @@ func NewStateManager(ethereum EthManager) *StateManager { Ethereum: ethereum, stateObjectCache: NewStateObjectCache(), bc: ethereum.BlockChain(), - watchedAddresses: make(map[string]bool), + manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm @@ -112,7 +110,6 @@ func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { - fmt.Printf("Processing Tx: %x\n", tx.Hash()) // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. @@ -122,7 +119,6 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { contract := sm.MakeContract(tx) if contract != nil { sm.EvalScript(contract.Init(), contract, tx, block) - fmt.Printf("state root of contract %x\n", contract.State().Root()) } else { ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } @@ -214,6 +210,10 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) + + sm.notifyChanges() + + sm.manifest.Reset() } } else { fmt.Println("total diff failed") @@ -337,22 +337,53 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(account) - sm.Changed(account) + sm.manifest.AddObjectChange(account) + sm.procState.UpdateStateObject(object) - sm.Changed(object) + sm.manifest.AddObjectChange(object) } -// Watch a specific address -func (sm *StateManager) Watch(addr []byte) { - if !sm.watchedAddresses[string(addr)] { - sm.watchedAddresses[string(addr)] = true +func (sm *StateManager) notifyChanges() { + for addr, stateObject := range sm.manifest.objectChanges { + sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } + + for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { + for addr, value := range mappedObjects { + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, value.String()) + } + } +} + +type Manifest struct { + // XXX These will be handy in the future. Not important for now. + objectAddresses map[string]bool + storageAddresses map[string]map[string]bool + + objectChanges map[string]*StateObject + storageChanges map[string]map[string]*big.Int } -// The following objects are used when changing a value and using the "watched" attribute -// to determine whether the reactor should be used to notify any subscribers on the address -func (sm *StateManager) Changed(stateObject *StateObject) { - if sm.watchedAddresses[string(stateObject.Address())] { - sm.Ethereum.Reactor().Post("addressChanged", stateObject) +func NewManifest() *Manifest { + m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} + m.Reset() + + return m +} + +func (m *Manifest) Reset() { + m.objectChanges = make(map[string]*StateObject) + m.storageChanges = make(map[string]map[string]*big.Int) +} + +func (m *Manifest) AddObjectChange(stateObject *StateObject) { + m.objectChanges[string(stateObject.Address())] = stateObject +} + +func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { + if m.storageChanges[string(stateObject.Address())] == nil { + m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) } + + m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage } diff --git a/ethchain/vm.go b/ethchain/vm.go index b983e88ff..0a3690c41 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -411,6 +411,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(2) val, loc := stack.Popn() closure.SetMem(loc, ethutil.NewValue(val)) + + // Add the change to manifest + vm.stateManager.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) case oJUMP: require(1) pc = stack.Pop() @@ -492,7 +495,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } closure.Gas.Sub(closure.Gas, gas) // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) + closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price, value) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { @@ -502,7 +505,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigTrue) // Notify of the changes - vm.stateManager.Changed(contract) + vm.stateManager.manifest.AddObjectChange(contract) } mem.Set(retOffset.Int64(), retSize.Int64(), ret) -- cgit v1.2.3 From c3293641e7b49c7e2d85d2bd69b37bc74cb5b00d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Apr 2014 17:13:32 +0200 Subject: Removed debug logging --- ethchain/error.go | 23 ++++++++++++++++++++++- ethchain/state_manager.go | 2 +- ethchain/transaction_pool.go | 10 +++------- 3 files changed, 26 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/error.go b/ethchain/error.go index 0f1d061c0..8d37b0208 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -1,6 +1,8 @@ package ethchain -import "fmt" +import ( + "fmt" +) // Parent error. In case a parent is unknown this error will be thrown // by the block manager @@ -40,3 +42,22 @@ func IsValidationErr(err error) bool { return ok } + +type NonceErr struct { + Message string + Is, Exp uint64 +} + +func (err *NonceErr) Error() string { + return err.Message +} + +func NonceError(is, exp uint64) *NonceErr { + return &NonceErr{Message: fmt.Sprintf("Nonce err. Is %d, expected %d", is, exp), Is: is, Exp: exp} +} + +func IsNonceErr(err error) bool { + _, ok := err.(*NonceErr) + + return ok +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 072fabc0e..02d0345d7 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -157,7 +157,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { hash := block.Hash() if sm.bc.HasBlock(hash) { - fmt.Println("[STATE] We already have this block, ignoring") + //fmt.Println("[STATE] We already have this block, ignoring") return nil } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 91fad2635..fc807c580 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -98,7 +98,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract } }() // Get the sender - sender := block.state.GetAccount(tx.Sender()) + sender := block.state.GetStateObject(tx.Sender()) if sender.Nonce != tx.Nonce { return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) @@ -112,7 +112,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract } // Get the receiver - receiver := block.state.GetAccount(tx.Recipient) + receiver := block.state.GetStateObject(tx.Recipient) sender.Nonce += 1 // Send Tx to self @@ -169,7 +169,6 @@ out: for { select { case tx := <-pool.queueChan: - log.Println("Received new Tx to queue") hash := tx.Hash() foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { return bytes.Compare(tx.Hash(), hash) == 0 @@ -186,11 +185,8 @@ out: log.Println("Validating Tx failed", err) } } else { - log.Println("Transaction ok, adding") - // Call blocking version. At this point it - // doesn't matter since this is a goroutine + // Call blocking version. pool.addTransaction(tx) - log.Println("Added") // Notify the subscribers pool.Ethereum.Reactor().Post("newTx", tx) -- cgit v1.2.3 From d2ab322267e489f47b4b908d060411eb0554a029 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Apr 2014 17:43:48 +0200 Subject: Removed debugging log --- ethchain/transaction_pool.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index fc807c580..8fbe676f5 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,14 +91,16 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { - defer func() { - if r := recover(); r != nil { - log.Println(r) - err = fmt.Errorf("%v", r) - } - }() + /* + defer func() { + if r := recover(); r != nil { + log.Println(r) + err = fmt.Errorf("%v", r) + } + }() + */ // Get the sender - sender := block.state.GetStateObject(tx.Sender()) + sender := block.state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) @@ -112,7 +114,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract } // Get the receiver - receiver := block.state.GetStateObject(tx.Recipient) + receiver := block.state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self -- cgit v1.2.3 From e6a68f0c3ab4987fa5e0e35cac765d40ff305aea Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 1 May 2014 22:13:59 +0200 Subject: Removed debug log --- ethchain/state_object.go | 1 - ethchain/transaction_pool.go | 14 ++++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8e921795d..4ec91d2e0 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -80,7 +80,6 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) c.SetAddr(addr, val) - //c.state.trie.Update(string(addr), string(val.Encode())) } func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 8fbe676f5..72836d6cb 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,14 +91,12 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { - /* - defer func() { - if r := recover(); r != nil { - log.Println(r) - err = fmt.Errorf("%v", r) - } - }() - */ + defer func() { + if r := recover(); r != nil { + log.Println(r) + err = fmt.Errorf("%v", r) + } + }() // Get the sender sender := block.state.GetAccount(tx.Sender()) -- cgit v1.2.3 From 17674fb888d3dc2de081f1c781a227b61c961189 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 1 May 2014 22:14:34 +0200 Subject: Added suicide back in --- ethchain/vm.go | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 0a3690c41..3a3b3447a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -73,10 +73,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } }() - // If the amount of gas supplied is less equal to 0 - if closure.Gas.Cmp(big.NewInt(0)) <= 0 { - // TODO Do something - } + ethutil.Config.Log.Debugf("[VM] Running closure %x\n", closure.object.Address()) // Memory for the current closure mem := &Memory{} @@ -107,9 +104,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } + /* + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } + */ gas := new(big.Int) useGas := func(amount *big.Int) { @@ -163,9 +162,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oLOG: stack.Print() mem.Print() - case oSTOP: // Stop the closure - return closure.Return(nil), nil - // 0x20 range case oADD: require(2) @@ -520,22 +516,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(ret), nil case oSUICIDE: - /* - recAddr := stack.Pop().Bytes() - // Purge all memory - deletedMemory := contract.state.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), "") - - ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) - break out - */ + require(1) + + receiver := vm.state.GetAccount(stack.Pop().Bytes()) + receiver.AddAmount(closure.object.Amount) + + vm.stateManager.manifest.AddObjectChange(receiver) + + closure.object.state.Purge() + + fallthrough + case oSTOP: // Stop the closure + return closure.Return(nil), nil default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) -- cgit v1.2.3 From 70c8656640a861d93ac40181c6c0bdd8faef856b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 2 May 2014 12:11:55 +0200 Subject: Added a KeyPairFromSec function which creates a new keypair based on the given seckey --- ethchain/keypair.go | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'ethchain') diff --git a/ethchain/keypair.go b/ethchain/keypair.go index a5af791d0..0f23bacdf 100644 --- a/ethchain/keypair.go +++ b/ethchain/keypair.go @@ -2,6 +2,7 @@ package ethchain import ( "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" "math/big" ) @@ -14,6 +15,15 @@ type KeyPair struct { state *State } +func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { + pubkey, err := secp256k1.GeneratePubKey(seckey) + if err != nil { + return nil, err + } + + return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil +} + func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} -- cgit v1.2.3 From 1f6df0cd522842095c5ca723d2e11fc6b97b8b6a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 2 May 2014 14:08:54 +0200 Subject: Added receipts for tx creation --- ethchain/transaction.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 421f26c98..e93e610be 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -59,6 +59,10 @@ func (tx *Transaction) IsContract() bool { return tx.contractCreation } +func (tx *Transaction) CreationAddress() []byte { + return tx.Hash()[12:] +} + func (tx *Transaction) Signature(key []byte) []byte { hash := tx.Hash() -- cgit v1.2.3 From 7c91159449c528daa099aec5a3744aa8a6b5a826 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 11:56:25 +0200 Subject: Added different storage notification object --- ethchain/state_manager.go | 2 +- ethchain/state_object.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 02d0345d7..501ec102b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -350,7 +350,7 @@ func (sm *StateManager) notifyChanges() { for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { for addr, value := range mappedObjects { - sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, value.String()) + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } } } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 4ec91d2e0..617646077 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -186,3 +186,9 @@ type CachedStateObject struct { Nonce uint64 Object *StateObject } + +type StorageState struct { + StateAddress []byte + Address []byte + Value *big.Int +} -- cgit v1.2.3 From af6875f4b25145402b20e37ab037d912f54ec968 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 17:14:29 +0200 Subject: Changed to lower case --- ethchain/vm_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 35a7b2e3f..f4a0197ea 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -86,7 +86,7 @@ func TestRun4(t *testing.T) { int32 a = 10 int32 b = 20 if a > b { - int32 c = this.Caller() + int32 c = this.caller() } Exit() `), false) @@ -98,21 +98,21 @@ func TestRun4(t *testing.T) { callerScript, err := mutan.Compile(strings.NewReader(` // Check if there's any cash in the initial store - if store[1000] == 0 { - store[1000] = 10^20 + if this.store[1000] == 0 { + this.store[1000] = 10^20 } - store[1001] = this.Value() * 20 - store[this.Origin()] = store[this.Origin()] + 1000 + this.store[1001] = this.value() * 20 + this.store[this.origin()] = this.store[this.origin()] + 1000 - if store[1001] > 20 { - store[1001] = 10^50 + if this.store[1001] > 20 { + this.store[1001] = 10^50 } int8 ret = 0 int8 arg = 10 - Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) + call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) big t for int8 i = 0; i < 10; i++ { -- cgit v1.2.3 From a0af7de58eeba598c8e967ae9deefb4ee287a1df Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 6 May 2014 17:43:27 +0200 Subject: Optimizations --- ethchain/asm.go | 16 +------ ethchain/types.go | 134 ++++++++++++++++++++++++++++++++++++++++++++++-------- ethchain/vm.go | 30 ++++-------- 3 files changed, 125 insertions(+), 55 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 3194549ba..d46e46af7 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -21,7 +21,7 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("%v", op)) switch op { - case oPUSH: // Push PC+1 on to the stack + case oPUSH32: // Push PC+1 on to the stack pc.Add(pc, ethutil.Big1) data := script[pc.Int64() : pc.Int64()+32] val := ethutil.BigD(data) @@ -36,20 +36,6 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("0x%x", b)) pc.Add(pc, big.NewInt(31)) - case oPUSH20: - pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+20] - val := ethutil.BigD(data) - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() - } - - asm = append(asm, fmt.Sprintf("0x%x", b)) - - pc.Add(pc, big.NewInt(19)) } pc.Add(pc, ethutil.Big1) diff --git a/ethchain/types.go b/ethchain/types.go index 827d4f27f..f9b7a84f5 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -48,8 +48,6 @@ const ( oGASLIMIT = 0x45 // 0x50 range - 'storage' and execution - oPUSH = 0x50 - oPUSH20 = 0x80 oPOP = 0x51 oDUP = 0x52 oSWAP = 0x53 @@ -63,14 +61,48 @@ const ( oPC = 0x5b oMSIZE = 0x5c - // 0x60 range - closures - oCREATE = 0x60 - oCALL = 0x61 - oRETURN = 0x62 + // 0x60 range + oPUSH1 = 0x60 + oPUSH2 = 0x61 + oPUSH3 = 0x62 + oPUSH4 = 0x63 + oPUSH5 = 0x64 + oPUSH6 = 0x65 + oPUSH7 = 0x66 + oPUSH8 = 0x67 + oPUSH9 = 0x68 + oPUSH10 = 0x69 + oPUSH11 = 0x6a + oPUSH12 = 0x6b + oPUSH13 = 0x6c + oPUSH14 = 0x6d + oPUSH15 = 0x6e + oPUSH16 = 0x6f + oPUSH17 = 0x70 + oPUSH18 = 0x71 + oPUSH19 = 0x72 + oPUSH20 = 0x73 + oPUSH21 = 0x74 + oPUSH22 = 0x75 + oPUSH23 = 0x76 + oPUSH24 = 0x77 + oPUSH25 = 0x78 + oPUSH26 = 0x79 + oPUSH27 = 0x7a + oPUSH28 = 0x7b + oPUSH29 = 0x7c + oPUSH30 = 0x7d + oPUSH31 = 0x7e + oPUSH32 = 0x7f + + // 0xf0 range - closures + oCREATE = 0xf0 + oCALL = 0xf2 + oRETURN = 0xf3 // 0x70 range - other - oLOG = 0x70 // XXX Unofficial - oSUICIDE = 0x7f + oLOG = 0xfe // XXX Unofficial + oSUICIDE = 0xff ) // Since the opcodes aren't all in order we can't use a regular slice @@ -119,8 +151,6 @@ var opCodeToString = map[OpCode]string{ oGASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution - oPUSH: "PUSH", - oPOP: "POP", oDUP: "DUP", oSWAP: "SWAP", oMLOAD: "MLOAD", @@ -133,7 +163,41 @@ var opCodeToString = map[OpCode]string{ oPC: "PC", oMSIZE: "MSIZE", - // 0x60 range - closures + // 0x60 range - push + oPUSH1: "PUSH1", + oPUSH2: "PUSH2", + oPUSH3: "PUSH3", + oPUSH4: "PUSH4", + oPUSH5: "PUSH5", + oPUSH6: "PUSH6", + oPUSH7: "PUSH7", + oPUSH8: "PUSH8", + oPUSH9: "PUSH9", + oPUSH10: "PUSH10", + oPUSH11: "PUSH11", + oPUSH12: "PUSH12", + oPUSH13: "PUSH13", + oPUSH14: "PUSH14", + oPUSH15: "PUSH15", + oPUSH16: "PUSH16", + oPUSH17: "PUSH17", + oPUSH18: "PUSH18", + oPUSH19: "PUSH19", + oPUSH20: "PUSH20", + oPUSH21: "PUSH21", + oPUSH22: "PUSH22", + oPUSH23: "PUSH23", + oPUSH24: "PUSH24", + oPUSH25: "PUSH25", + oPUSH26: "PUSH26", + oPUSH27: "PUSH27", + oPUSH28: "PUSH28", + oPUSH29: "PUSH29", + oPUSH30: "PUSH30", + oPUSH31: "PUSH31", + oPUSH32: "PUSH32", + + // 0xf0 range oCREATE: "CREATE", oCALL: "CALL", oRETURN: "RETURN", @@ -193,10 +257,6 @@ var OpCodes = map[string]byte{ "GASLIMIT": 0x45, // 0x50 range - 'storage' and execution - "PUSH": 0x50, - - "PUSH20": 0x80, - "POP": 0x51, "DUP": 0x52, "SWAP": 0x53, @@ -210,13 +270,47 @@ var OpCodes = map[string]byte{ "PC": 0x5b, "MSIZE": 0x5c, - // 0x60 range - closures - "CREATE": 0x60, - "CALL": 0x61, - "RETURN": 0x62, + // 0x70 range - 'push' + "PUSH1": 0x60, + "PUSH2": 0x61, + "PUSH3": 0x62, + "PUSH4": 0x63, + "PUSH5": 0x64, + "PUSH6": 0x65, + "PUSH7": 0x66, + "PUSH8": 0x67, + "PUSH9": 0x68, + "PUSH10": 0x69, + "PUSH11": 0x6a, + "PUSH12": 0x6b, + "PUSH13": 0x6c, + "PUSH14": 0x6d, + "PUSH15": 0x6e, + "PUSH16": 0x6f, + "PUSH17": 0x70, + "PUSH18": 0x71, + "PUSH19": 0x72, + "PUSH20": 0x73, + "PUSH21": 0x74, + "PUSH22": 0x75, + "PUSH23": 0x76, + "PUSH24": 0x77, + "PUSH25": 0x78, + "PUSH26": 0x70, + "PUSH27": 0x7a, + "PUSH28": 0x7b, + "PUSH29": 0x7c, + "PUSH30": 0x7d, + "PUSH31": 0x7e, + "PUSH32": 0x7f, + + // 0xf0 range - closures + "CREATE": 0xf0, + "CALL": 0xf1, + "RETURN": 0xf2, // 0x70 range - other - "LOG": 0x70, + "LOG": 0xfe, "SUICIDE": 0x7f, } diff --git a/ethchain/vm.go b/ethchain/vm.go index 3a3b3447a..bac313006 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -95,6 +95,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro ethutil.Config.Log.Debugf("# op\n") } + fmt.Println(closure.Script) + for { // The base for all big integer arithmetic base := new(big.Int) @@ -104,11 +106,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - /* - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } - */ + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } gas := new(big.Int) useGas := func(amount *big.Int) { @@ -352,27 +352,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // TODO stack.Push(big.NewInt(0)) - // 0x50 range - case oPUSH: // Push PC+1 on to the stack + // 0x50 range + case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: + a := big.NewInt(int64(op) - int64(oPUSH1) + 1) pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, big.NewInt(32)) + data := closure.Gets(pc, a) val := ethutil.BigD(data.Bytes()) - // Push value to stack stack.Push(val) - - pc.Add(pc, big.NewInt(31)) + pc.Add(pc, a.Sub(a, big.NewInt(1))) step++ - case oPUSH20: - pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, big.NewInt(20)) - val := ethutil.BigD(data.Bytes()) - // Push value to stack - stack.Push(val) - - pc.Add(pc, big.NewInt(19)) - step++ case oPOP: require(1) stack.Pop() -- cgit v1.2.3 From 45ce820b111ab2b4e4c7b8d83dd8bebf1bb37bad Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 7 May 2014 11:05:49 +0200 Subject: Implemented value() --- ethchain/state_manager.go | 1 + ethchain/vm.go | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 501ec102b..e8843a89e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -331,6 +331,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, + Value: tx.Value, //Price: tx.GasPrice, }) closure.Call(vm, tx.Data, nil) diff --git a/ethchain/vm.go b/ethchain/vm.go index 3a3b3447a..234f7f72a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" + "log" _ "math" "math/big" ) @@ -53,6 +54,7 @@ type RuntimeVars struct { Time int64 Diff *big.Int TxData []string + Value *big.Int } func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { @@ -324,8 +326,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLER: stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: - // FIXME: Original value of the call, not the current value - stack.Push(closure.Value) + log.Println("Value:", vm.vars.Value) + stack.Push(vm.vars.Value) case oCALLDATALOAD: require(1) offset := stack.Pop().Int64() -- cgit v1.2.3 From 554f4f6f7d8b8bc5332d42631ec9de0d7015eccf Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 14:20:06 +0200 Subject: Fixed disasamble for all pushes --- ethchain/asm.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index d46e46af7..492be0999 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -21,9 +21,10 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("%v", op)) switch op { - case oPUSH32: // Push PC+1 on to the stack + case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+32] + a := int64(op) - int64(oPUSH1) + 1 + data := script[pc.Int64() : pc.Int64()+a] val := ethutil.BigD(data) var b []byte @@ -35,7 +36,7 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("0x%x", b)) - pc.Add(pc, big.NewInt(31)) + pc.Add(pc, big.NewInt(a-1)) } pc.Add(pc, ethutil.Big1) -- cgit v1.2.3 From f0440e85dc306f270666e3aee1fe419b684a2ae8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 14:20:45 +0200 Subject: Removed value from closure. --- ethchain/closure.go | 4 +--- ethchain/state_manager.go | 2 +- ethchain/types.go | 4 ++-- ethchain/vm.go | 26 +++++++++++++++++--------- 4 files changed, 21 insertions(+), 15 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 7e911ad99..0f1e386ae 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -24,20 +24,18 @@ type Closure struct { Gas *big.Int Price *big.Int - Value *big.Int Args []byte } // Create a new closure for the given data items -func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price, val *big.Int) *Closure { +func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects // and we don't want the transaction's values to change. c.Gas = new(big.Int).Set(gas) c.Price = new(big.Int).Set(price) - c.Value = new(big.Int).Set(val) return c } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index e8843a89e..b8a893d15 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -323,7 +323,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans return } - closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) + closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice) vm := NewVm(sm.procState, sm, RuntimeVars{ Origin: account.Address(), BlockNumber: block.BlockInfo().Number, diff --git a/ethchain/types.go b/ethchain/types.go index f9b7a84f5..9964bbe3b 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -97,8 +97,8 @@ const ( // 0xf0 range - closures oCREATE = 0xf0 - oCALL = 0xf2 - oRETURN = 0xf3 + oCALL = 0xf1 + oRETURN = 0xf2 // 0x70 range - other oLOG = 0xfe // XXX Unofficial diff --git a/ethchain/vm.go b/ethchain/vm.go index b4c77c849..ee470c269 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" - "log" _ "math" "math/big" ) @@ -96,7 +95,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } - fmt.Println(closure.Script) for { @@ -320,13 +318,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) case oBALANCE: - stack.Push(closure.Value) + stack.Push(closure.object.Amount) case oORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) case oCALLER: stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: - log.Println("Value:", vm.vars.Value) stack.Push(vm.vars.Value) case oCALLDATALOAD: require(1) @@ -406,13 +403,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) pc = stack.Pop() // Reduce pc by one because of the increment that's at the end of this for loop - pc.Sub(pc, ethutil.Big1) + //pc.Sub(pc, ethutil.Big1) + continue case oJUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos - pc.Sub(pc, ethutil.Big1) + //pc.Sub(pc, ethutil.Big1) + continue } case oPC: stack.Push(pc) @@ -441,8 +440,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro contract.initScript, vm.state, gas, - closure.Price, - value) + closure.Price) // Call the closure and set the return value as // main script. closure.Script, err = closure.Call(vm, nil, hook) @@ -469,10 +467,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro break } + // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) + // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) + fmt.Println("before", contract.Amount) if contract != nil { // Prepay for the gas @@ -482,8 +483,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro gas = new(big.Int).Set(closure.Gas) } closure.Gas.Sub(closure.Gas, gas) + + // Add the value to the state object + contract.AddAmount(value) + // Create a new callable closure - closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price, value) + closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { @@ -496,6 +501,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.stateManager.manifest.AddObjectChange(contract) } + vm.state.SetStateObject(contract) + fmt.Println("after", contract.Amount) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) -- cgit v1.2.3 From d709815106824a3469b5f4152fd32705d7d142d4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 18:26:46 +0200 Subject: Added trans state and removed watch address etc The transient state can be used to test out changes before committing them to the proc state. The transient state is currently being used by the gui to support proper nonce updating without having to wait for a block. This used to be done by a cached state mechanism which can now safely by removed. --- ethchain/state_manager.go | 24 ++++++++---------------- ethchain/transaction_pool.go | 3 +-- 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index b8a893d15..fb5753ab3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -50,6 +50,10 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State + // Transiently state. The trans state isn't ever saved, validated and + // it could be used for setting account nonces without effecting + // the main states. + transState *State manifest *Manifest } @@ -65,6 +69,8 @@ func NewStateManager(ethereum EthManager) *StateManager { manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() + sm.transState = sm.procState.Copy() + return sm } @@ -72,22 +78,8 @@ func (sm *StateManager) ProcState() *State { return sm.procState } -// Watches any given address and puts it in the address state store -func (sm *StateManager) WatchAddr(addr []byte) *CachedStateObject { - //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) - account := sm.procState.GetAccount(addr) - - return sm.stateObjectCache.Add(addr, account) -} - -func (sm *StateManager) GetAddrState(addr []byte) *CachedStateObject { - account := sm.stateObjectCache.Get(addr) - if account == nil { - a := sm.procState.GetAccount(addr) - account = &CachedStateObject{Nonce: a.Nonce, Object: a} - } - - return account +func (sm *StateManager) TransState() *State { + return sm.transState } func (sm *StateManager) BlockChain() *BlockChain { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 72836d6cb..56deae0c6 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -148,8 +148,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) - sender := accountState.Object + sender := pool.Ethereum.StateManager().procState.GetAccount(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 -- cgit v1.2.3 From e8fb965ccbb65807c1f462e8f2ee82508a822b58 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 18:41:45 +0200 Subject: Cleaned up Removed the unneeded address watch mechanism. State manager's transient state should now take care of this. --- ethchain/state_manager.go | 33 +++++++++------------------------ ethchain/state_object.go | 29 ++--------------------------- 2 files changed, 11 insertions(+), 51 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index fb5753ab3..76b02f9ab 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -25,24 +25,16 @@ type EthManager interface { type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex - // Canonical block chain bc *BlockChain - // States for addresses. You can watch any address - // at any given time - stateObjectCache *StateObjectCache - // Stack for processing contracts stack *Stack // non-persistent key/value memory storage mem map[string]*big.Int - + // Proof of work used for validating Pow PoW - + // The ethereum manager interface Ethereum EthManager - - SecondaryBlockProcessor BlockProcessor - // The managed states // Processor state. Anything processed will be applied to this // state @@ -54,19 +46,18 @@ type StateManager struct { // it could be used for setting account nonces without effecting // the main states. transState *State - + // Manifest for keeping changes regarding state objects. See `notify` manifest *Manifest } func NewStateManager(ethereum EthManager) *StateManager { sm := &StateManager{ - stack: NewStack(), - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Ethereum: ethereum, - stateObjectCache: NewStateObjectCache(), - bc: ethereum.BlockChain(), - manifest: NewManifest(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Ethereum: ethereum, + bc: ethereum.BlockChain(), + manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() sm.transState = sm.procState.Copy() @@ -193,12 +184,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Add the block to the chain sm.bc.Add(block) - // If there's a block processor present, pass in the block for further - // processing - if sm.SecondaryBlockProcessor != nil { - sm.SecondaryBlockProcessor.ProcessBlock(block) - } - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 617646077..b38ee4f5c 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -160,33 +160,8 @@ func (c *StateObject) RlpDecode(data []byte) { c.script = decoder.Get(3).Bytes() } -// The cached state and state object cache are helpers which will give you somewhat -// control over the nonce. When creating new transactions you're interested in the 'next' -// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions. -type StateObjectCache struct { - cachedObjects map[string]*CachedStateObject -} - -func NewStateObjectCache() *StateObjectCache { - return &StateObjectCache{cachedObjects: make(map[string]*CachedStateObject)} -} - -func (s *StateObjectCache) Add(addr []byte, object *StateObject) *CachedStateObject { - state := &CachedStateObject{Nonce: object.Nonce, Object: object} - s.cachedObjects[string(addr)] = state - - return state -} - -func (s *StateObjectCache) Get(addr []byte) *CachedStateObject { - return s.cachedObjects[string(addr)] -} - -type CachedStateObject struct { - Nonce uint64 - Object *StateObject -} - +// Storage change object. Used by the manifest for notifying changes to +// the sub channels. type StorageState struct { StateAddress []byte Address []byte -- cgit v1.2.3 From 5a0bae1dae831818740a2f20ca308c4176f5201d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 19:09:36 +0200 Subject: Auto update state changes notifications --- ethchain/closure.go | 6 +++--- ethchain/state.go | 35 ++++------------------------------- ethchain/state_manager.go | 15 +++++++-------- ethchain/state_object.go | 2 +- ethchain/vm.go | 11 +++-------- 5 files changed, 18 insertions(+), 51 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 0f1e386ae..59194e4e8 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -11,7 +11,7 @@ type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte GetMem(*big.Int) *ethutil.Value - SetMem(*big.Int, *ethutil.Value) + SetStore(*big.Int, *ethutil.Value) N() *big.Int } @@ -64,8 +64,8 @@ func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { return ethutil.NewValue(partial) } -func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { - c.object.SetMem(x, val) +func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) { + c.object.SetStorage(x, val) } func (c *Closure) Address() []byte { diff --git a/ethchain/state.go b/ethchain/state.go index 1b5655d4c..5d42c40c0 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -15,11 +15,13 @@ type State struct { trie *ethutil.Trie // Nested states states map[string]*State + + manifest *Manifest } // Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie, states: make(map[string]*State)} + return &State{trie: trie, states: make(map[string]*State), manifest: NewManifest()} } // Resets the trie and all siblings @@ -124,36 +126,6 @@ const ( UnknownTy ) -/* -// Returns the object stored at key and the type stored at key -// Returns nil if nothing is stored -func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { - // Fetch data from the trie - data := s.trie.Get(string(key)) - // Returns the nil type, indicating nothing could be retrieved. - // Anything using this function should check for this ret val - if data == "" { - return nil, NilTy - } - - var typ ObjType - val := ethutil.NewValueFromBytes([]byte(data)) - // Check the length of the retrieved value. - // Len 2 = Account - // Len 3 = Contract - // Other = invalid for now. If other types emerge, add them here - if val.Len() == 2 { - typ = AccountTy - } else if val.Len() == 3 { - typ = ContractTy - } else { - typ = UnknownTy - } - - return val, typ -} -*/ - // Updates any given state object func (s *State) UpdateStateObject(object *StateObject) { addr := object.Address() @@ -163,6 +135,7 @@ func (s *State) UpdateStateObject(object *StateObject) { } s.trie.Update(string(addr), string(object.RlpEncode())) + s.manifest.AddObjectChange(object) } func (s *State) Put(key, object []byte) { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 76b02f9ab..9ab378b67 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -47,7 +47,9 @@ type StateManager struct { // the main states. transState *State // Manifest for keeping changes regarding state objects. See `notify` - manifest *Manifest + // XXX Should we move the manifest to the State object. Benefit: + // * All states can keep their own local changes + //manifest *Manifest } func NewStateManager(ethereum EthManager) *StateManager { @@ -57,7 +59,7 @@ func NewStateManager(ethereum EthManager) *StateManager { Pow: &EasyPow{}, Ethereum: ethereum, bc: ethereum.BlockChain(), - manifest: NewManifest(), + //manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() sm.transState = sm.procState.Copy() @@ -190,7 +192,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { sm.notifyChanges() - sm.manifest.Reset() + sm.procState.manifest.Reset() } } else { fmt.Println("total diff failed") @@ -315,18 +317,15 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(account) - sm.manifest.AddObjectChange(account) - sm.procState.UpdateStateObject(object) - sm.manifest.AddObjectChange(object) } func (sm *StateManager) notifyChanges() { - for addr, stateObject := range sm.manifest.objectChanges { + for addr, stateObject := range sm.procState.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { + for stateObjectAddr, mappedObjects := range sm.procState.manifest.storageChanges { for addr, value := range mappedObjects { sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index b38ee4f5c..7a11a1152 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -77,7 +77,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { +func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) c.SetAddr(addr, val) } diff --git a/ethchain/vm.go b/ethchain/vm.go index ee470c269..584c66611 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -395,10 +395,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oSSTORE: require(2) val, loc := stack.Popn() - closure.SetMem(loc, ethutil.NewValue(val)) + closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest - vm.stateManager.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) + vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) case oJUMP: require(1) pc = stack.Pop() @@ -473,7 +473,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) - fmt.Println("before", contract.Amount) if contract != nil { // Prepay for the gas @@ -497,12 +496,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro //contract.State().Reset() } else { stack.Push(ethutil.BigTrue) - // Notify of the changes - vm.stateManager.manifest.AddObjectChange(contract) } vm.state.SetStateObject(contract) - fmt.Println("after", contract.Amount) mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { @@ -520,8 +516,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - - vm.stateManager.manifest.AddObjectChange(receiver) + vm.state.SetStateObject(receiver) closure.object.state.Purge() -- cgit v1.2.3 From afe83af219c2146e022f6665cf30097b582d3e79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 9 May 2014 16:09:28 +0200 Subject: Moved seeding and moved manifest --- ethchain/state.go | 47 +++++++++++++++++++++++++++++++++++++---------- ethchain/state_manager.go | 33 --------------------------------- 2 files changed, 37 insertions(+), 43 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 5d42c40c0..d02584d67 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -116,16 +116,6 @@ func (s *State) Copy() *State { return NewState(s.trie.Copy()) } -type ObjType byte - -const ( - NilTy ObjType = iota - AccountTy - ContractTy - - UnknownTy -) - // Updates any given state object func (s *State) UpdateStateObject(object *StateObject) { addr := object.Address() @@ -145,3 +135,40 @@ func (s *State) Put(key, object []byte) { func (s *State) Root() interface{} { return s.trie.Root } + +// Object manifest +// +// The object manifest is used to keep changes to the state so we can keep track of the changes +// that occurred during a state transitioning phase. +type Manifest struct { + // XXX These will be handy in the future. Not important for now. + objectAddresses map[string]bool + storageAddresses map[string]map[string]bool + + objectChanges map[string]*StateObject + storageChanges map[string]map[string]*big.Int +} + +func NewManifest() *Manifest { + m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} + m.Reset() + + return m +} + +func (m *Manifest) Reset() { + m.objectChanges = make(map[string]*StateObject) + m.storageChanges = make(map[string]map[string]*big.Int) +} + +func (m *Manifest) AddObjectChange(stateObject *StateObject) { + m.objectChanges[string(stateObject.Address())] = stateObject +} + +func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { + if m.storageChanges[string(stateObject.Address())] == nil { + m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) + } + + m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 9ab378b67..dd21a31b1 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -331,36 +331,3 @@ func (sm *StateManager) notifyChanges() { } } } - -type Manifest struct { - // XXX These will be handy in the future. Not important for now. - objectAddresses map[string]bool - storageAddresses map[string]map[string]bool - - objectChanges map[string]*StateObject - storageChanges map[string]map[string]*big.Int -} - -func NewManifest() *Manifest { - m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} - m.Reset() - - return m -} - -func (m *Manifest) Reset() { - m.objectChanges = make(map[string]*StateObject) - m.storageChanges = make(map[string]map[string]*big.Int) -} - -func (m *Manifest) AddObjectChange(stateObject *StateObject) { - m.objectChanges[string(stateObject.Address())] = stateObject -} - -func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { - if m.storageChanges[string(stateObject.Address())] == nil { - m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) - } - - m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage -} -- cgit v1.2.3 From c03bf14e02fe7f13944b71f5370b1d7bd5978ffe Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 10 May 2014 02:01:09 +0200 Subject: Fixed some tests --- ethchain/vm_test.go | 67 +---------------------------------------------------- 1 file changed, 1 insertion(+), 66 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index f4a0197ea..b919b496f 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -11,71 +11,6 @@ import ( "testing" ) -/* -func TestRun3(t *testing.T) { - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "PUSH", "300", - "PUSH", "0", - "MSTORE", - - "PUSH", "32", - "CALLDATA", - - "PUSH", "64", - "PUSH", "0", - "RETURN", - }) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) - addr := tx.Hash()[12:] - contract := MakeContract(tx, state) - state.UpdateContract(contract) - - callerScript := ethutil.Assemble( - "PUSH", 1337, // Argument - "PUSH", 65, // argument mem offset - "MSTORE", - "PUSH", 64, // ret size - "PUSH", 0, // ret offset - - "PUSH", 32, // arg size - "PUSH", 65, // arg offset - "PUSH", 1000, /// Gas - "PUSH", 0, /// value - "PUSH", addr, // Sender - "CALL", - "PUSH", 64, - "PUSH", 0, - "RETURN", - ) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) - - // Contract addr as test address - account := NewAccount(ContractAddr, big.NewInt(10000000)) - callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) - - vm := NewVm(state, RuntimeVars{ - origin: account.Address(), - blockNumber: 1, - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - // XXX Tx data? Could be just an argument to the closure instead - txData: nil, - }) - ret := callerClosure.Call(vm, nil) - - exp := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 57} - if bytes.Compare(ret, exp) != 0 { - t.Errorf("expected return value to be %v, got %v", exp, ret) - } -}*/ - func TestRun4(t *testing.T) { ethutil.ReadConfig("") @@ -142,7 +77,7 @@ func TestRun4(t *testing.T) { fmt.Println(err) } fmt.Println("account.Amount =", account.Amount) - callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0)) + callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice) vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), -- cgit v1.2.3 From 28357d657b8c46e841fc96a61758652d2617b068 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 13 May 2014 14:43:29 +0200 Subject: Implemented new JS/EthPub methods - getTxCountAt - getPeerCount - getIsMining - getIsListening - getCoinbase --- ethchain/state_manager.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index dd21a31b1..bc8b46831 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -20,6 +20,9 @@ type EthManager interface { TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) Reactor() *ethutil.ReactorEngine + PeerCount() int + IsMining() bool + IsListening() bool } type StateManager struct { -- cgit v1.2.3 From a4883a029f3585d7e263661c30cbd147f3d5d655 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 13 May 2014 17:51:33 +0200 Subject: Propagate back to network --- ethchain/state_manager.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index bc8b46831..8f1eb1ce5 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -197,6 +197,9 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { sm.procState.manifest.Reset() } + + sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + } else { fmt.Println("total diff failed") } -- cgit v1.2.3 From 0c1f732c64b7c1380b2f0422ee82d462ea88dc03 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 11:29:57 +0200 Subject: Do not queue messages if the peer isn't connected (e.g. timing out) --- ethchain/state_manager.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8f1eb1ce5..f830f2022 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -199,7 +199,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { } sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) - } else { fmt.Println("total diff failed") } -- cgit v1.2.3 From f4fa0d48cb10f925908062357be965c54370cba9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 13:54:40 +0200 Subject: Moved keyring to ethutil & removed old methods. Implements #20 --- ethchain/keypair.go | 87 ----------------------------------------------------- 1 file changed, 87 deletions(-) delete mode 100644 ethchain/keypair.go (limited to 'ethchain') diff --git a/ethchain/keypair.go b/ethchain/keypair.go deleted file mode 100644 index 0f23bacdf..000000000 --- a/ethchain/keypair.go +++ /dev/null @@ -1,87 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/eth-go/ethutil" - "github.com/obscuren/secp256k1-go" - "math/big" -) - -type KeyPair struct { - PrivateKey []byte - PublicKey []byte - - // The associated account - account *StateObject - state *State -} - -func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { - pubkey, err := secp256k1.GeneratePubKey(seckey) - if err != nil { - return nil, err - } - - return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil -} - -func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { - keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} - - return keyPair -} - -func (k *KeyPair) Address() []byte { - return ethutil.Sha3Bin(k.PublicKey[1:])[12:] -} - -func (k *KeyPair) Account() *StateObject { - if k.account == nil { - k.account = k.state.GetAccount(k.Address()) - } - - return k.account -} - -// Create transaction, creates a new and signed transaction, ready for processing -func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { - /* TODO - tx := NewTransaction(receiver, value, data) - tx.Nonce = k.account.Nonce - - // Sign the transaction with the private key in this key chain - tx.Sign(k.PrivateKey) - - return tx - */ - return nil -} - -func (k *KeyPair) RlpEncode() []byte { - return ethutil.EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() -} - -type KeyRing struct { - keys []*KeyPair -} - -func (k *KeyRing) Add(pair *KeyPair) { - k.keys = append(k.keys, pair) -} - -// The public "singleton" keyring -var keyRing *KeyRing - -func GetKeyRing(state *State) *KeyRing { - if keyRing == nil { - keyRing = &KeyRing{} - - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - it := ethutil.NewValueFromBytes(data).NewIterator() - for it.Next() { - v := it.Value() - keyRing.Add(NewKeyPairFromValue(v)) - } - } - - return keyRing -} -- cgit v1.2.3 From 98a631b5563b8a87c3fc83f14256087251926a61 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 16:29:34 +0200 Subject: Remove any invalid transactions after block processing --- ethchain/state_manager.go | 2 ++ ethchain/transaction_pool.go | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f830f2022..57d56469b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -199,6 +199,8 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { } sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + + sm.Ethereum.TxPool().RemoveInvalid(sm.procState) } else { fmt.Println("total diff failed") } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 56deae0c6..6c0282dc6 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -210,9 +210,9 @@ func (pool *TxPool) CurrentTransactions() []*Transaction { 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 - } + tx := e.Value.(*Transaction) + + txList[i] = tx i++ } @@ -220,6 +220,17 @@ func (pool *TxPool) CurrentTransactions() []*Transaction { return txList } +func (pool *TxPool) RemoveInvalid(state *State) { + for e := pool.pool.Front(); e != nil; e = e.Next() { + tx := e.Value.(*Transaction) + sender := state.GetAccount(tx.Sender()) + err := pool.ValidateTransaction(tx) + if err != nil || sender.Nonce != tx.Nonce { + pool.pool.Remove(e) + } + } +} + func (pool *TxPool) Flush() []*Transaction { txList := pool.CurrentTransactions() -- cgit v1.2.3 From 7bf2ae0b116fff0fede5b1455c5fda20caf98252 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 15 May 2014 14:05:15 +0200 Subject: Removed old tx pool notification system. Fixes #19 --- ethchain/block_chain.go | 3 ++- ethchain/transaction_pool.go | 19 +++---------------- 2 files changed, 5 insertions(+), 17 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2be4cd92b..11fbc7795 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,7 +260,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) @@ -268,6 +268,7 @@ func AddTestNetFunds(block *Block) { account.Amount = ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } + log.Printf("%x\n", block.RlpEncode()) } func (bc *BlockChain) setLastBlock() { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 6c0282dc6..21ce8cdc1 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -133,7 +133,8 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) - pool.notifySubscribers(TxPost, tx) + // Notify all subscribers + pool.Ethereum.Reactor().Post("newTx:post", tx) return } @@ -188,10 +189,7 @@ out: pool.addTransaction(tx) // Notify the subscribers - pool.Ethereum.Reactor().Post("newTx", tx) - - // Notify the subscribers - pool.notifySubscribers(TxPre, tx) + pool.Ethereum.Reactor().Post("newTx:pre", tx) } case <-pool.quit: break out @@ -252,14 +250,3 @@ func (pool *TxPool) Stop() { log.Println("[TXP] Stopped") } - -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 From f95993e326567555d0a2e1f96974c34e7b3a214f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 15 May 2014 14:54:07 +0200 Subject: M --- ethchain/block_chain.go | 2 +- ethchain/state_manager.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 11fbc7795..1848b9ddb 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,7 +260,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 57d56469b..143d9d647 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -193,11 +193,11 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) - sm.notifyChanges() - sm.procState.manifest.Reset() } + sm.notifyChanges() + sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) sm.Ethereum.TxPool().RemoveInvalid(sm.procState) -- cgit v1.2.3 From 8730dfdcc2e2b40410a57385e4864d15f2f0336b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 17 May 2014 14:07:52 +0200 Subject: Changed how changes are being applied to states --- ethchain/block_chain.go | 4 +- ethchain/block_chain_test.go | 17 +++++-- ethchain/state_manager.go | 109 ++++++++++++++++++++----------------------- ethchain/transaction_pool.go | 3 +- ethchain/vm_test.go | 2 +- 5 files changed, 69 insertions(+), 66 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 1848b9ddb..6c3b15a6a 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -280,7 +280,7 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = info.Number - log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) } else { AddTestNetFunds(bc.genesisBlock) @@ -295,7 +295,7 @@ func (bc *BlockChain) setLastBlock() { // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - log.Printf("Last block: %x\n", bc.CurrentBlock.Hash()) + ethutil.Config.Log.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 30eb62266..4e4bb9dd4 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -18,6 +18,18 @@ type TestManager struct { Blocks []*Block } +func (s *TestManager) IsListening() bool { + return false +} + +func (s *TestManager) IsMining() bool { + return false +} + +func (s *TestManager) PeerCount() int { + return 0 +} + func (s *TestManager) BlockChain() *BlockChain { return s.blockChain } @@ -38,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { } func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest") + ethutil.ReadConfig(".ethtest", ethutil.LogStd) db, err := ethdb.NewMemDatabase() if err != nil { @@ -62,8 +74,7 @@ func NewTestManager() *TestManager { func (tm *TestManager) AddFakeBlock(blk []byte) error { block := NewBlockFromBytes(blk) tm.Blocks = append(tm.Blocks, block) - tm.StateManager().PrepareDefault(block) - err := tm.StateManager().ProcessBlock(block, false) + err := tm.StateManager().ProcessBlock(tm.StateManager().CurrentState(), block, false) return err } func (tm *TestManager) CreateChain1() error { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 143d9d647..28570775b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -39,20 +39,13 @@ type StateManager struct { // The ethereum manager interface Ethereum EthManager // The managed states - // Processor state. Anything processed will be applied to this - // state - procState *State - // Comparative state it used for comparing and validating end - // results - compState *State // Transiently state. The trans state isn't ever saved, validated and // it could be used for setting account nonces without effecting // the main states. transState *State - // Manifest for keeping changes regarding state objects. See `notify` - // XXX Should we move the manifest to the State object. Benefit: - // * All states can keep their own local changes - //manifest *Manifest + // Mining state. The mining state is used purely and solely by the mining + // operation. + miningState *State } func NewStateManager(ethereum EthManager) *StateManager { @@ -62,30 +55,39 @@ func NewStateManager(ethereum EthManager) *StateManager { Pow: &EasyPow{}, Ethereum: ethereum, bc: ethereum.BlockChain(), - //manifest: NewManifest(), } - sm.procState = ethereum.BlockChain().CurrentBlock.State() - sm.transState = sm.procState.Copy() + sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy() + sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy() return sm } -func (sm *StateManager) ProcState() *State { - return sm.procState +func (sm *StateManager) CurrentState() *State { + return sm.Ethereum.BlockChain().CurrentBlock.State() } func (sm *StateManager) TransState() *State { return sm.transState } +func (sm *StateManager) MiningState() *State { + return sm.miningState +} + +func (sm *StateManager) NewMiningState() *State { + sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy() + + return sm.miningState +} + func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { - contract := MakeContract(tx, sm.procState) +func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) if contract != nil { - sm.procState.states[string(tx.Hash()[12:])] = contract.state + state.states[string(tx.Hash()[12:])] = contract.state return contract } @@ -95,7 +97,7 @@ func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. -func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { +func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { // If there's no recipient, it's a contract @@ -104,9 +106,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { if tx.IsContract() { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) if err == nil { - contract := sm.MakeContract(tx) + contract := sm.MakeContract(state, tx) if contract != nil { - sm.EvalScript(contract.Init(), contract, tx, block) + sm.EvalScript(state, contract.Init(), contract, tx, block) } else { ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } @@ -115,9 +117,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := sm.procState.GetContract(tx.Recipient) + contract := state.GetContract(tx.Recipient) if err == nil && len(contract.Script()) > 0 { - sm.EvalScript(contract.Script(), contract, tx, block) + sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { ethutil.Config.Log.Infoln("[STATE] process:", err) } @@ -125,20 +127,8 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { } } -// The prepare function, prepares the state manager for the next -// "ProcessBlock" action. -func (sm *StateManager) Prepare(processor *State, comparative *State) { - sm.compState = comparative - sm.procState = processor -} - -// Default prepare function -func (sm *StateManager) PrepareDefault(block *Block) { - sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) -} - // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { +func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -153,7 +143,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) 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 sm.bc.CurrentBlock.Undo() + defer state.Reset() // 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 @@ -162,7 +152,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { } // Process the transactions on to current block - sm.ApplyTransactions(sm.bc.CurrentBlock, block.Transactions()) + sm.ApplyTransactions(state, sm.bc.CurrentBlock, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -172,19 +162,20 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err := sm.AccumelateRewards(block); err != nil { + if err := sm.AccumelateRewards(state, block); err != nil { fmt.Println("[SM] Error accumulating reward", err) return err } - if !sm.compState.Cmp(sm.procState) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) + //if !sm.compState.Cmp(state) { + if !block.State().Cmp(state) { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, state.trie.Root) } // Calculate the new total difficulty and sync back to the db if sm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - sm.procState.Sync() + state.Sync() // Add the block to the chain sm.bc.Add(block) @@ -193,14 +184,14 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) - sm.procState.manifest.Reset() + state.manifest.Reset() } - sm.notifyChanges() + sm.notifyChanges(state) sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) - sm.Ethereum.TxPool().RemoveInvalid(sm.procState) + sm.Ethereum.TxPool().RemoveInvalid(state) } else { fmt.Println("total diff failed") } @@ -276,21 +267,21 @@ func CalculateUncleReward(block *Block) *big.Int { return UncleReward } -func (sm *StateManager) AccumelateRewards(block *Block) error { +func (sm *StateManager) AccumelateRewards(state *State, block *Block) error { // Get the account associated with the coinbase - account := sm.procState.GetAccount(block.Coinbase) + account := state.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address account.AddAmount(CalculateBlockReward(block, len(block.Uncles))) addr := make([]byte, len(block.Coinbase)) copy(addr, block.Coinbase) - sm.procState.UpdateStateObject(account) + state.UpdateStateObject(account) for _, uncle := range block.Uncles { - uncleAccount := sm.procState.GetAccount(uncle.Coinbase) + uncleAccount := state.GetAccount(uncle.Coinbase) uncleAccount.AddAmount(CalculateUncleReward(uncle)) - sm.procState.UpdateStateObject(uncleAccount) + state.UpdateStateObject(uncleAccount) } return nil @@ -300,8 +291,8 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { - account := sm.procState.GetAccount(tx.Sender()) +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) { + account := state.GetAccount(tx.Sender()) err := account.ConvertGas(tx.Gas, tx.GasPrice) if err != nil { @@ -309,8 +300,8 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans return } - closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice) - vm := NewVm(sm.procState, sm, RuntimeVars{ + closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) + vm := NewVm(state, sm, RuntimeVars{ Origin: account.Address(), BlockNumber: block.BlockInfo().Number, PrevHash: block.PrevHash, @@ -323,16 +314,16 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans closure.Call(vm, tx.Data, nil) // Update the account (refunds) - sm.procState.UpdateStateObject(account) - sm.procState.UpdateStateObject(object) + state.UpdateStateObject(account) + state.UpdateStateObject(object) } -func (sm *StateManager) notifyChanges() { - for addr, stateObject := range sm.procState.manifest.objectChanges { +func (sm *StateManager) notifyChanges(state *State) { + for addr, stateObject := range state.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range sm.procState.manifest.storageChanges { + for stateObjectAddr, mappedObjects := range state.manifest.storageChanges { for addr, value := range mappedObjects { sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 21ce8cdc1..da77f32b3 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -149,7 +149,8 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) + //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) + sender := pool.Ethereum.StateManager().CurrentState().GetAccount(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 diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index b919b496f..5d03ccf0c 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -12,7 +12,7 @@ import ( ) func TestRun4(t *testing.T) { - ethutil.ReadConfig("") + ethutil.ReadConfig("", ethutil.LogStd) db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) -- cgit v1.2.3 From bd48690f63d07d9a0568f0d8092006ebaa12af5f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 19 May 2014 11:25:27 +0200 Subject: Testing different mining state --- ethchain/dagger.go | 4 ++-- ethchain/transaction_pool.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 9d2df4069..18e53d3a8 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -29,14 +29,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - log.Println("[POW] Received reactor event; breaking out.") + ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") return nil default: i++ if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - log.Println("[POW] Hashing @", int64(hashes), "khash") + ethutil.Config.Log.Infoln("[POW] Hashing @", int64(hashes), "khash") } sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index da77f32b3..796ec7c9a 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -131,7 +131,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract block.state.UpdateStateObject(sender) - log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) // Notify all subscribers pool.Ethereum.Reactor().Post("newTx:post", tx) -- cgit v1.2.3 From b8034f4d9ed7eea29a219a2d894ae22041a906a7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 19 May 2014 12:14:04 +0200 Subject: Increment nonce in the public api --- ethchain/vm.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 584c66611..6579830ec 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -95,7 +95,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } - fmt.Println(closure.Script) for { // The base for all big integer arithmetic -- cgit v1.2.3 From fd19142c0db3d2b6651989f5389944f3e211d84f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 11:19:07 +0200 Subject: No longer store script directly in the state tree --- ethchain/block.go | 2 +- ethchain/block_chain.go | 2 +- ethchain/state.go | 49 +++++++++++++------------------------------ ethchain/state_manager.go | 5 +++-- ethchain/state_object.go | 21 +++++++++++-------- ethchain/state_object_test.go | 25 ++++++++++++++++++++++ ethchain/transaction.go | 2 +- ethchain/vm.go | 2 +- 8 files changed, 59 insertions(+), 49 deletions(-) create mode 100644 ethchain/state_object_test.go (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index aac50ccb1..ca84dc19c 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -122,7 +122,7 @@ func (block *Block) Transactions() []*Transaction { } func (block *Block) PayFee(addr []byte, fee *big.Int) bool { - contract := block.state.GetContract(addr) + contract := block.state.GetStateObject(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) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6c3b15a6a..99e17727c 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,7 +260,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) diff --git a/ethchain/state.go b/ethchain/state.go index d02584d67..63c4a32a6 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -49,28 +49,6 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } -// XXX Deprecated -func (s *State) GetContract(addr []byte) *StateObject { - data := s.trie.Get(string(addr)) - if data == "" { - return nil - } - - // build contract - contract := NewStateObjectFromBytes(addr, []byte(data)) - - // Check if there's a cached state for this contract - cachedState := s.states[string(addr)] - if cachedState != nil { - contract.state = cachedState - } else { - // If it isn't cached, cache the state - s.states[string(addr)] = contract.state - } - - return contract -} - func (s *State) GetStateObject(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { @@ -91,6 +69,21 @@ func (s *State) GetStateObject(addr []byte) *StateObject { return stateObject } +// Updates any given state object +func (s *State) UpdateStateObject(object *StateObject) { + addr := object.Address() + + if object.state != nil { + s.states[string(addr)] = object.state + } + + ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) + + s.trie.Update(string(addr), string(object.RlpEncode())) + + s.manifest.AddObjectChange(object) +} + func (s *State) SetStateObject(stateObject *StateObject) { s.states[string(stateObject.address)] = stateObject.state @@ -116,18 +109,6 @@ func (s *State) Copy() *State { return NewState(s.trie.Copy()) } -// Updates any given state object -func (s *State) UpdateStateObject(object *StateObject) { - addr := object.Address() - - if object.state != nil { - s.states[string(addr)] = object.state - } - - s.trie.Update(string(addr), string(object.RlpEncode())) - s.manifest.AddObjectChange(object) -} - func (s *State) Put(key, object []byte) { s.trie.Update(string(key), string(object)) } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 28570775b..098263e8a 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -87,7 +87,7 @@ func (sm *StateManager) BlockChain() *BlockChain { func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { contract := MakeContract(tx, state) if contract != nil { - state.states[string(tx.Hash()[12:])] = contract.state + state.states[string(tx.CreationAddress())] = contract.state return contract } @@ -117,7 +117,8 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := state.GetContract(tx.Recipient) + contract := state.GetStateObject(tx.Recipient) + ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) if err == nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 7a11a1152..cb6211ea6 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -10,8 +10,9 @@ type StateObject struct { // Address of the object address []byte // Shared attributes - Amount *big.Int - Nonce uint64 + Amount *big.Int + ScriptHash []byte + Nonce uint64 // Contract related attributes state *State script []byte @@ -22,12 +23,10 @@ type StateObject struct { func MakeContract(tx *Transaction, state *State) *StateObject { // Create contract if there's no recipient if tx.IsContract() { - // FIXME - addr := tx.Hash()[12:] + addr := tx.CreationAddress() value := tx.Value - contract := NewContract(addr, value, []byte("")) - state.UpdateStateObject(contract) + contract := NewContract(addr, value, ZeroHash256) contract.script = tx.Data contract.initScript = tx.Init @@ -146,9 +145,10 @@ func (c *StateObject) RlpEncode() []byte { if c.state != nil { root = c.state.trie.Root } else { - root = nil + root = ZeroHash256 } - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, c.script}) + + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) } func (c *StateObject) RlpDecode(data []byte) { @@ -157,7 +157,10 @@ func (c *StateObject) RlpDecode(data []byte) { c.Amount = decoder.Get(0).BigInt() c.Nonce = decoder.Get(1).Uint() c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) - c.script = decoder.Get(3).Bytes() + + c.ScriptHash = decoder.Get(3).Bytes() + + c.script, _ = ethutil.Config.Db.Get(c.ScriptHash) } // Storage change object. Used by the manifest for notifying changes to diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go new file mode 100644 index 000000000..1db01a537 --- /dev/null +++ b/ethchain/state_object_test.go @@ -0,0 +1,25 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "testing" +) + +func TestSync(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd) + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + + contract.script = []byte{42} + + state.UpdateStateObject(contract) + state.Sync() + + object := state.GetStateObject([]byte("aa")) + fmt.Printf("%x\n", object.Script()) +} diff --git a/ethchain/transaction.go b/ethchain/transaction.go index e93e610be..8ea4704cb 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -60,7 +60,7 @@ func (tx *Transaction) IsContract() bool { } func (tx *Transaction) CreationAddress() []byte { - return tx.Hash()[12:] + return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } func (tx *Transaction) Signature(key []byte) []byte { diff --git a/ethchain/vm.go b/ethchain/vm.go index 6579830ec..e732d22a4 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -471,7 +471,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro args := mem.Get(inOffset.Int64(), inSize.Int64()) // Fetch the contract which will serve as the closure body - contract := vm.state.GetContract(addr.Bytes()) + contract := vm.state.GetStateObject(addr.Bytes()) if contract != nil { // Prepay for the gas -- cgit v1.2.3 From 12f30e6220354c4a8b08ecf41bb53444143f3660 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 20 May 2014 11:50:34 +0200 Subject: Refactored a lot of the chain catchup/reorg. --- ethchain/block_chain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6c3b15a6a..2ce0f90a6 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -127,7 +127,6 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] We have found the common parent block, breaking") break } - log.Println("Checking incoming blocks:") chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } @@ -182,6 +181,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { // XXX Why are we resetting? This is the block chain, it has nothing to do with states //bc.Ethereum.StateManager().PrepareDefault(returnTo) + // Manually reset the last sync block err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { return err -- cgit v1.2.3 From 2450398862e8ac55b39dd88a3af169985e1727f3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 12:19:21 +0200 Subject: Added Maran to premine --- ethchain/block_chain.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 99e17727c..9926354bd 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,9 +260,8 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { - //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) account := block.state.GetAccount(codedAddr) account.Amount = ethutil.BigPow(2, 200) -- cgit v1.2.3 From 530ab6b8fc9e7ea2b784dbd3f16d0272d227f6d6 Mon Sep 17 00:00:00 2001 From: Nick Savers Date: Tue, 20 May 2014 13:02:37 +0200 Subject: Re-arranged transaction RLP encoding... According to latest Yellow Paper specs and conform other clients https://github.com/ethereum/latexpaper/commit/4794642e51ac1884e5e1af8a18ebc83aca115d64 --- ethchain/transaction.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 8ea4704cb..c18ff7c53 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -109,10 +109,10 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } -// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] -// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] +// [ NONCE, GASPRICE, GAS, TO, VALUE, DATA, V, R, S ] +// [ NONCE, GASPRICE, GAS, 0, VALUE, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} if tx.contractCreation { data = append(data, tx.Init) @@ -135,10 +135,10 @@ func (tx *Transaction) RlpDecode(data []byte) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() - tx.Value = decoder.Get(1).BigInt() - tx.GasPrice = decoder.Get(2).BigInt() - tx.Gas = decoder.Get(3).BigInt() - tx.Recipient = decoder.Get(4).Bytes() + tx.GasPrice = decoder.Get(1).BigInt() + tx.Gas = decoder.Get(2).BigInt() + tx.Recipient = decoder.Get(3).Bytes() + tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() // If the list is of length 10 it's a contract creation tx -- cgit v1.2.3 From 378815ee62b21cec60aceeafc7bc8a2a479290b5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 13:06:47 +0200 Subject: Rearranged according to YP --- ethchain/transaction.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 8ea4704cb..bd7a0e424 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -109,10 +109,8 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } -// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] -// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} if tx.contractCreation { data = append(data, tx.Init) @@ -135,10 +133,10 @@ func (tx *Transaction) RlpDecode(data []byte) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() - tx.Value = decoder.Get(1).BigInt() - tx.GasPrice = decoder.Get(2).BigInt() - tx.Gas = decoder.Get(3).BigInt() - tx.Recipient = decoder.Get(4).Bytes() + tx.GasPrice = decoder.Get(1).BigInt() + tx.Gas = decoder.Get(2).BigInt() + tx.Recipient = decoder.Get(3).Bytes() + tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() // If the list is of length 10 it's a contract creation tx -- cgit v1.2.3 From 45b810450fc75ef47964b1b53197114d1bf6db3d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 13:09:44 +0200 Subject: ... --- ethchain/transaction.go | 5 ----- 1 file changed, 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index a36286e86..bd7a0e424 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -109,11 +109,6 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } -<<<<<<< HEAD -======= -// [ NONCE, GASPRICE, GAS, TO, VALUE, DATA, V, R, S ] -// [ NONCE, GASPRICE, GAS, 0, VALUE, CODE, INIT, V, R, S ] ->>>>>>> 38b4dc2cdf23380532a25240760273dd07b9dff6 func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} -- cgit v1.2.3 From 6a31d55b2e2d95dd64e3d56b0c12e9ffb7c1c373 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 13:29:21 +0200 Subject: added roman --- ethchain/block_chain.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 457aed714..eb25bd3f4 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -261,6 +261,7 @@ func AddTestNetFunds(block *Block) { "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // Roman } { codedAddr := ethutil.FromHex(addr) account := block.state.GetAccount(codedAddr) -- cgit v1.2.3 From 7d3e99a2abcef6011714a7e6e515aa8e2bc738cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 14:29:52 +0200 Subject: Fixed genesis and block data --- ethchain/block.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++------ ethchain/genesis.go | 17 +++++++++---- 2 files changed, 74 insertions(+), 12 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index ca84dc19c..beb2bc14c 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -40,6 +40,14 @@ type Block struct { Difficulty *big.Int // Creation time Time int64 + // The block number + Number *big.Int + // Minimum Gas Price + MinGasPrice *big.Int + // Gas limit + GasLimit *big.Int + // Gas used + GasUsed *big.Int // Extra data Extra string // Block Nonce for verification @@ -233,9 +241,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.state = NewState(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() + block.Number = header.Get(6).BigInt() + block.MinGasPrice = header.Get(7).BigInt() + block.GasLimit = header.Get(8).BigInt() + block.GasUsed = header.Get(9).BigInt() + block.Time = int64(header.Get(10).BigInt().Uint64()) + block.Extra = header.Get(11).Str() + block.Nonce = header.Get(12).Bytes() block.contractStates = make(map[string]*ethutil.Trie) // Tx list might be empty if this is an uncle. Uncles only have their @@ -270,16 +282,51 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.state = NewState(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() + block.Number = header.Get(6).BigInt() + block.MinGasPrice = header.Get(7).BigInt() + block.GasLimit = header.Get(8).BigInt() + block.GasUsed = header.Get(9).BigInt() + block.Time = int64(header.Get(10).BigInt().Uint64()) + block.Extra = header.Get(11).Str() + block.Nonce = header.Get(12).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\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) + //return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) + return fmt.Sprintf(` + Block(%x): + PrevHash: %x + UncleSha: %x + Coinbase: %x + Root: %x + TxSha: %x + Difficulty: %v + Number: %v + MinGas: %v + MaxLimit: %v + GasUsed: %v + Time: %v + Extra: %v + Nonce: %x +`, + block.Hash(), + block.PrevHash, + block.UncleSha, + block.Coinbase, + block.state.trie.Root, + block.TxSha, + block.Difficulty, + block.Number, + block.MinGasPrice, + block.GasLimit, + block.GasUsed, + block.Time, + block.Extra, + block.Nonce) } + func (block *Block) GetRoot() interface{} { return block.state.trie.Root } @@ -299,6 +346,14 @@ func (block *Block) header() []interface{} { block.TxSha, // Current block Difficulty block.Difficulty, + // The block number + block.Number, + // Block minimum gas price + block.MinGasPrice, + // Block upper gas bound + block.GasLimit, + // Block gas used + block.GasUsed, // Time the block was found? block.Time, // Extra data diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 935978a69..7e145ef53 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -15,7 +15,6 @@ var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) var GenesisHeader = []interface{}{ // Previous hash (none) - //"", ZeroHash256, // Sha of uncles ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), @@ -23,15 +22,23 @@ var GenesisHeader = []interface{}{ ZeroHash160, // Root state "", - // Sha of transactions //EmptyShaList, - ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + ZeroHash256, + //ethutil.Sha3Bin(ethutil.Encode(ZeroHash256)), // Difficulty ethutil.BigPow(2, 22), + // Number + ethutil.Big0, + // Block minimum gas price + ethutil.Big0, + // Block upper gas bound + big.NewInt(1000000), + // Block gas used + ethutil.Big0, // Time - int64(0), + ethutil.Big0, // Extra - "", + nil, // Nonce ethutil.Sha3Bin(big.NewInt(42).Bytes()), } -- cgit v1.2.3 From f5d441473499428964b75924845cf0c7bcaaa5ca Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 20 May 2014 14:41:35 +0200 Subject: Fix notification when processing block that didn't have this client as origin --- ethchain/state_manager.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 098263e8a..c7c6857d8 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -180,6 +180,7 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) // Add the block to the chain sm.bc.Add(block) + sm.notifyChanges(state) ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { @@ -188,8 +189,6 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) state.manifest.Reset() } - sm.notifyChanges(state) - sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) sm.Ethereum.TxPool().RemoveInvalid(state) -- cgit v1.2.3 From 2bd377a3de54652923558b63cc8756531269e36e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 15:02:46 +0200 Subject: Changed transaction hash for poc 5 --- ethchain/block.go | 76 ++++++++++++++++++++++++++----------------------- ethchain/block_chain.go | 16 +++++++++++ ethchain/genesis.go | 3 +- 3 files changed, 57 insertions(+), 38 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index beb2bc14c..c6c2c1226 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" + "strconv" "time" ) @@ -214,7 +215,12 @@ func (block *Block) SetUncles(uncles []*Block) { func (block *Block) SetTransactions(txs []*Transaction) { block.transactions = txs - block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs())) + trie := ethutil.NewTrie(ethutil.Config.Db, "") + for i, tx := range txs { + trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) + } + + block.TxSha = trie.Root.([]byte) } func (block *Block) Value() *ethutil.Value { @@ -293,45 +299,10 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { return block } -func (block *Block) String() string { - //return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) - return fmt.Sprintf(` - Block(%x): - PrevHash: %x - UncleSha: %x - Coinbase: %x - Root: %x - TxSha: %x - Difficulty: %v - Number: %v - MinGas: %v - MaxLimit: %v - GasUsed: %v - Time: %v - Extra: %v - Nonce: %x -`, - block.Hash(), - block.PrevHash, - block.UncleSha, - block.Coinbase, - block.state.trie.Root, - block.TxSha, - block.Difficulty, - block.Number, - block.MinGasPrice, - block.GasLimit, - block.GasUsed, - block.Time, - block.Extra, - block.Nonce) -} - func (block *Block) GetRoot() interface{} { return block.state.trie.Root } -//////////// UNEXPORTED ///////////////// func (block *Block) header() []interface{} { return []interface{}{ // Sha of the previous block @@ -362,3 +333,36 @@ func (block *Block) header() []interface{} { block.Nonce, } } + +func (block *Block) String() string { + return fmt.Sprintf(` + BLOCK(%x): + PrevHash: %x + UncleSha: %x + Coinbase: %x + Root: %x + TxSha: %x + Difficulty: %v + Number: %v + MinGas: %v + MaxLimit: %v + GasUsed: %v + Time: %v + Extra: %v + Nonce: %x +`, + block.Hash(), + block.PrevHash, + block.UncleSha, + block.Coinbase, + block.state.trie.Root, + block.TxSha, + block.Difficulty, + block.Number, + block.MinGasPrice, + block.GasLimit, + block.GasUsed, + block.Time, + block.Extra, + block.Nonce) +} diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index eb25bd3f4..2865336fb 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -70,6 +70,22 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { diff.Mul(diff, mul) diff.Add(diff, bc.CurrentBlock.Difficulty) block.Difficulty = diff + + block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) + + // max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024) + base := new(big.Int) + base2 := new(big.Int) + parentGL := bc.CurrentBlock.GasLimit + parentUsed := bc.CurrentBlock.GasUsed + + base.Mul(parentGL, big.NewInt(1024-1)) + base2.Mul(parentUsed, big.NewInt(6)) + base2.Div(base2, big.NewInt(5)) + base.Add(base, base2) + base.Div(base, big.NewInt(1024)) + + block.GasLimit = ethutil.BigMax(big.NewInt(10000), base) } return block diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 7e145ef53..b8f9f865a 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -22,9 +22,8 @@ var GenesisHeader = []interface{}{ ZeroHash160, // Root state "", - //EmptyShaList, + // tx sha ZeroHash256, - //ethutil.Sha3Bin(ethutil.Encode(ZeroHash256)), // Difficulty ethutil.BigPow(2, 22), // Number -- cgit v1.2.3 From ad51c85e5d67ca2e64e95786e79d062c4467b4c1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 19:19:53 +0200 Subject: Fixed crash --- ethchain/block.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index c6c2c1226..bdb243286 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -99,6 +99,9 @@ func CreateBlock(root interface{}, Time: time.Now().Unix(), Extra: extra, UncleSha: EmptyShaList, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), contractStates: make(map[string]*ethutil.Trie), } block.SetTransactions(txes) @@ -220,7 +223,7 @@ func (block *Block) SetTransactions(txs []*Transaction) { trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) } - block.TxSha = trie.Root.([]byte) + block.TxSha = []byte(trie.Root.(string)) } func (block *Block) Value() *ethutil.Value { -- cgit v1.2.3 From 3b38df085ebebd68f1bf76c11c8b87ae75f29fe2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 22:04:47 +0200 Subject: Fixed casting issue --- ethchain/block.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index bdb243286..24ff5a32f 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -223,7 +223,15 @@ func (block *Block) SetTransactions(txs []*Transaction) { trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) } - block.TxSha = []byte(trie.Root.(string)) + switch trie.Root.(type) { + case string: + block.TxSha = []byte(trie.Root.(string)) + case []byte: + block.TxSha = trie.Root.([]byte) + default: + panic(fmt.Sprintf("invalid root type %T", trie.Root)) + } + } func (block *Block) Value() *ethutil.Value { -- cgit v1.2.3 From 64701e388c3f603a4fad5b6ff45ba2633b3f645e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 22:43:59 +0200 Subject: Fixed state issue --- ethchain/state.go | 3 --- 1 file changed, 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 63c4a32a6..db715f1cb 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -61,9 +61,6 @@ func (s *State) GetStateObject(addr []byte) *StateObject { cachedStateObject := s.states[string(addr)] if cachedStateObject != nil { stateObject.state = cachedStateObject - } else { - // If it isn't cached, cache the state - s.states[string(addr)] = stateObject.state } return stateObject -- cgit v1.2.3 From 5ceb1620e93e1999c6f72e6164c7c65af63244ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 00:17:50 +0200 Subject: Fixed couple issues * (imp) Lock / RLock tries * (fix) stack --- ethchain/stack.go | 2 +- ethchain/state_manager.go | 46 +++++++++++++++++++++++-------------------- ethchain/state_object_test.go | 29 ++++++++++++++++++++++++++- ethchain/vm.go | 2 ++ ethchain/vm_test.go | 9 ++++++--- 5 files changed, 62 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index e9297b324..bf34e6ea9 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -65,7 +65,7 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) { } func (st *Stack) Push(d *big.Int) { - st.data = append(st.data, d) + st.data = append(st.data, new(big.Int).Set(d)) } func (st *Stack) Get(amount *big.Int) []*big.Int { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c7c6857d8..27eaa5e60 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -100,30 +100,34 @@ func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { - // If there's no recipient, it's a contract - // Check if this is a contract creation traction and if so - // create a contract of this tx. - if tx.IsContract() { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - if err == nil { - contract := sm.MakeContract(state, tx) - if contract != nil { - sm.EvalScript(state, contract.Init(), contract, tx, block) - } else { - ethutil.Config.Log.Infoln("[STATE] Unable to create contract") - } + sm.ApplyTransaction(state, block, tx) + } +} + +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) { + // If there's no recipient, it's a contract + // Check if this is a contract creation traction and if so + // create a contract of this tx. + if tx.IsContract() { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + if err == nil { + contract := sm.MakeContract(state, tx) + if contract != nil { + sm.EvalScript(state, contract.Init(), contract, tx, block) } else { - ethutil.Config.Log.Infoln("[STATE] contract create:", err) + ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := state.GetStateObject(tx.Recipient) - ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) - if err == nil && len(contract.Script()) > 0 { - sm.EvalScript(state, contract.Script(), contract, tx, block) - } else if err != nil { - ethutil.Config.Log.Infoln("[STATE] process:", err) - } + ethutil.Config.Log.Infoln("[STATE] contract create:", err) + } + } else { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + contract := state.GetStateObject(tx.Recipient) + ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) + if err == nil && len(contract.Script()) > 0 { + sm.EvalScript(state, contract.Script(), contract, tx, block) + } else if err != nil { + ethutil.Config.Log.Infoln("[STATE] process:", err) } } } diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go index 1db01a537..e955acc56 100644 --- a/ethchain/state_object_test.go +++ b/ethchain/state_object_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" + "math/big" "testing" ) @@ -21,5 +22,31 @@ func TestSync(t *testing.T) { state.Sync() object := state.GetStateObject([]byte("aa")) - fmt.Printf("%x\n", object.Script()) + if len(object.Script()) == 0 { + t.Fail() + } +} + +func TestObjectGet(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd) + + db, _ := ethdb.NewMemDatabase() + ethutil.Config.Db = db + + state := NewState(ethutil.NewTrie(db, "")) + + contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + state.UpdateStateObject(contract) + + contract = state.GetStateObject([]byte("aa")) + contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello")) + o := contract.GetMem(big.NewInt(0)) + fmt.Println(o) + + state.UpdateStateObject(contract) + contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello00")) + + contract = state.GetStateObject([]byte("aa")) + o = contract.GetMem(big.NewInt(0)) + fmt.Println("after", o) } diff --git a/ethchain/vm.go b/ethchain/vm.go index e732d22a4..9be38fcc1 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -390,10 +390,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + //fmt.Println("get", val.BigInt(), "@", loc) stack.Push(val.BigInt()) case oSSTORE: require(2) val, loc := stack.Popn() + //fmt.Println("storing", val, "@", loc) closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 5d03ccf0c..2ec70536a 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,5 +1,6 @@ package ethchain +/* import ( _ "bytes" "fmt" @@ -23,10 +24,11 @@ func TestRun4(t *testing.T) { if a > b { int32 c = this.caller() } - Exit() + exit() `), false) tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) - addr := tx.Hash()[12:] + tx.Sign(ContractAddr) + addr := tx.CreationAddress() contract := MakeContract(tx, state) state.UpdateStateObject(contract) fmt.Printf("%x\n", addr) @@ -34,7 +36,7 @@ func TestRun4(t *testing.T) { callerScript, err := mutan.Compile(strings.NewReader(` // Check if there's any cash in the initial store if this.store[1000] == 0 { - this.store[1000] = 10^20 + this.store[1000] = 10**20 } @@ -93,3 +95,4 @@ func TestRun4(t *testing.T) { } fmt.Println("account.Amount =", account.Amount) } +*/ -- cgit v1.2.3 From 3c35ba7c31423da644c5fb73030af4673cff90ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 01:12:28 +0200 Subject: Fixed state overwriting issue --- ethchain/state.go | 10 +++------- ethchain/state_object.go | 1 + ethchain/vm.go | 6 +++--- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index db715f1cb..6ec6916f4 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -60,6 +60,7 @@ func (s *State) GetStateObject(addr []byte) *StateObject { // Check if there's a cached state for this contract cachedStateObject := s.states[string(addr)] if cachedStateObject != nil { + //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) stateObject.state = cachedStateObject } @@ -70,8 +71,9 @@ func (s *State) GetStateObject(addr []byte) *StateObject { func (s *State) UpdateStateObject(object *StateObject) { addr := object.Address() - if object.state != nil { + if object.state != nil && s.states[string(addr)] == nil { s.states[string(addr)] = object.state + //fmt.Printf("update cached #%d %x addr: %x\n", object.state.trie.Cache().Len(), object.state.Root(), addr[0:4]) } ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) @@ -81,12 +83,6 @@ func (s *State) UpdateStateObject(object *StateObject) { s.manifest.AddObjectChange(object) } -func (s *State) SetStateObject(stateObject *StateObject) { - s.states[string(stateObject.address)] = stateObject.state - - s.UpdateStateObject(stateObject) -} - func (s *State) GetAccount(addr []byte) (account *StateObject) { data := s.trie.Get(string(addr)) if data == "" { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index cb6211ea6..8e059f334 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -78,6 +78,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) + //fmt.Println("storing", val.BigInt(), "@", num) c.SetAddr(addr, val) } diff --git a/ethchain/vm.go b/ethchain/vm.go index e732d22a4..c4304e5ac 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -448,7 +448,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigD(addr)) - vm.state.SetStateObject(contract) + vm.state.UpdateStateObject(contract) } case oCALL: require(7) @@ -497,7 +497,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigTrue) } - vm.state.SetStateObject(contract) + vm.state.UpdateStateObject(contract) mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { @@ -515,7 +515,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - vm.state.SetStateObject(receiver) + vm.state.UpdateStateObject(receiver) closure.object.state.Purge() -- cgit v1.2.3 From cbf221f6b7a48ece543d6141d8a7e9dbf9b8d86d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 11:42:20 +0200 Subject: Fixed competing block method --- ethchain/state_manager.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 27eaa5e60..8c442cf44 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -132,8 +132,19 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac } } +func (sm *StateManager) Process(block *Block, dontReact bool) error { + if !sm.bc.HasBlock(block.PrevHash) { + return ParentError(block.PrevHash) + } + + parent := sm.bc.GetBlock(block.PrevHash) + + return sm.ProcessBlock(parent.State(), parent, block, dontReact) + +} + // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) error { +func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -186,7 +197,7 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) sm.bc.Add(block) sm.notifyChanges(state) - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) -- cgit v1.2.3 From 07fe00c4661e3b96e1758598df881057c1f52b3a Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 11:42:31 +0200 Subject: Changed numbers --- ethchain/block_chain.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2865336fb..b72c78cdb 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -190,8 +190,8 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { returnTo = bc.GetBlock(hash) bc.CurrentBlock = returnTo bc.LastBlockHash = returnTo.Hash() - info := bc.BlockInfo(returnTo) - bc.LastBlockNumber = info.Number + //info := bc.BlockInfo(returnTo) + bc.LastBlockNumber = returnTo.Number.Uint64() } // XXX Why are we resetting? This is the block chain, it has nothing to do with states @@ -228,9 +228,9 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []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 + lastNumber := bc.CurrentBlock.Number.Uint64() // Get the parents number - parentNumber := bc.BlockInfoByHash(hash).Number + parentNumber := bc.GetBlock(hash).Number.Uint64() // Get the min amount. We might not have max amount of blocks count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max))) startNumber := parentNumber + count @@ -291,10 +291,10 @@ func (bc *BlockChain) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { block := NewBlockFromBytes(data) - info := bc.BlockInfo(block) + //info := bc.BlockInfo(block) bc.CurrentBlock = block bc.LastBlockHash = block.Hash() - bc.LastBlockNumber = info.Number + bc.LastBlockNumber = block.Number.Uint64() ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) } else { -- cgit v1.2.3 From 0c27c5eb7fd4cea3ccdf26096a47ed91b0e9b848 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 12:38:56 +0200 Subject: Proper log statement --- ethchain/transaction_pool.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 796ec7c9a..dcf0c4c31 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -81,8 +81,9 @@ func NewTxPool(ethereum EthManager) *TxPool { // Blocking function. Don't use directly. Use QueueTransaction instead func (pool *TxPool) addTransaction(tx *Transaction) { pool.mutex.Lock() + defer pool.mutex.Unlock() + pool.pool.PushBack(tx) - pool.mutex.Unlock() // Broadcast the transaction to the rest of the peers pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) @@ -182,9 +183,7 @@ out: // Validate the transaction err := pool.ValidateTransaction(tx) if err != nil { - if ethutil.Config.Debug { - log.Println("Validating Tx failed", err) - } + ethutil.Config.Log.Debugln("Validating Tx failed", err) } else { // Call blocking version. pool.addTransaction(tx) -- cgit v1.2.3 From 2667cb3ab69271604262e809927f7ab25dafa93e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 12:39:07 +0200 Subject: Apply to parent --- ethchain/state_manager.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8c442cf44..9fe485b7a 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -123,8 +123,7 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) contract := state.GetStateObject(tx.Recipient) - ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) - if err == nil && len(contract.Script()) > 0 { + if err == nil && contract != nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { ethutil.Config.Log.Infoln("[STATE] process:", err) @@ -168,7 +167,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } // Process the transactions on to current block - sm.ApplyTransactions(state, sm.bc.CurrentBlock, block.Transactions()) + sm.ApplyTransactions(state, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { -- cgit v1.2.3 From 86cf69648efc5029abffbf39f1be7308acb1531e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 13:04:40 +0200 Subject: Improved miner so it won't include invalid transactions --- ethchain/state_manager.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 9fe485b7a..8b56d65bb 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -104,7 +104,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra } } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) { +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) error { // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. @@ -115,10 +115,10 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac if contract != nil { sm.EvalScript(state, contract.Init(), contract, tx, block) } else { - ethutil.Config.Log.Infoln("[STATE] Unable to create contract") + return fmt.Errorf("[STATE] Unable to create contract") } } else { - ethutil.Config.Log.Infoln("[STATE] contract create:", err) + return fmt.Errorf("[STATE] contract create:", err) } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) @@ -126,9 +126,11 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac if err == nil && contract != nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { - ethutil.Config.Log.Infoln("[STATE] process:", err) + return fmt.Errorf("[STATE] process:", err) } } + + return nil } func (sm *StateManager) Process(block *Block, dontReact bool) error { @@ -184,7 +186,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea //if !sm.compState.Cmp(state) { if !block.State().Cmp(state) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, state.trie.Root) + return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) } // Calculate the new total difficulty and sync back to the db -- cgit v1.2.3 From f5852b47d1008e3b1752031900e8f4cdd982ee61 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 14:00:13 +0200 Subject: Removed some logging and refactored a bit --- ethchain/dagger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 18e53d3a8..565e1e447 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -29,7 +29,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") + //ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") return nil default: i++ -- cgit v1.2.3 From f8f84ef0953534f44c3ce7c9630c569b1059e4bd Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 00:25:02 +0200 Subject: Removed old contract creation code --- ethchain/block.go | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 24ff5a32f..3401632b1 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -56,8 +56,6 @@ 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 @@ -91,28 +89,23 @@ 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, - GasUsed: new(big.Int), - MinGasPrice: new(big.Int), - GasLimit: new(big.Int), - contractStates: make(map[string]*ethutil.Trie), + transactions: txes, + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), } block.SetTransactions(txes) block.SetUncles([]*Block{}) block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) - for _, tx := range txes { - block.MakeContract(tx) - } - return block } @@ -178,13 +171,6 @@ func (block *Block) Undo() { block.state.Reset() } -func (block *Block) MakeContract(tx *Transaction) { - contract := MakeContract(tx, block.state) - if contract != nil { - block.state.states[string(tx.Hash()[12:])] = contract.state - } -} - /////// Block Encoding func (block *Block) rlpTxs() interface{} { // Marshal the transactions of this block @@ -265,7 +251,6 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.Time = int64(header.Get(10).BigInt().Uint64()) block.Extra = header.Get(11).Str() block.Nonce = header.Get(12).Bytes() - block.contractStates = make(map[string]*ethutil.Trie) // Tx list might be empty if this is an uncle. Uncles only have their // header set. -- cgit v1.2.3 From 230aafbf66ba747fb3796810adf3b1680f368e73 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 17:35:26 +0200 Subject: Working on interop * Receipts after each transaction * Fee structure * Applying fees to miners --- ethchain/block.go | 74 +++++++++++++++++------------ ethchain/block_chain.go | 21 +++++---- ethchain/genesis.go | 2 +- ethchain/state_manager.go | 42 +++++++++++++---- ethchain/state_object.go | 2 +- ethchain/transaction.go | 108 +++++++++++++++++++++++++++++++++++-------- ethchain/transaction_pool.go | 18 ++++---- ethchain/vm.go | 1 + 8 files changed, 191 insertions(+), 77 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 3401632b1..c846516f4 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -55,6 +55,7 @@ type Block struct { Nonce []byte // List of transactions and/or contracts transactions []*Transaction + receipts []*Receipt TxSha []byte } @@ -84,24 +85,20 @@ func CreateBlock(root interface{}, base []byte, Difficulty *big.Int, Nonce []byte, - extra string, - txes []*Transaction) *Block { + extra string) *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, - GasUsed: new(big.Int), - MinGasPrice: new(big.Int), - GasLimit: new(big.Int), + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), } - block.SetTransactions(txes) block.SetUncles([]*Block{}) block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) @@ -115,7 +112,10 @@ func (block *Block) Hash() []byte { } func (block *Block) HashNoNonce() []byte { - return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) + return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, + block.UncleSha, block.Coinbase, block.state.trie.Root, + block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, + block.GasLimit, block.GasUsed, block.Time, block.Extra})) } func (block *Block) State() *State { @@ -172,15 +172,15 @@ func (block *Block) Undo() { } /////// Block Encoding -func (block *Block) rlpTxs() interface{} { +func (block *Block) rlpReceipts() interface{} { // Marshal the transactions of this block - encTx := make([]interface{}, len(block.transactions)) - for i, tx := range block.transactions { + encR := make([]interface{}, len(block.receipts)) + for i, r := range block.receipts { // Cast it to a string (safe) - encTx[i] = tx.RlpData() + encR[i] = r.RlpData() } - return encTx + return encR } func (block *Block) rlpUncles() interface{} { @@ -201,7 +201,12 @@ func (block *Block) SetUncles(uncles []*Block) { block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles())) } -func (block *Block) SetTransactions(txs []*Transaction) { +func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { + self.receipts = receipts + self.setTransactions(txs) +} + +func (block *Block) setTransactions(txs []*Transaction) { block.transactions = txs trie := ethutil.NewTrie(ethutil.Config.Db, "") @@ -221,7 +226,7 @@ func (block *Block) SetTransactions(txs []*Transaction) { } func (block *Block) Value() *ethutil.Value { - return ethutil.NewValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()}) + return ethutil.NewValue([]interface{}{block.header(), block.rlpReceipts(), block.rlpUncles()}) } func (block *Block) RlpEncode() []byte { @@ -245,6 +250,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() + //fmt.Printf("#%v : %x\n", block.Number, block.Coinbase) block.MinGasPrice = header.Get(7).BigInt() block.GasLimit = header.Get(8).BigInt() block.GasUsed = header.Get(9).BigInt() @@ -255,12 +261,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { // 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 + receipts := decoder.Get(1) + block.transactions = make([]*Transaction, receipts.Len()) + block.receipts = make([]*Receipt, receipts.Len()) + for i := 0; i < receipts.Len(); i++ { + receipt := NewRecieptFromValue(receipts.Get(i)) + block.transactions[i] = receipt.Tx + block.receipts[i] = receipt } } @@ -299,6 +306,10 @@ func (block *Block) GetRoot() interface{} { return block.state.trie.Root } +func (self *Block) Receipts() []*Receipt { + return self.receipts +} + func (block *Block) header() []interface{} { return []interface{}{ // Sha of the previous block @@ -346,6 +357,7 @@ func (block *Block) String() string { Time: %v Extra: %v Nonce: %x + NumTx: %v `, block.Hash(), block.PrevHash, @@ -360,5 +372,7 @@ func (block *Block) String() string { block.GasUsed, block.Time, block.Extra, - block.Nonce) + block.Nonce, + len(block.transactions), + ) } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b72c78cdb..b45d254b5 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -36,7 +36,7 @@ func (bc *BlockChain) Genesis() *Block { return bc.genesisBlock } -func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { +func (bc *BlockChain) NewBlock(coinbase []byte) *Block { var root interface{} var lastBlockTime int64 hash := ZeroHash256 @@ -53,8 +53,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { coinbase, ethutil.BigPow(2, 32), nil, - "", - txs) + "") if bc.CurrentBlock != nil { var mul *big.Int @@ -272,16 +271,18 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { func AddTestNetFunds(block *Block) { for _, addr := range []string{ - "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin - "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey - "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // Roman + "8a40bfaa73256b60764c1bf40675a99083efb075", + "e4157b34ea9615cfbde6b4fda419828124b70c78", + "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", + "6c386a4b26f73c802f34673f7248bb118f97424a", + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", + "e6716f9544a56c530d868e4bfbacb172315bdead", + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", } { codedAddr := ethutil.FromHex(addr) account := block.state.GetAccount(codedAddr) - account.Amount = ethutil.BigPow(2, 200) + account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } log.Printf("%x\n", block.RlpEncode()) diff --git a/ethchain/genesis.go b/ethchain/genesis.go index b8f9f865a..359c47c26 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -23,7 +23,7 @@ var GenesisHeader = []interface{}{ // Root state "", // tx sha - ZeroHash256, + "", // Difficulty ethutil.BigPow(2, 22), // Number diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8b56d65bb..3b67381ea 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -97,40 +97,56 @@ func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. -func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) { +func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { // Process each transaction/contract + var receipts []*Receipt + var validTxs []*Transaction + totalUsedGas := big.NewInt(0) for _, tx := range txs { - sm.ApplyTransaction(state, block, tx) + usedGas, err := sm.ApplyTransaction(state, block, tx) + if err != nil { + ethutil.Config.Log.Infoln(err) + continue + } + + accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) + receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + + receipts = append(receipts, receipt) + validTxs = append(validTxs, tx) } + + return receipts, txs } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) error { +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) { // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. + totalGasUsed := big.NewInt(0) if tx.IsContract() { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) if err == nil { contract := sm.MakeContract(state, tx) if contract != nil { sm.EvalScript(state, contract.Init(), contract, tx, block) } else { - return fmt.Errorf("[STATE] Unable to create contract") + return nil, fmt.Errorf("[STATE] Unable to create contract") } } else { - return fmt.Errorf("[STATE] contract create:", err) + return nil, fmt.Errorf("[STATE] contract create:", err) } } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) contract := state.GetStateObject(tx.Recipient) if err == nil && contract != nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { - return fmt.Errorf("[STATE] process:", err) + return nil, fmt.Errorf("[STATE] process:", err) } } - return nil + return totalGasUsed, nil } func (sm *StateManager) Process(block *Block, dontReact bool) error { @@ -276,6 +292,14 @@ func CalculateBlockReward(block *Block, uncleLength int) *big.Int { for i := 0; i < uncleLength; i++ { base.Add(base, UncleInclusionReward) } + + lastCumulGasUsed := big.NewInt(0) + for _, r := range block.Receipts() { + usedGas := new(big.Int).Sub(r.CumulativeGasUsed, lastCumulGasUsed) + usedGas.Add(usedGas, r.Tx.GasPrice) + base.Add(base, usedGas) + } + return base.Add(base, BlockReward) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8e059f334..4046054db 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -146,7 +146,7 @@ func (c *StateObject) RlpEncode() []byte { if c.state != nil { root = c.state.trie.Root } else { - root = ZeroHash256 + root = "" } return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index bd7a0e424..16ea312c0 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -46,11 +47,13 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - if tx.contractCreation { - data = append(data, tx.Init) - } + /* + if tx.contractCreation { + data = append(data, tx.Init) + } + */ return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } @@ -138,18 +141,87 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Recipient = decoder.Get(3).Bytes() tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() - - // If the list is of length 10 it's a contract creation tx - if decoder.Len() == 10 { - tx.contractCreation = true - tx.Init = decoder.Get(6).Bytes() - - tx.v = byte(decoder.Get(7).Uint()) - tx.r = decoder.Get(8).Bytes() - tx.s = decoder.Get(9).Bytes() - } else { - tx.v = byte(decoder.Get(6).Uint()) - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() - } + tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() + + /* + // If the list is of length 10 it's a contract creation tx + if decoder.Len() == 10 { + tx.contractCreation = true + tx.Init = decoder.Get(6).Bytes() + + tx.v = byte(decoder.Get(7).Uint()) + tx.r = decoder.Get(8).Bytes() + tx.s = decoder.Get(9).Bytes() + } else { + tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() + } + */ +} + +func (tx *Transaction) String() string { + return fmt.Sprintf(` + TX(%x) + Contract: %v + From: %x + Nonce: %v + GasPrice: %v + Gas: %v + To: %x + Value: %v + Data: 0x%x + V: 0x%x + R: 0x%x + S: 0x%x + `, + tx.Hash(), + len(tx.Recipient) > 1, + tx.Sender(), + tx.Nonce, + tx.GasPrice, + tx.Gas, + tx.Recipient, + tx.Value, + tx.Data, + tx.v, + tx.r, + tx.s) +} + +type Receipt struct { + Tx *Transaction + PostState []byte + CumulativeGasUsed *big.Int +} + +func NewRecieptFromValue(val *ethutil.Value) *Receipt { + r := &Receipt{} + r.RlpValueDecode(val) + + return r +} + +func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { + self.Tx = NewTransactionFromValue(decoder.Get(0)) + self.PostState = decoder.Get(1).Bytes() + self.CumulativeGasUsed = decoder.Get(2).BigInt() +} + +func (self *Receipt) RlpData() interface{} { + return []interface{}{self.Tx.RlpData(), self.PostState, self.CumulativeGasUsed} +} + +func (self *Receipt) String() string { + return fmt.Sprintf(` + R + Tx:[ %v] + PostState: 0x%x + CumulativeGasUsed: %v + `, + self.Tx, + self.PostState, + self.CumulativeGasUsed) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index dcf0c4c31..ee026ffdd 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,15 +91,15 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { defer func() { if r := recover(); r != nil { - log.Println(r) + ethutil.Config.Log.Infoln(r) err = fmt.Errorf("%v", r) } }() // Get the sender - sender := block.state.GetAccount(tx.Sender()) + sender := state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) @@ -107,19 +107,21 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // 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)) + //totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) if sender.Amount.Cmp(totAmount) < 0 { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } + //fmt.Println(tx) // Get the receiver - receiver := block.state.GetAccount(tx.Recipient) + receiver := state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { // Subtract the fee - sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) + sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) } else { // Subtract the amount from the senders account sender.SubAmount(totAmount) @@ -127,10 +129,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(tx.Value) - block.state.UpdateStateObject(receiver) + state.UpdateStateObject(receiver) } - block.state.UpdateStateObject(sender) + state.UpdateStateObject(sender) ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) diff --git a/ethchain/vm.go b/ethchain/vm.go index d8254998e..e067a9c96 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -18,6 +18,7 @@ var ( GasCreate = big.NewInt(100) GasCall = big.NewInt(20) GasMemory = big.NewInt(1) + GasTx = big.NewInt(500) ) func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int { -- cgit v1.2.3 From cc8464ce805279735f637ac710b25e2fb264f9aa Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 17:56:33 +0200 Subject: Transaction querying --- ethchain/block.go | 11 +++++++++++ ethchain/transaction.go | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index c846516f4..73e29f878 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -1,6 +1,7 @@ package ethchain import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -161,6 +162,16 @@ func (block *Block) BlockInfo() BlockInfo { return bi } +func (self *Block) GetTransaction(hash []byte) *Transaction { + for _, receipt := range self.receipts { + if bytes.Compare(receipt.Tx.Hash(), hash) == 0 { + return receipt.Tx + } + } + + return nil +} + // Sync the block's state and contract respectively func (block *Block) Sync() { block.state.Sync() diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 16ea312c0..6ae7e77e1 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -167,10 +167,10 @@ func (tx *Transaction) String() string { TX(%x) Contract: %v From: %x + To: %x Nonce: %v GasPrice: %v Gas: %v - To: %x Value: %v Data: 0x%x V: 0x%x @@ -178,12 +178,12 @@ func (tx *Transaction) String() string { S: 0x%x `, tx.Hash(), - len(tx.Recipient) > 1, + len(tx.Recipient) == 1, tx.Sender(), + tx.Recipient, tx.Nonce, tx.GasPrice, tx.Gas, - tx.Recipient, tx.Value, tx.Data, tx.v, -- cgit v1.2.3 From 281559d42712c2b2ae903cb893b2ddc82318307d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 18:24:04 +0200 Subject: Canonical contract creation --- ethchain/state_manager.go | 22 +++++++++++++++------- ethchain/state_object.go | 3 +-- ethchain/transaction.go | 9 ++------- ethchain/types.go | 7 +++++++ 4 files changed, 25 insertions(+), 16 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3b67381ea..4f009b6d3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -84,7 +84,7 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { +func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { contract := MakeContract(tx, state) if contract != nil { state.states[string(tx.CreationAddress())] = contract.state @@ -123,18 +123,24 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. + // TODO COMMENT THIS SECTION totalGasUsed := big.NewInt(0) if tx.IsContract() { err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) if err == nil { - contract := sm.MakeContract(state, tx) + contract := sm.MakeStateObject(state, tx) if contract != nil { - sm.EvalScript(state, contract.Init(), contract, tx, block) + script, err := sm.EvalScript(state, contract.Init(), contract, tx, block) + if err != nil { + return nil, fmt.Errorf("[STATE] Error during init script run %v", err) + } + contract.script = script + state.UpdateStateObject(contract) } else { return nil, fmt.Errorf("[STATE] Unable to create contract") } } else { - return nil, fmt.Errorf("[STATE] contract create:", err) + return nil, fmt.Errorf("[STATE] contract creation tx:", err) } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) @@ -331,10 +337,10 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) { +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, err error) { account := state.GetAccount(tx.Sender()) - err := account.ConvertGas(tx.Gas, tx.GasPrice) + err = account.ConvertGas(tx.Gas, tx.GasPrice) if err != nil { ethutil.Config.Log.Debugln(err) return @@ -351,11 +357,13 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj Value: tx.Value, //Price: tx.GasPrice, }) - closure.Call(vm, tx.Data, nil) + ret, err = closure.Call(vm, tx.Data, nil) // Update the account (refunds) state.UpdateStateObject(account) state.UpdateStateObject(object) + + return } func (sm *StateManager) notifyChanges(state *State) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 4046054db..4d615e2fe 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -28,8 +28,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { value := tx.Value contract := NewContract(addr, value, ZeroHash256) - contract.script = tx.Data - contract.initScript = tx.Init + contract.initScript = tx.Data state.UpdateStateObject(contract) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 6ae7e77e1..25d63879b 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -16,7 +16,6 @@ type Transaction struct { Gas *big.Int GasPrice *big.Int Data []byte - Init []byte v byte r, s []byte @@ -24,8 +23,8 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte, init []byte) *Transaction { - return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, Init: init, contractCreation: true} +func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { + return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { @@ -115,10 +114,6 @@ func (tx *Transaction) Sign(privk []byte) error { func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - if tx.contractCreation { - data = append(data, tx.Init) - } - return append(data, tx.v, tx.r, tx.s) } diff --git a/ethchain/types.go b/ethchain/types.go index 9964bbe3b..e0fdd5191 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -322,3 +322,10 @@ func IsOpCode(s string) bool { } return false } + +func AppendScript(init, script []byte) []byte { + s := append(init, byte(oRETURN)) + s = append(s, script...) + + return s +} -- cgit v1.2.3 From 99fa9afaf15ceecffcc5b7051ffe9c7f0d179dec Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 25 May 2014 14:13:07 +0100 Subject: Updated to work with the new config --- ethchain/block_chain_test.go | 4 ++-- ethchain/state_object_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 4e4bb9dd4..ecaf8ca89 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -50,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { } func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest", ethutil.LogStd) + ethutil.ReadConfig(".ethtest", ethutil.LogStd, "") db, err := ethdb.NewMemDatabase() if err != nil { @@ -74,7 +74,7 @@ func NewTestManager() *TestManager { func (tm *TestManager) AddFakeBlock(blk []byte) error { block := NewBlockFromBytes(blk) tm.Blocks = append(tm.Blocks, block) - err := tm.StateManager().ProcessBlock(tm.StateManager().CurrentState(), block, false) + err := tm.StateManager().Process(block, false) return err } func (tm *TestManager) CreateChain1() error { diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go index e955acc56..91ed7c0dd 100644 --- a/ethchain/state_object_test.go +++ b/ethchain/state_object_test.go @@ -9,7 +9,7 @@ import ( ) func TestSync(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) @@ -28,7 +28,7 @@ func TestSync(t *testing.T) { } func TestObjectGet(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() ethutil.Config.Db = db -- cgit v1.2.3 From 81ef40010f6f31bc94f654048b41fa3a9f9e07eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 25 May 2014 14:13:54 +0100 Subject: The body of contracts are now returned instead --- ethchain/state_manager.go | 32 ++++++++++++++++-------- ethchain/transaction.go | 12 +++++++-- ethchain/vm_test.go | 64 +++++++++++++---------------------------------- 3 files changed, 50 insertions(+), 58 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4f009b6d3..2d2a32e2f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -120,16 +120,27 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra } func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) { - // If there's no recipient, it's a contract - // Check if this is a contract creation traction and if so - // create a contract of this tx. - // TODO COMMENT THIS SECTION + /* + Applies transactions to the given state and creates new + state objects where needed. + + If said objects needs to be created + run the initialization script provided by the transaction and + assume there's a return value. The return value will be set to + the script section of the state object. + */ totalGasUsed := big.NewInt(0) - if tx.IsContract() { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + // Apply the transaction to the current state + err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + if tx.CreatesContract() { if err == nil { + // Create a new state object and the transaction + // as it's data provider. contract := sm.MakeStateObject(state, tx) if contract != nil { + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. script, err := sm.EvalScript(state, contract.Init(), contract, tx, block) if err != nil { return nil, fmt.Errorf("[STATE] Error during init script run %v", err) @@ -143,10 +154,11 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac return nil, fmt.Errorf("[STATE] contract creation tx:", err) } } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) - contract := state.GetStateObject(tx.Recipient) - if err == nil && contract != nil && len(contract.Script()) > 0 { - sm.EvalScript(state, contract.Script(), contract, tx, block) + // Find the state object at the "recipient" address. If + // there's an object attempt to run the script. + stateObject := state.GetStateObject(tx.Recipient) + if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { + sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) } else if err != nil { return nil, fmt.Errorf("[STATE] process:", err) } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 25d63879b..2c5615f99 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -57,10 +57,15 @@ func (tx *Transaction) Hash() []byte { return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } -func (tx *Transaction) IsContract() bool { +func (tx *Transaction) CreatesContract() bool { return tx.contractCreation } +/* Depricated */ +func (tx *Transaction) IsContract() bool { + return tx.CreatesContract() +} + func (tx *Transaction) CreationAddress() []byte { return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } @@ -139,6 +144,9 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.v = byte(decoder.Get(6).Uint()) tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() + if len(tx.Recipient) == 0 { + tx.contractCreation = true + } /* // If the list is of length 10 it's a contract creation tx @@ -173,7 +181,7 @@ func (tx *Transaction) String() string { S: 0x%x `, tx.Hash(), - len(tx.Recipient) == 1, + len(tx.Recipient) == 0, tx.Sender(), tx.Recipient, tx.Nonce, diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 2ec70536a..520f9a2ed 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,6 +1,5 @@ package ethchain -/* import ( _ "bytes" "fmt" @@ -13,60 +12,33 @@ import ( ) func TestRun4(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - script, err := mutan.Compile(strings.NewReader(` - int32 a = 10 - int32 b = 20 - if a > b { - int32 c = this.caller() - } - exit() - `), false) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) - tx.Sign(ContractAddr) - addr := tx.CreationAddress() - contract := MakeContract(tx, state) - state.UpdateStateObject(contract) - fmt.Printf("%x\n", addr) - callerScript, err := mutan.Compile(strings.NewReader(` - // Check if there's any cash in the initial store - if this.store[1000] == 0 { - this.store[1000] = 10**20 - } - - - this.store[1001] = this.value() * 20 - this.store[this.origin()] = this.store[this.origin()] + 1000 + this.store[this.origin()] = 10**20 + hello := "world" - if this.store[1001] > 20 { - this.store[1001] = 10^50 - } - - int8 ret = 0 - int8 arg = 10 - call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) - - big t - for int8 i = 0; i < 10; i++ { - t = i - } + return lambda { + big to = this.data[0] + big from = this.origin() + big value = this.data[1] - if 10 > 20 { - int8 shouldnt = 2 - } else { - int8 should = 1 + if this.store[from] >= value { + this.store[from] = this.store[from] - value + this.store[to] = this.store[to] + value } + } `), false) if err != nil { fmt.Println(err) } + fmt.Println(Disassemble(callerScript)) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript) + callerTx.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) // Contract addr as test address gas := big.NewInt(1000) @@ -79,7 +51,7 @@ func TestRun4(t *testing.T) { fmt.Println(err) } fmt.Println("account.Amount =", account.Amount) - callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice) + callerClosure := NewClosure(account, c, callerScript, state, gas, gasPrice) vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), @@ -89,10 +61,10 @@ func TestRun4(t *testing.T) { Time: 1, Diff: big.NewInt(256), }) - _, e = callerClosure.Call(vm, nil, nil) + var ret []byte + ret, e = callerClosure.Call(vm, nil, nil) if e != nil { fmt.Println("error", e) } - fmt.Println("account.Amount =", account.Amount) + fmt.Println(ret) } -*/ -- cgit v1.2.3 From 3ebd7f1166f03f94117651d8e74b9603ee7d6966 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 26 May 2014 00:09:38 +0200 Subject: State snapshotting --- ethchain/state.go | 16 +++++++++++++++- ethchain/state_object.go | 7 ++++++- ethchain/state_test.go | 31 +++++++++++++++++++++++++++++++ ethchain/vm.go | 17 +++++++++++++---- 4 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 ethchain/state_test.go (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 6ec6916f4..e209e0e2f 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -99,7 +99,21 @@ func (s *State) Cmp(other *State) bool { } func (s *State) Copy() *State { - return NewState(s.trie.Copy()) + state := NewState(s.trie.Copy()) + for k, subState := range s.states { + state.states[k] = subState.Copy() + } + + return state +} + +func (s *State) Snapshot() *State { + return s.Copy() +} + +func (s *State) Revert(snapshot *State) { + s.trie = snapshot.trie + s.states = snapshot.states } func (s *State) Put(key, object []byte) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 4d615e2fe..3e9c6df40 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -81,12 +81,17 @@ func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { c.SetAddr(addr, val) } -func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { +func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value { nb := ethutil.BigToBytes(num, 256) return c.Addr(nb) } +/* DEPRECATED */ +func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { + return c.GetStorage(num) +} + func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { if int64(len(c.script)-1) < pc.Int64() { return ethutil.NewValue(0) diff --git a/ethchain/state_test.go b/ethchain/state_test.go new file mode 100644 index 000000000..4cc3fdf75 --- /dev/null +++ b/ethchain/state_test.go @@ -0,0 +1,31 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "testing" +) + +func TestSnapshot(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd, "") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + stateObject := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + state.UpdateStateObject(stateObject) + stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42)) + + snapshot := state.Snapshot() + + stateObject = state.GetStateObject([]byte("aa")) + stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(43)) + + state.Revert(snapshot) + + stateObject = state.GetStateObject([]byte("aa")) + if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) { + t.Error("Expected storage 0 to be 42") + } +} diff --git a/ethchain/vm.go b/ethchain/vm.go index e067a9c96..e025920f3 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -426,6 +426,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro value := stack.Pop() size, offset := stack.Popn() + // Snapshot the current stack so we are able to + // revert back to it later. + snapshot := vm.state.Snapshot() + // Generate a new address addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N()) // Create a new contract @@ -448,6 +452,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Script, err = closure.Call(vm, nil, hook) if err != nil { stack.Push(ethutil.BigFalse) + + // Revert the state as it was before. + vm.state.Revert(snapshot) } else { stack.Push(ethutil.BigD(addr)) @@ -473,6 +480,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) + snapshot := vm.state.Snapshot() + // Fetch the contract which will serve as the closure body contract := vm.state.GetStateObject(addr.Bytes()) @@ -495,14 +504,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if err != nil { stack.Push(ethutil.BigFalse) // Reset the changes applied this object - //contract.State().Reset() + vm.state.Revert(snapshot) } else { stack.Push(ethutil.BigTrue) - } - vm.state.UpdateStateObject(contract) + vm.state.UpdateStateObject(contract) - mem.Set(retOffset.Int64(), retSize.Int64(), ret) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } } else { ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) stack.Push(ethutil.BigFalse) -- cgit v1.2.3 From aba3066658a32723543f9e4eda74a14ef140fc0e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 27 May 2014 13:10:18 +0200 Subject: Changed debug hook and added state iterator --- ethchain/closure.go | 2 +- ethchain/state.go | 5 +++++ ethchain/vm.go | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 59194e4e8..e65cfd252 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -72,7 +72,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack) +type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { c.Args = args diff --git a/ethchain/state.go b/ethchain/state.go index e209e0e2f..5af748e00 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -49,6 +49,11 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } +func (s *State) EachStorage(cb ethutil.EachCallback) { + it := s.trie.NewIterator() + it.Each(cb) +} + func (s *State) GetStateObject(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { diff --git a/ethchain/vm.go b/ethchain/vm.go index e025920f3..0d9e8599e 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -543,7 +543,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, ethutil.Big1) if hook != nil { - hook(step-1, op, mem, stack) + hook(step-1, op, mem, stack, closure.Object()) } } } -- cgit v1.2.3 From 4eb1771e67ee2c66d5fb86c2b5961d84e40f7dd0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 27 May 2014 13:32:31 +0200 Subject: Hooks can now quit the vm --- ethchain/closure.go | 2 +- ethchain/vm.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index e65cfd252..c935ed50a 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -72,7 +72,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) +type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { c.Args = args diff --git a/ethchain/vm.go b/ethchain/vm.go index 0d9e8599e..9821a839a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -543,7 +543,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, ethutil.Big1) if hook != nil { - hook(step-1, op, mem, stack, closure.Object()) + if !hook(step-1, op, mem, stack, closure.Object()) { + return nil, nil + } } } } -- cgit v1.2.3 From 98d4b511207404a133ceca37467f9a1c32c20bc5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:03:12 +0200 Subject: Changed opcode names --- ethchain/asm.go | 4 +- ethchain/types.go | 333 ++++++++++++++++++++++++++---------------------------- 2 files changed, 165 insertions(+), 172 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 492be0999..430a89450 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -21,9 +21,9 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("%v", op)) switch op { - case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: + case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: pc.Add(pc, ethutil.Big1) - a := int64(op) - int64(oPUSH1) + 1 + a := int64(op) - int64(PUSH1) + 1 data := script[pc.Int64() : pc.Int64()+a] val := ethutil.BigD(data) diff --git a/ethchain/types.go b/ethchain/types.go index e0fdd5191..293871143 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -5,206 +5,206 @@ type OpCode int // Op codes const ( // 0x0 range - arithmetic ops - oSTOP = 0x00 - oADD = 0x01 - oMUL = 0x02 - oSUB = 0x03 - oDIV = 0x04 - oSDIV = 0x05 - oMOD = 0x06 - oSMOD = 0x07 - oEXP = 0x08 - oNEG = 0x09 - oLT = 0x0a - oGT = 0x0b - oEQ = 0x0c - oNOT = 0x0d + STOP = 0x00 + ADD = 0x01 + MUL = 0x02 + SUB = 0x03 + DIV = 0x04 + SDIV = 0x05 + MOD = 0x06 + SMOD = 0x07 + EXP = 0x08 + NEG = 0x09 + LT = 0x0a + GT = 0x0b + EQ = 0x0c + NOT = 0x0d // 0x10 range - bit ops - oAND = 0x10 - oOR = 0x11 - oXOR = 0x12 - oBYTE = 0x13 + AND = 0x10 + OR = 0x11 + XOR = 0x12 + BYTE = 0x13 // 0x20 range - crypto - oSHA3 = 0x20 + SHA3 = 0x20 // 0x30 range - closure state - oADDRESS = 0x30 - oBALANCE = 0x31 - oORIGIN = 0x32 - oCALLER = 0x33 - oCALLVALUE = 0x34 - oCALLDATALOAD = 0x35 - oCALLDATASIZE = 0x36 - oGASPRICE = 0x37 + ADDRESS = 0x30 + BALANCE = 0x31 + ORIGIN = 0x32 + CALLER = 0x33 + CALLVALUE = 0x34 + CALLDATALOAD = 0x35 + CALLDATASIZE = 0x36 + GASPRICE = 0x37 // 0x40 range - block operations - oPREVHASH = 0x40 - oCOINBASE = 0x41 - oTIMESTAMP = 0x42 - oNUMBER = 0x43 - oDIFFICULTY = 0x44 - oGASLIMIT = 0x45 + PREVHASH = 0x40 + COINBASE = 0x41 + TIMESTAMP = 0x42 + NUMBER = 0x43 + DIFFICULTY = 0x44 + GASLIMIT = 0x45 // 0x50 range - 'storage' and execution - oPOP = 0x51 - oDUP = 0x52 - oSWAP = 0x53 - oMLOAD = 0x54 - oMSTORE = 0x55 - oMSTORE8 = 0x56 - oSLOAD = 0x57 - oSSTORE = 0x58 - oJUMP = 0x59 - oJUMPI = 0x5a - oPC = 0x5b - oMSIZE = 0x5c + POP = 0x51 + DUP = 0x52 + SWAP = 0x53 + MLOAD = 0x54 + MSTORE = 0x55 + MSTORE8 = 0x56 + SLOAD = 0x57 + SSTORE = 0x58 + JUMP = 0x59 + JUMPI = 0x5a + PC = 0x5b + MSIZE = 0x5c // 0x60 range - oPUSH1 = 0x60 - oPUSH2 = 0x61 - oPUSH3 = 0x62 - oPUSH4 = 0x63 - oPUSH5 = 0x64 - oPUSH6 = 0x65 - oPUSH7 = 0x66 - oPUSH8 = 0x67 - oPUSH9 = 0x68 - oPUSH10 = 0x69 - oPUSH11 = 0x6a - oPUSH12 = 0x6b - oPUSH13 = 0x6c - oPUSH14 = 0x6d - oPUSH15 = 0x6e - oPUSH16 = 0x6f - oPUSH17 = 0x70 - oPUSH18 = 0x71 - oPUSH19 = 0x72 - oPUSH20 = 0x73 - oPUSH21 = 0x74 - oPUSH22 = 0x75 - oPUSH23 = 0x76 - oPUSH24 = 0x77 - oPUSH25 = 0x78 - oPUSH26 = 0x79 - oPUSH27 = 0x7a - oPUSH28 = 0x7b - oPUSH29 = 0x7c - oPUSH30 = 0x7d - oPUSH31 = 0x7e - oPUSH32 = 0x7f + PUSH1 = 0x60 + PUSH2 = 0x61 + PUSH3 = 0x62 + PUSH4 = 0x63 + PUSH5 = 0x64 + PUSH6 = 0x65 + PUSH7 = 0x66 + PUSH8 = 0x67 + PUSH9 = 0x68 + PUSH10 = 0x69 + PUSH11 = 0x6a + PUSH12 = 0x6b + PUSH13 = 0x6c + PUSH14 = 0x6d + PUSH15 = 0x6e + PUSH16 = 0x6f + PUSH17 = 0x70 + PUSH18 = 0x71 + PUSH19 = 0x72 + PUSH20 = 0x73 + PUSH21 = 0x74 + PUSH22 = 0x75 + PUSH23 = 0x76 + PUSH24 = 0x77 + PUSH25 = 0x78 + PUSH26 = 0x79 + PUSH27 = 0x7a + PUSH28 = 0x7b + PUSH29 = 0x7c + PUSH30 = 0x7d + PUSH31 = 0x7e + PUSH32 = 0x7f // 0xf0 range - closures - oCREATE = 0xf0 - oCALL = 0xf1 - oRETURN = 0xf2 + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 // 0x70 range - other - oLOG = 0xfe // XXX Unofficial - oSUICIDE = 0xff + LOG = 0xfe // XXX Unofficial + SUICIDE = 0xff ) // Since the opcodes aren't all in order we can't use a regular slice var opCodeToString = map[OpCode]string{ // 0x0 range - arithmetic ops - oSTOP: "STOP", - oADD: "ADD", - oMUL: "MUL", - oSUB: "SUB", - oDIV: "DIV", - oSDIV: "SDIV", - oMOD: "MOD", - oSMOD: "SMOD", - oEXP: "EXP", - oNEG: "NEG", - oLT: "LT", - oGT: "GT", - oEQ: "EQ", - oNOT: "NOT", + STOP: "STOP", + ADD: "ADD", + MUL: "MUL", + SUB: "SUB", + DIV: "DIV", + SDIV: "SDIV", + MOD: "MOD", + SMOD: "SMOD", + EXP: "EXP", + NEG: "NEG", + LT: "LT", + GT: "GT", + EQ: "EQ", + NOT: "NOT", // 0x10 range - bit ops - oAND: "AND", - oOR: "OR", - oXOR: "XOR", - oBYTE: "BYTE", + AND: "AND", + OR: "OR", + XOR: "XOR", + BYTE: "BYTE", // 0x20 range - crypto - oSHA3: "SHA3", + SHA3: "SHA3", // 0x30 range - closure state - oADDRESS: "ADDRESS", - oBALANCE: "BALANCE", - oORIGIN: "ORIGIN", - oCALLER: "CALLER", - oCALLVALUE: "CALLVALUE", - oCALLDATALOAD: "CALLDATALOAD", - oCALLDATASIZE: "CALLDATASIZE", - oGASPRICE: "TXGASPRICE", + ADDRESS: "ADDRESS", + BALANCE: "BALANCE", + ORIGIN: "ORIGIN", + CALLER: "CALLER", + CALLVALUE: "CALLVALUE", + CALLDATALOAD: "CALLDATALOAD", + CALLDATASIZE: "CALLDATASIZE", + GASPRICE: "TXGASPRICE", // 0x40 range - block operations - oPREVHASH: "PREVHASH", - oCOINBASE: "COINBASE", - oTIMESTAMP: "TIMESTAMP", - oNUMBER: "NUMBER", - oDIFFICULTY: "DIFFICULTY", - oGASLIMIT: "GASLIMIT", + PREVHASH: "PREVHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution - oDUP: "DUP", - oSWAP: "SWAP", - oMLOAD: "MLOAD", - oMSTORE: "MSTORE", - oMSTORE8: "MSTORE8", - oSLOAD: "SLOAD", - oSSTORE: "SSTORE", - oJUMP: "JUMP", - oJUMPI: "JUMPI", - oPC: "PC", - oMSIZE: "MSIZE", + DUP: "DUP", + SWAP: "SWAP", + MLOAD: "MLOAD", + MSTORE: "MSTORE", + MSTORE8: "MSTORE8", + SLOAD: "SLOAD", + SSTORE: "SSTORE", + JUMP: "JUMP", + JUMPI: "JUMPI", + PC: "PC", + MSIZE: "MSIZE", // 0x60 range - push - oPUSH1: "PUSH1", - oPUSH2: "PUSH2", - oPUSH3: "PUSH3", - oPUSH4: "PUSH4", - oPUSH5: "PUSH5", - oPUSH6: "PUSH6", - oPUSH7: "PUSH7", - oPUSH8: "PUSH8", - oPUSH9: "PUSH9", - oPUSH10: "PUSH10", - oPUSH11: "PUSH11", - oPUSH12: "PUSH12", - oPUSH13: "PUSH13", - oPUSH14: "PUSH14", - oPUSH15: "PUSH15", - oPUSH16: "PUSH16", - oPUSH17: "PUSH17", - oPUSH18: "PUSH18", - oPUSH19: "PUSH19", - oPUSH20: "PUSH20", - oPUSH21: "PUSH21", - oPUSH22: "PUSH22", - oPUSH23: "PUSH23", - oPUSH24: "PUSH24", - oPUSH25: "PUSH25", - oPUSH26: "PUSH26", - oPUSH27: "PUSH27", - oPUSH28: "PUSH28", - oPUSH29: "PUSH29", - oPUSH30: "PUSH30", - oPUSH31: "PUSH31", - oPUSH32: "PUSH32", + PUSH1: "PUSH1", + PUSH2: "PUSH2", + PUSH3: "PUSH3", + PUSH4: "PUSH4", + PUSH5: "PUSH5", + PUSH6: "PUSH6", + PUSH7: "PUSH7", + PUSH8: "PUSH8", + PUSH9: "PUSH9", + PUSH10: "PUSH10", + PUSH11: "PUSH11", + PUSH12: "PUSH12", + PUSH13: "PUSH13", + PUSH14: "PUSH14", + PUSH15: "PUSH15", + PUSH16: "PUSH16", + PUSH17: "PUSH17", + PUSH18: "PUSH18", + PUSH19: "PUSH19", + PUSH20: "PUSH20", + PUSH21: "PUSH21", + PUSH22: "PUSH22", + PUSH23: "PUSH23", + PUSH24: "PUSH24", + PUSH25: "PUSH25", + PUSH26: "PUSH26", + PUSH27: "PUSH27", + PUSH28: "PUSH28", + PUSH29: "PUSH29", + PUSH30: "PUSH30", + PUSH31: "PUSH31", + PUSH32: "PUSH32", // 0xf0 range - oCREATE: "CREATE", - oCALL: "CALL", - oRETURN: "RETURN", + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", // 0x70 range - other - oLOG: "LOG", - oSUICIDE: "SUICIDE", + LOG: "LOG", + SUICIDE: "SUICIDE", } func (o OpCode) String() string { @@ -322,10 +322,3 @@ func IsOpCode(s string) bool { } return false } - -func AppendScript(init, script []byte) []byte { - s := append(init, byte(oRETURN)) - s = append(s, script...) - - return s -} -- cgit v1.2.3 From 73761f7af64432b6946934c3b1db646d8e99ef07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:05:46 +0200 Subject: Closure call now returns the total usage as well * Return the used gas value based on the UseGas and ReturnGas --- ethchain/closure.go | 22 ++++-- ethchain/state_manager.go | 38 ++++++---- ethchain/transaction_pool.go | 18 +++-- ethchain/vm.go | 164 +++++++++++++++++++++---------------------- 4 files changed, 138 insertions(+), 104 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index c935ed50a..f2b46e461 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -22,8 +22,7 @@ type Closure struct { Script []byte State *State - Gas *big.Int - Price *big.Int + Gas, UsedGas, Price *big.Int Args []byte } @@ -74,10 +73,12 @@ func (c *Closure) Address() []byte { type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool -func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { +func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, error) { c.Args = args - return vm.RunClosure(c, hook) + ret, err := vm.RunClosure(c, hook) + + return ret, c.UsedGas, err } func (c *Closure) Return(ret []byte) []byte { @@ -93,10 +94,23 @@ func (c *Closure) Return(ret []byte) []byte { return ret } +func (c *Closure) UseGas(gas *big.Int) bool { + if c.Gas.Cmp(gas) < 0 { + return false + } + + // Sub the amount of gas from the remaining + c.Gas.Sub(c.Gas, gas) + c.UsedGas.Add(c.UsedGas, gas) + + return true +} + // Implement the Callee interface func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { // Return the gas to the closure c.Gas.Add(c.Gas, gas) + c.UsedGas.Sub(c.UsedGas, gas) } func (c *Closure) Object() *StateObject { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 2d2a32e2f..1a9e9f601 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -106,7 +106,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra usedGas, err := sm.ApplyTransaction(state, block, tx) if err != nil { ethutil.Config.Log.Infoln(err) - continue + //continue } accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) @@ -119,7 +119,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra return receipts, txs } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) { +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { /* Applies transactions to the given state and creates new state objects where needed. @@ -129,9 +129,17 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac assume there's a return value. The return value will be set to the script section of the state object. */ - totalGasUsed := big.NewInt(0) + var ( + addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } + gas = new(big.Int) + script []byte + ) + totalGasUsed = big.NewInt(0) + // Apply the transaction to the current state - err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + addTotalGas(gas) + if tx.CreatesContract() { if err == nil { // Create a new state object and the transaction @@ -141,30 +149,32 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac // Evaluate the initialization script // and use the return value as the // script section for the state object. - script, err := sm.EvalScript(state, contract.Init(), contract, tx, block) + script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) + addTotalGas(gas) + if err != nil { - return nil, fmt.Errorf("[STATE] Error during init script run %v", err) + err = fmt.Errorf("[STATE] Error during init script run %v", err) + return } contract.script = script state.UpdateStateObject(contract) } else { - return nil, fmt.Errorf("[STATE] Unable to create contract") + err = fmt.Errorf("[STATE] Unable to create contract") } } else { - return nil, fmt.Errorf("[STATE] contract creation tx:", err) + err = fmt.Errorf("[STATE] contract creation tx: %v", err) } } else { // Find the state object at the "recipient" address. If // there's an object attempt to run the script. stateObject := state.GetStateObject(tx.Recipient) if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { - sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) - } else if err != nil { - return nil, fmt.Errorf("[STATE] process:", err) + _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) + addTotalGas(gas) } } - return totalGasUsed, nil + return } func (sm *StateManager) Process(block *Block, dontReact bool) error { @@ -349,7 +359,7 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, err error) { +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { account := state.GetAccount(tx.Sender()) err = account.ConvertGas(tx.Gas, tx.GasPrice) @@ -369,7 +379,7 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj Value: tx.Value, //Price: tx.GasPrice, }) - ret, err = closure.Call(vm, tx.Data, nil) + ret, gas, err = closure.Call(vm, tx.Data, nil) // Update the account (refunds) state.UpdateStateObject(account) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ee026ffdd..7198026a8 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,28 +91,37 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (gas *big.Int, err error) { defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) err = fmt.Errorf("%v", r) } }() + + gas = new(big.Int) + addGas := func(g *big.Int) { gas.Add(gas, g) } + // Get the sender sender := state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { - return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) + err = fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) + return } + txTotalBytes := big.NewInt(int64(len(tx.Data))) + txTotalBytes.Div(txTotalBytes, ethutil.Big32) + addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + // 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)) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) if sender.Amount.Cmp(totAmount) < 0 { - return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + return } - //fmt.Println(tx) // Get the receiver receiver := state.GetAccount(tx.Recipient) @@ -120,6 +129,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + addGas(GasTx) // Subtract the fee sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) } else { diff --git a/ethchain/vm.go b/ethchain/vm.go index 9821a839a..29eb4aaf5 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -21,11 +21,10 @@ var ( GasTx = big.NewInt(500) ) -func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int { +func CalculateTxGas(initSize *big.Int) *big.Int { totalGas := new(big.Int) - totalGas.Add(totalGas, GasCreate) - txTotalBytes := new(big.Int).Add(initSize, scriptSize) + txTotalBytes := new(big.Int).Set(initSize) txTotalBytes.Div(txTotalBytes, ethutil.Big32) totalGas.Add(totalGas, new(big.Int).Mul(txTotalBytes, GasSStore)) @@ -92,12 +91,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc := big.NewInt(0) // Current step count step := 0 + prevStep := 0 if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } for { + prevStep = step // The base for all big integer arithmetic base := new(big.Int) @@ -111,16 +112,16 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } gas := new(big.Int) - useGas := func(amount *big.Int) { + setStepGasUsage := func(amount *big.Int) { gas.Add(gas, amount) } switch op { - case oSHA3: - useGas(GasSha) - case oSLOAD: - useGas(GasSLoad) - case oSSTORE: + case SHA3: + setStepGasUsage(GasSha) + case SLOAD: + setStepGasUsage(GasSLoad) + case SSTORE: var mult *big.Int y, x := stack.Peekn() val := closure.GetMem(x) @@ -131,67 +132,64 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { mult = ethutil.Big1 } - useGas(new(big.Int).Mul(mult, GasSStore)) - case oBALANCE: - useGas(GasBalance) - case oCREATE: + setStepGasUsage(new(big.Int).Mul(mult, GasSStore)) + case BALANCE: + setStepGasUsage(GasBalance) + case CREATE: require(3) args := stack.Get(big.NewInt(3)) initSize := new(big.Int).Add(args[1], args[0]) - useGas(CalculateTxGas(initSize, ethutil.Big0)) - case oCALL: - useGas(GasCall) - case oMLOAD, oMSIZE, oMSTORE8, oMSTORE: - useGas(GasMemory) + setStepGasUsage(CalculateTxGas(initSize)) + case CALL: + setStepGasUsage(GasCall) + case MLOAD, MSIZE, MSTORE8, MSTORE: + setStepGasUsage(GasMemory) default: - useGas(GasStep) + setStepGasUsage(GasStep) } - if closure.Gas.Cmp(gas) < 0 { + if !closure.UseGas(gas) { ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } - // Sub the amount of gas from the remaining - closure.Gas.Sub(closure.Gas, gas) - switch op { - case oLOG: + case LOG: stack.Print() mem.Print() // 0x20 range - case oADD: + case ADD: require(2) x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) // Pop result back on the stack stack.Push(base) - case oSUB: + case SUB: require(2) x, y := stack.Popn() // (x - y) % 2 ** 256 base.Sub(x, y) // Pop result back on the stack stack.Push(base) - case oMUL: + case MUL: require(2) x, y := stack.Popn() // (x * y) % 2 ** 256 base.Mul(x, y) // Pop result back on the stack stack.Push(base) - case oDIV: + case DIV: require(2) x, y := stack.Popn() // floor(x / y) base.Div(x, y) // Pop result back on the stack stack.Push(base) - case oSDIV: + case SDIV: require(2) x, y := stack.Popn() // n > 2**255 @@ -208,12 +206,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } // Push result on to the stack stack.Push(z) - case oMOD: + case MOD: require(2) x, y := stack.Popn() base.Mod(x, y) stack.Push(base) - case oSMOD: + case SMOD: require(2) x, y := stack.Popn() // n > 2**255 @@ -230,17 +228,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } // Push result on to the stack stack.Push(z) - case oEXP: + case EXP: require(2) x, y := stack.Popn() base.Exp(x, y, Pow256) stack.Push(base) - case oNEG: + case NEG: require(1) base.Sub(Pow256, stack.Pop()) stack.Push(base) - case oLT: + case LT: require(2) x, y := stack.Popn() // x < y @@ -249,7 +247,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } - case oGT: + case GT: require(2) x, y := stack.Popn() // x > y @@ -258,7 +256,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } - case oEQ: + case EQ: require(2) x, y := stack.Popn() // x == y @@ -267,7 +265,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } - case oNOT: + case NOT: require(1) x := stack.Pop() if x.Cmp(ethutil.BigFalse) == 0 { @@ -277,7 +275,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } // 0x10 range - case oAND: + case AND: require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { @@ -286,7 +284,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigFalse) } - case oOR: + case OR: require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { @@ -294,11 +292,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } - case oXOR: + case XOR: require(2) x, y := stack.Popn() stack.Push(base.Xor(x, y)) - case oBYTE: + case BYTE: require(2) val, th := stack.Popn() if th.Cmp(big.NewInt(32)) < 0 { @@ -308,92 +306,92 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } // 0x20 range - case oSHA3: + case SHA3: require(2) size, offset := stack.Popn() data := mem.Get(offset.Int64(), size.Int64()) stack.Push(ethutil.BigD(data)) // 0x30 range - case oADDRESS: + case ADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) - case oBALANCE: + case BALANCE: stack.Push(closure.object.Amount) - case oORIGIN: + case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) - case oCALLER: + case CALLER: stack.Push(ethutil.BigD(closure.Callee().Address())) - case oCALLVALUE: + case CALLVALUE: stack.Push(vm.vars.Value) - case oCALLDATALOAD: + case CALLDATALOAD: require(1) offset := stack.Pop().Int64() val := closure.Args[offset : offset+32] stack.Push(ethutil.BigD(val)) - case oCALLDATASIZE: + case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) - case oGASPRICE: + case GASPRICE: stack.Push(closure.Price) // 0x40 range - case oPREVHASH: + case PREVHASH: stack.Push(ethutil.BigD(vm.vars.PrevHash)) - case oCOINBASE: + case COINBASE: stack.Push(ethutil.BigD(vm.vars.Coinbase)) - case oTIMESTAMP: + case TIMESTAMP: stack.Push(big.NewInt(vm.vars.Time)) - case oNUMBER: + case NUMBER: stack.Push(big.NewInt(int64(vm.vars.BlockNumber))) - case oDIFFICULTY: + case DIFFICULTY: stack.Push(vm.vars.Diff) - case oGASLIMIT: + case GASLIMIT: // TODO stack.Push(big.NewInt(0)) // 0x50 range - case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: - a := big.NewInt(int64(op) - int64(oPUSH1) + 1) + case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: + a := big.NewInt(int64(op) - int64(PUSH1) + 1) pc.Add(pc, ethutil.Big1) data := closure.Gets(pc, a) val := ethutil.BigD(data.Bytes()) // Push value to stack stack.Push(val) pc.Add(pc, a.Sub(a, big.NewInt(1))) - step++ - case oPOP: + step += int(op) - int(PUSH1) + 1 + case POP: require(1) stack.Pop() - case oDUP: + case DUP: require(1) stack.Push(stack.Peek()) - case oSWAP: + case SWAP: require(2) x, y := stack.Popn() stack.Push(y) stack.Push(x) - case oMLOAD: + case MLOAD: require(1) offset := stack.Pop() stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) - case oMSTORE: // Store the value at stack top-1 in to memory at location stack top + case MSTORE: // Store the value at stack top-1 in to memory at location stack top require(2) // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) - case oMSTORE8: + case MSTORE8: require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) - case oSLOAD: + case SLOAD: require(1) loc := stack.Pop() val := closure.GetMem(loc) //fmt.Println("get", val.BigInt(), "@", loc) stack.Push(val.BigInt()) - case oSSTORE: + case SSTORE: require(2) val, loc := stack.Popn() //fmt.Println("storing", val, "@", loc) @@ -401,13 +399,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) - case oJUMP: + case JUMP: require(1) pc = stack.Pop() // Reduce pc by one because of the increment that's at the end of this for loop //pc.Sub(pc, ethutil.Big1) continue - case oJUMPI: + case JUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { @@ -415,12 +413,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro //pc.Sub(pc, ethutil.Big1) continue } - case oPC: + case PC: stack.Push(pc) - case oMSIZE: + case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) // 0x60 range - case oCREATE: + case CREATE: require(3) value := stack.Pop() @@ -439,9 +437,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) - closure.Gas.Sub(closure.Gas, gas) + closure.UseGas(gas) + // Create the closure - closure := NewClosure(closure.callee, + c := NewClosure(closure.callee, closure.Object(), contract.initScript, vm.state, @@ -449,7 +448,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Price) // Call the closure and set the return value as // main script. - closure.Script, err = closure.Call(vm, nil, hook) + c.Script, _, err = c.Call(vm, nil, hook) + if err != nil { stack.Push(ethutil.BigFalse) @@ -460,7 +460,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.state.UpdateStateObject(contract) } - case oCALL: + case CALL: require(7) // Closure addr addr := stack.Pop() @@ -492,7 +492,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Copy gas = new(big.Int).Set(closure.Gas) } - closure.Gas.Sub(closure.Gas, gas) + closure.UseGas(gas) // Add the value to the state object contract.AddAmount(value) @@ -500,7 +500,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Create a new callable closure closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) - ret, err := closure.Call(vm, args, hook) + ret, _, err := closure.Call(vm, args, hook) if err != nil { stack.Push(ethutil.BigFalse) // Reset the changes applied this object @@ -516,13 +516,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) stack.Push(ethutil.BigFalse) } - case oRETURN: + case RETURN: require(2) size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) return closure.Return(ret), nil - case oSUICIDE: + case SUICIDE: require(1) receiver := vm.state.GetAccount(stack.Pop().Bytes()) @@ -532,7 +532,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.object.state.Purge() fallthrough - case oSTOP: // Stop the closure + case STOP: // Stop the closure return closure.Return(nil), nil default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) @@ -543,7 +543,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, ethutil.Big1) if hook != nil { - if !hook(step-1, op, mem, stack, closure.Object()) { + if !hook(prevStep, op, mem, stack, closure.Object()) { return nil, nil } } -- cgit v1.2.3 From 9988b1a04710e03ce7ed4b23393e2e90f06889f9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:06:09 +0200 Subject: Sort transactions based on the nonce * Added a transaction sorter --- ethchain/transaction.go | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2c5615f99..2cb946b3b 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -147,22 +147,6 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { if len(tx.Recipient) == 0 { tx.contractCreation = true } - - /* - // If the list is of length 10 it's a contract creation tx - if decoder.Len() == 10 { - tx.contractCreation = true - tx.Init = decoder.Get(6).Bytes() - - tx.v = byte(decoder.Get(7).Uint()) - tx.r = decoder.Get(8).Bytes() - tx.s = decoder.Get(9).Bytes() - } else { - tx.v = byte(decoder.Get(6).Uint()) - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() - } - */ } func (tx *Transaction) String() string { @@ -228,3 +212,15 @@ func (self *Receipt) String() string { self.PostState, self.CumulativeGasUsed) } + +// Transaction slice type for basic sorting +type Transactions []*Transaction + +func (s Transactions) Len() int { return len(s) } +func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +type TxByNonce struct{ Transactions } + +func (s TxByNonce) Less(i, j int) bool { + return s.Transactions[i].Nonce < s.Transactions[j].Nonce +} -- cgit v1.2.3 From 6e98e5709a68b1a84e9c3b391eab4a3546c4225d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:39:34 +0200 Subject: Set initial used gas --- ethchain/closure.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index f2b46e461..01fd5d794 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -35,6 +35,7 @@ func NewClosure(callee, object *StateObject, script []byte, state *State, gas, p // and we don't want the transaction's values to change. c.Gas = new(big.Int).Set(gas) c.Price = new(big.Int).Set(price) + c.UsedGas = new(big.Int) return c } -- cgit v1.2.3 From 65722aeeca0fed685a00d660ddd7bb667ac3be9b Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 13:14:56 +0200 Subject: Added StringToBytesFunc --- ethchain/vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 29eb4aaf5..85136e435 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -448,7 +448,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Price) // Call the closure and set the return value as // main script. - c.Script, _, err = c.Call(vm, nil, hook) + c.Script, gas, err = c.Call(vm, nil, hook) if err != nil { stack.Push(ethutil.BigFalse) -- cgit v1.2.3 From b695c82520548f62f65937731def1224c72dce48 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 15:07:11 +0200 Subject: Fixes #60 --- ethchain/state_manager.go | 7 +++++-- ethchain/transaction_pool.go | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1a9e9f601..a57377bee 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -105,8 +105,11 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra for _, tx := range txs { usedGas, err := sm.ApplyTransaction(state, block, tx) if err != nil { + if IsNonceErr(err) { + continue + } + ethutil.Config.Log.Infoln(err) - //continue } accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) @@ -116,7 +119,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra validTxs = append(validTxs, tx) } - return receipts, txs + return receipts, validTxs } func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 7198026a8..ba2ffcef5 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -106,7 +106,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract sender := state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { - err = fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) + err = NonceError(tx.Nonce, sender.Nonce) return } @@ -235,7 +235,7 @@ func (pool *TxPool) RemoveInvalid(state *State) { tx := e.Value.(*Transaction) sender := state.GetAccount(tx.Sender()) err := pool.ValidateTransaction(tx) - if err != nil || sender.Nonce != tx.Nonce { + if err != nil || sender.Nonce >= tx.Nonce { pool.pool.Remove(e) } } -- cgit v1.2.3 From 4d987624867fc02a079d8355c28bad620db85f06 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 23:16:54 +0200 Subject: Fixed state object gas return --- ethchain/closure.go | 8 ++++---- ethchain/vm.go | 12 +++++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 01fd5d794..5c9c3e47c 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -11,13 +11,13 @@ type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte GetMem(*big.Int) *ethutil.Value - SetStore(*big.Int, *ethutil.Value) + SetStorage(*big.Int, *ethutil.Value) N() *big.Int } // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee *StateObject + callee ClosureRef object *StateObject Script []byte State *State @@ -28,7 +28,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { +func NewClosure(callee ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects @@ -118,7 +118,7 @@ func (c *Closure) Object() *StateObject { return c.object } -func (c *Closure) Callee() *StateObject { +func (c *Closure) Callee() ClosureRef { return c.callee } diff --git a/ethchain/vm.go b/ethchain/vm.go index 85136e435..9720d8be1 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -326,9 +326,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALLDATALOAD: require(1) offset := stack.Pop().Int64() - val := closure.Args[offset : offset+32] - stack.Push(ethutil.BigD(val)) + var data []byte + if len(closure.Args) >= int(offset+32) { + data = closure.Args[offset : offset+32] + } else { + data = []byte{0} + } + + stack.Push(ethutil.BigD(data)) case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) case GASPRICE: @@ -498,7 +504,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro contract.AddAmount(value) // Create a new callable closure - closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price) + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) ret, _, err := closure.Call(vm, args, hook) if err != nil { -- cgit v1.2.3 From 8fcba0eb1e947061aadeea1059830dbcdfd2ef44 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 May 2014 23:54:48 +0200 Subject: fixed test --- ethchain/state_test.go | 1 - ethchain/vm_test.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_test.go b/ethchain/state_test.go index 4cc3fdf75..292129953 100644 --- a/ethchain/state_test.go +++ b/ethchain/state_test.go @@ -1,7 +1,6 @@ package ethchain import ( - "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" "testing" diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 520f9a2ed..518a88766 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -62,7 +62,7 @@ func TestRun4(t *testing.T) { Diff: big.NewInt(256), }) var ret []byte - ret, e = callerClosure.Call(vm, nil, nil) + ret, _, e = callerClosure.Call(vm, nil, nil) if e != nil { fmt.Println("error", e) } -- cgit v1.2.3 From fb6ff61730ed92ada68c9c5a5b3a6f9976a78161 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 2 Jun 2014 15:20:27 +0200 Subject: Implemented Public Peer interface --- ethchain/state_manager.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a57377bee..8479e9f44 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -2,6 +2,7 @@ package ethchain import ( "bytes" + "container/list" "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -14,6 +15,16 @@ type BlockProcessor interface { ProcessBlock(block *Block) } +type Peer interface { + Inbound() bool + LastSend() time.Time + LastPong() int64 + Host() []byte + Port() uint16 + Version() string + Connected() *int32 +} + type EthManager interface { StateManager() *StateManager BlockChain() *BlockChain @@ -23,6 +34,7 @@ type EthManager interface { PeerCount() int IsMining() bool IsListening() bool + Peers() *list.List } type StateManager struct { -- cgit v1.2.3 From 2010fea0888991e978e715477516bc374bb29f01 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 3 Jun 2014 10:42:55 +0200 Subject: Added faux latency for peeroverview --- ethchain/state_manager.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8479e9f44..8e5ca1b83 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -22,6 +22,7 @@ type Peer interface { Host() []byte Port() uint16 Version() string + PingTime() string Connected() *int32 } -- cgit v1.2.3 From d7b882977c4289bc2aabb51e1cf6b3577bc02aca Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 3 Jun 2014 11:56:19 +0200 Subject: Make contract creation error more explicit by mentioning the sneder --- ethchain/state_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8e5ca1b83..f1c09b819 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -178,7 +178,7 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac err = fmt.Errorf("[STATE] Unable to create contract") } } else { - err = fmt.Errorf("[STATE] contract creation tx: %v", err) + err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) } } else { // Find the state object at the "recipient" address. If -- cgit v1.2.3 From c7d1924c344535c2d54265728bc2aa429215e595 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 9 Jun 2014 21:35:56 +0200 Subject: sha --- ethchain/vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 9720d8be1..955be847f 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -309,7 +309,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SHA3: require(2) size, offset := stack.Popn() - data := mem.Get(offset.Int64(), size.Int64()) + data := ethutil.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) stack.Push(ethutil.BigD(data)) // 0x30 range -- cgit v1.2.3 From 2995d6c281b83f5bb055a22093b2b94e64c477d3 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 15:02:41 +0200 Subject: Validate minimum gasPrice and reject if not met --- ethchain/transaction_pool.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ba2ffcef5..d4175d973 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -22,6 +22,7 @@ type TxMsgTy byte const ( TxPre = iota TxPost + minGasPrice = 1000000 ) type TxMsg struct { @@ -172,6 +173,12 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } + if tx.IsContract() { + if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { + return fmt.Errorf("[TXPL] Gasprice to low, %s given should be at least %d.", tx.GasPrice, minGasPrice) + } + } + // Increment the nonce making each tx valid only once to prevent replay // attacks -- cgit v1.2.3 From 753f749423df7d5fba55a4080383d215db8e0fc7 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:22:06 +0200 Subject: Implement CalcGasPrice for ethereum/go-ethereum#77 --- ethchain/block.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 73e29f878..780c60869 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -154,6 +154,35 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { return true } +func (block *Block) CalcGasLimit(parent *Block) *big.Int { + if block.Number == big.NewInt(0) { + return ethutil.BigPow(10, 6) + } + previous := new(big.Int).Mul(big.NewInt(1023), parent.GasLimit) + current := new(big.Rat).Mul(new(big.Rat).SetInt(block.GasUsed), big.NewRat(6, 5)) + curInt := new(big.Int).Div(current.Num(), current.Denom()) + + result := new(big.Int).Add(previous, curInt) + result.Div(result, big.NewInt(1024)) + + min := ethutil.BigPow(10, 4) + + return ethutil.BigMax(min, result) + /* + base := new(big.Int) + base2 := new(big.Int) + parentGL := bc.CurrentBlock.GasLimit + parentUsed := bc.CurrentBlock.GasUsed + + base.Mul(parentGL, big.NewInt(1024-1)) + base2.Mul(parentUsed, big.NewInt(6)) + base2.Div(base2, big.NewInt(5)) + base.Add(base, base2) + base.Div(base, big.NewInt(1024)) + */ + +} + func (block *Block) BlockInfo() BlockInfo { bi := BlockInfo{} data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) -- cgit v1.2.3 From 69044fe5774840a49de3f881a490db52e907affb Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:22:43 +0200 Subject: Refactor to use new method --- ethchain/block_chain.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b45d254b5..5e6ce46e1 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -72,19 +72,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - // max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024) - base := new(big.Int) - base2 := new(big.Int) - parentGL := bc.CurrentBlock.GasLimit - parentUsed := bc.CurrentBlock.GasUsed - - base.Mul(parentGL, big.NewInt(1024-1)) - base2.Mul(parentUsed, big.NewInt(6)) - base2.Div(base2, big.NewInt(5)) - base.Add(base, base2) - base.Div(base, big.NewInt(1024)) - - block.GasLimit = ethutil.BigMax(big.NewInt(10000), base) + block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) } return block -- cgit v1.2.3 From bdc206885a1d9c730464f60ec65557403720be1e Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:23:32 +0200 Subject: Don't mine transactions if they would go over the GasLimit implements ethereum/go-ethereum#77 further. --- ethchain/error.go | 18 ++++++++++++++++++ ethchain/state_manager.go | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'ethchain') diff --git a/ethchain/error.go b/ethchain/error.go index 8d37b0208..29896bc59 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -2,6 +2,7 @@ package ethchain import ( "fmt" + "math/big" ) // Parent error. In case a parent is unknown this error will be thrown @@ -43,6 +44,23 @@ func IsValidationErr(err error) bool { return ok } +type GasLimitErr struct { + Message string + Is, Max *big.Int +} + +func IsGasLimitErr(err error) bool { + _, ok := err.(*GasLimitErr) + + return ok +} +func (err *GasLimitErr) Error() string { + return err.Message +} +func GasLimitError(is, max *big.Int) *GasLimitErr { + return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max} +} + type NonceErr struct { Message string Is, Exp uint64 diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f1c09b819..aea5433ff 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -114,6 +114,8 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra // Process each transaction/contract var receipts []*Receipt var validTxs []*Transaction + var ignoredTxs []*Transaction // Transactions which go over the gasLimit + totalUsedGas := big.NewInt(0) for _, tx := range txs { usedGas, err := sm.ApplyTransaction(state, block, tx) @@ -121,6 +123,12 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra if IsNonceErr(err) { continue } + if IsGasLimitErr(err) { + ignoredTxs = append(ignoredTxs, tx) + // We need to figure out if we want to do something with thse txes + ethutil.Config.Log.Debugln("Gastlimit:", err) + continue + } ethutil.Config.Log.Infoln(err) } @@ -151,6 +159,7 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac script []byte ) totalGasUsed = big.NewInt(0) + snapshot := state.Snapshot() // Apply the transaction to the current state gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) @@ -190,6 +199,14 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac } } + parent := sm.bc.GetBlock(block.PrevHash) + total := new(big.Int).Add(block.GasUsed, totalGasUsed) + limit := block.CalcGasLimit(parent) + if total.Cmp(limit) > 0 { + state.Revert(snapshot) + err = GasLimitError(total, limit) + } + return } -- cgit v1.2.3 From e090d131c38bef3c5f2d0f5e9fa28f5d0ed06659 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 11:40:40 +0200 Subject: Implemented counting of usedGas --- ethchain/state_manager.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index aea5433ff..6fb664e3d 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -140,6 +140,9 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra validTxs = append(validTxs, tx) } + // Update the total gas used for the block (to be mined) + block.GasUsed = totalUsedGas + return receipts, validTxs } -- cgit v1.2.3 From 1938bfcddfd2722880a692c59cad344b611711c8 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 16:16:57 +0200 Subject: Fix compare --- ethchain/block.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 780c60869..fee4a2d59 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -155,9 +155,10 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { } func (block *Block) CalcGasLimit(parent *Block) *big.Int { - if block.Number == big.NewInt(0) { + if block.Number.Cmp(big.NewInt(0)) == 0 { return ethutil.BigPow(10, 6) } + previous := new(big.Int).Mul(big.NewInt(1023), parent.GasLimit) current := new(big.Rat).Mul(new(big.Rat).SetInt(block.GasUsed), big.NewRat(6, 5)) curInt := new(big.Int).Div(current.Num(), current.Denom()) -- cgit v1.2.3 From 4d3209ad1d6ea6f7e4fc311c387392f23ebc7dde Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:23 +0200 Subject: Moved process transaction to state manager * Buy gas of the coinbase address --- ethchain/state_manager.go | 93 ++++++++++++++++++++++++++++++++++++++------ ethchain/transaction_pool.go | 29 +++++++++----- 2 files changed, 100 insertions(+), 22 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f1c09b819..e783ffdd8 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -108,15 +108,90 @@ func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObj return nil } +func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + gas = new(big.Int) + addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) + + // Get the sender + sender := state.GetAccount(tx.Sender()) + + if sender.Nonce != tx.Nonce { + err = NonceError(tx.Nonce, sender.Nonce) + return + } + + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + txTotalBytes := big.NewInt(int64(len(tx.Data))) + txTotalBytes.Div(txTotalBytes, ethutil.Big32) + addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + + // 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, rGas) + if sender.Amount.Cmp(totAmount) < 0 { + state.UpdateStateObject(sender) + err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + return + } + + coinbase.BuyGas(gas, tx.GasPrice) + state.UpdateStateObject(coinbase) + + // Get the receiver + receiver := state.GetAccount(tx.Recipient) + + // Send Tx to self + if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + // Subtract the fee + sender.SubAmount(rGas) + } else { + // Subtract the amount from the senders account + sender.SubAmount(totAmount) + + fmt.Printf("state root after sender update %x\n", state.Root()) + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(tx.Value) + state.UpdateStateObject(receiver) + + fmt.Printf("state root after receiver update %x\n", state.Root()) + } + + state.UpdateStateObject(sender) + + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + + return +} + // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. -func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { +func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { // Process each transaction/contract var receipts []*Receipt var validTxs []*Transaction totalUsedGas := big.NewInt(0) + for _, tx := range txs { - usedGas, err := sm.ApplyTransaction(state, block, tx) + usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) if err != nil { if IsNonceErr(err) { continue @@ -135,7 +210,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra return receipts, validTxs } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { +func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { /* Applies transactions to the given state and creates new state objects where needed. @@ -152,8 +227,9 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac ) totalGasUsed = big.NewInt(0) + ca := state.GetAccount(coinbase) // Apply the transaction to the current state - gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + gas, err = sm.ProcessTransaction(tx, ca, state, false) addTotalGas(gas) if tx.CreatesContract() { @@ -229,7 +305,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } // Process the transactions on to current block - sm.ApplyTransactions(state, parent, block.Transactions()) + sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -337,13 +413,6 @@ func CalculateBlockReward(block *Block, uncleLength int) *big.Int { base.Add(base, UncleInclusionReward) } - lastCumulGasUsed := big.NewInt(0) - for _, r := range block.Receipts() { - usedGas := new(big.Int).Sub(r.CumulativeGasUsed, lastCumulGasUsed) - usedGas.Add(usedGas, r.Tx.GasPrice) - base.Add(base, usedGas) - } - return base.Add(base, BlockReward) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ba2ffcef5..bc7bde797 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -89,9 +89,11 @@ func (pool *TxPool) addTransaction(tx *Transaction) { pool.Ethereum.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, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) @@ -101,6 +103,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract gas = new(big.Int) addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) // Get the sender sender := state.GetAccount(tx.Sender()) @@ -110,28 +113,37 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract return } + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + pool.Ethereum.Reactor().Post("newTx:post", tx) + }() + txTotalBytes := big.NewInt(int64(len(tx.Data))) txTotalBytes.Div(txTotalBytes, ethutil.Big32) addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + // 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)) - totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) + totAmount := new(big.Int).Add(tx.Value, rGas) if sender.Amount.Cmp(totAmount) < 0 { err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) return } + state.UpdateStateObject(sender) + fmt.Printf("state root after sender update %x\n", state.Root()) // Get the receiver receiver := state.GetAccount(tx.Recipient) - sender.Nonce += 1 // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - addGas(GasTx) // Subtract the fee - sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) + sender.SubAmount(rGas) } else { // Subtract the amount from the senders account sender.SubAmount(totAmount) @@ -140,17 +152,14 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract receiver.AddAmount(tx.Value) state.UpdateStateObject(receiver) + fmt.Printf("state root after receiver update %x\n", state.Root()) } - state.UpdateStateObject(sender) - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) - // Notify all subscribers - pool.Ethereum.Reactor().Post("newTx:post", tx) - return } +*/ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Get the last block so we can retrieve the sender and receiver from -- cgit v1.2.3 From 1bf6f8b4a6936d8ad14b345b2cfa4dc9d1f8a360 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:34 +0200 Subject: Added a buy gas method --- ethchain/state_object.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 3e9c6df40..a1dd531de 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -108,10 +108,14 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) + + ethutil.Config.Log.Debugf("%x: #%d %v (+ %v)", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) + + ethutil.Config.Log.Debugf("%x: #%d %v (- %v)", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -129,6 +133,17 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { return nil } +func (self *StateObject) BuyGas(gas, price *big.Int) error { + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, price) + + self.AddAmount(rGas) + + // TODO Do sub from TotalGasPool + // and check if enough left + return nil +} + // Returns the address of the contract/account func (c *StateObject) Address() []byte { return c.address @@ -153,14 +168,14 @@ func (c *StateObject) RlpEncode() []byte { root = "" } - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethutil.Sha3Bin(c.script)}) } func (c *StateObject) RlpDecode(data []byte) { decoder := ethutil.NewValueFromBytes(data) - c.Amount = decoder.Get(0).BigInt() - c.Nonce = decoder.Get(1).Uint() + c.Nonce = decoder.Get(0).Uint() + c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.ScriptHash = decoder.Get(3).Bytes() -- cgit v1.2.3 From 9ee6295c752a518603de01e4feaec787c61a5dcf Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:45 +0200 Subject: Minor changes --- ethchain/block_chain.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b45d254b5..68ef9d47e 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -271,7 +271,7 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { func AddTestNetFunds(block *Block) { for _, addr := range []string{ - "8a40bfaa73256b60764c1bf40675a99083efb075", + "51ba59315b3a95761d0863b05ccc7a7f54703d99", "e4157b34ea9615cfbde6b4fda419828124b70c78", "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", "6c386a4b26f73c802f34673f7248bb118f97424a", @@ -285,7 +285,6 @@ func AddTestNetFunds(block *Block) { account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } - log.Printf("%x\n", block.RlpEncode()) } func (bc *BlockChain) setLastBlock() { -- cgit v1.2.3 From 3a9d7d318abb3cd01ecd012ae85da5e586436d65 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 12 Jun 2014 10:07:27 +0200 Subject: log changes --- ethchain/transaction_pool.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index d4175d973..103c305fe 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -162,6 +162,10 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return errors.New("[TXPL] No last block on the block chain") } + if len(tx.Recipient) != 20 { + return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) + } + // Get the sender //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) @@ -207,6 +211,8 @@ out: // Call blocking version. pool.addTransaction(tx) + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) } -- cgit v1.2.3 From b855e5f7df194c84651d7cc7ee32d307a2fa0a2e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 12 Jun 2014 11:19:32 +0200 Subject: Changed opcode numbers and added missing opcodes --- ethchain/state_manager.go | 8 ++++---- ethchain/transaction.go | 4 +++- ethchain/types.go | 45 +++++++++++++++++++++++++++++++-------------- ethchain/vm.go | 5 +++++ 4 files changed, 43 insertions(+), 19 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 9631b55fe..7b44ba3b8 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -166,13 +166,9 @@ func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObj // Subtract the amount from the senders account sender.SubAmount(totAmount) - fmt.Printf("state root after sender update %x\n", state.Root()) - // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(tx.Value) state.UpdateStateObject(receiver) - - fmt.Printf("state root after receiver update %x\n", state.Root()) } state.UpdateStateObject(sender) @@ -215,6 +211,8 @@ func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block * validTxs = append(validTxs, tx) } + fmt.Println("################# MADE\n", receipts, "\n############################") + // Update the total gas used for the block (to be mined) block.GasUsed = totalUsedGas @@ -250,6 +248,7 @@ func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *B // as it's data provider. contract := sm.MakeStateObject(state, tx) if contract != nil { + fmt.Println(Disassemble(contract.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. @@ -323,6 +322,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { return ParentError(block.PrevHash) } + fmt.Println(block.Receipts()) // Process the transactions on to current block sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2cb946b3b..32dbd8388 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,6 +1,7 @@ package ethchain import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" @@ -144,7 +145,8 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.v = byte(decoder.Get(6).Uint()) tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() - if len(tx.Recipient) == 0 { + + if bytes.Compare(tx.Recipient, ContractAddr) == 0 { tx.contractCreation = true } } diff --git a/ethchain/types.go b/ethchain/types.go index 293871143..fdfd5792b 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -1,5 +1,9 @@ package ethchain +import ( + "fmt" +) + type OpCode int // Op codes @@ -37,7 +41,10 @@ const ( CALLVALUE = 0x34 CALLDATALOAD = 0x35 CALLDATASIZE = 0x36 - GASPRICE = 0x37 + CALLDATACOPY = 0x37 + CODESIZE = 0x38 + CODECOPY = 0x39 + GASPRICE = 0x3a // 0x40 range - block operations PREVHASH = 0x40 @@ -48,18 +55,19 @@ const ( GASLIMIT = 0x45 // 0x50 range - 'storage' and execution - POP = 0x51 - DUP = 0x52 - SWAP = 0x53 - MLOAD = 0x54 - MSTORE = 0x55 - MSTORE8 = 0x56 - SLOAD = 0x57 - SSTORE = 0x58 - JUMP = 0x59 - JUMPI = 0x5a - PC = 0x5b - MSIZE = 0x5c + POP = 0x50 + DUP = 0x51 + SWAP = 0x52 + MLOAD = 0x53 + MSTORE = 0x54 + MSTORE8 = 0x55 + SLOAD = 0x56 + SSTORE = 0x57 + JUMP = 0x58 + JUMPI = 0x59 + PC = 0x5a + MSIZE = 0x5b + GAS = 0x5c // 0x60 range PUSH1 = 0x60 @@ -140,6 +148,9 @@ var opCodeToString = map[OpCode]string{ CALLVALUE: "CALLVALUE", CALLDATALOAD: "CALLDATALOAD", CALLDATASIZE: "CALLDATASIZE", + CALLDATACOPY: "CALLDATACOPY", + CODESIZE: "CODESIZE", + CODECOPY: "CODECOPY", GASPRICE: "TXGASPRICE", // 0x40 range - block operations @@ -162,6 +173,7 @@ var opCodeToString = map[OpCode]string{ JUMPI: "JUMPI", PC: "PC", MSIZE: "MSIZE", + GAS: "GAS", // 0x60 range - push PUSH1: "PUSH1", @@ -208,7 +220,12 @@ var opCodeToString = map[OpCode]string{ } func (o OpCode) String() string { - return opCodeToString[o] + str := opCodeToString[o] + if len(str) == 0 { + return fmt.Sprintf("Missing opcode 0x%x", int(o)) + } + + return str } // Op codes for assembling diff --git a/ethchain/vm.go b/ethchain/vm.go index 955be847f..ebdc58659 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -337,6 +337,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigD(data)) case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) + case CALLDATACOPY: + case CODESIZE: + case CODECOPY: case GASPRICE: stack.Push(closure.Price) @@ -423,6 +426,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(pc) case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) + case GAS: + stack.Push(closure.Gas) // 0x60 range case CREATE: require(3) -- cgit v1.2.3 From d078e9b8c92fb3bd5789a8e39c169b19864e0a04 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:45:11 +0200 Subject: Refactoring state transitioning --- ethchain/asm.go | 12 +- ethchain/deprecated.go | 225 +++++++++++++++++++++++++++++ ethchain/error.go | 17 +++ ethchain/stack.go | 6 + ethchain/state_manager.go | 335 +++++++++++++++++++++++-------------------- ethchain/state_object.go | 2 +- ethchain/transaction.go | 16 ++- ethchain/transaction_pool.go | 2 +- ethchain/types.go | 8 +- ethchain/vm.go | 77 ++++++++-- 10 files changed, 509 insertions(+), 191 deletions(-) create mode 100644 ethchain/deprecated.go (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 430a89450..277326ff9 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -25,16 +25,10 @@ func Disassemble(script []byte) (asm []string) { pc.Add(pc, ethutil.Big1) a := int64(op) - int64(PUSH1) + 1 data := script[pc.Int64() : pc.Int64()+a] - val := ethutil.BigD(data) - - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() + if len(data) == 0 { + data = []byte{0} } - - asm = append(asm, fmt.Sprintf("0x%x", b)) + asm = append(asm, fmt.Sprintf("0x%x", data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/deprecated.go b/ethchain/deprecated.go new file mode 100644 index 000000000..ed2697e2a --- /dev/null +++ b/ethchain/deprecated.go @@ -0,0 +1,225 @@ +package ethchain + +import ( + "bytes" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { + account := state.GetAccount(tx.Sender()) + + err = account.ConvertGas(tx.Gas, tx.GasPrice) + if err != nil { + ethutil.Config.Log.Debugln(err) + return + } + + closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) + vm := NewVm(state, sm, RuntimeVars{ + Origin: account.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + //Price: tx.GasPrice, + }) + ret, gas, err = closure.Call(vm, tx.Data, nil) + + // Update the account (refunds) + state.UpdateStateObject(account) + state.UpdateStateObject(object) + + return +} + +func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + gas = new(big.Int) + addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) + + // Get the sender + sender := state.GetAccount(tx.Sender()) + + if sender.Nonce != tx.Nonce { + err = NonceError(tx.Nonce, sender.Nonce) + return + } + + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + txTotalBytes := big.NewInt(int64(len(tx.Data))) + //fmt.Println("txTotalBytes", txTotalBytes) + //txTotalBytes.Div(txTotalBytes, ethutil.Big32) + addGas(new(big.Int).Mul(txTotalBytes, GasData)) + + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + + // 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, rGas) + if sender.Amount.Cmp(totAmount) < 0 { + state.UpdateStateObject(sender) + err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + return + } + + coinbase.BuyGas(gas, tx.GasPrice) + state.UpdateStateObject(coinbase) + fmt.Printf("1. root %x\n", state.Root()) + + // Get the receiver + receiver := state.GetAccount(tx.Recipient) + + // Send Tx to self + if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + // Subtract the fee + sender.SubAmount(rGas) + } else { + // Subtract the amount from the senders account + sender.SubAmount(totAmount) + state.UpdateStateObject(sender) + fmt.Printf("3. root %x\n", state.Root()) + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(tx.Value) + state.UpdateStateObject(receiver) + fmt.Printf("2. root %x\n", state.Root()) + } + + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + + return +} + +func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { + /* + Applies transactions to the given state and creates new + state objects where needed. + + If said objects needs to be created + run the initialization script provided by the transaction and + assume there's a return value. The return value will be set to + the script section of the state object. + */ + var ( + addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } + gas = new(big.Int) + script []byte + ) + totalGasUsed = big.NewInt(0) + snapshot := state.Snapshot() + + ca := state.GetAccount(coinbase) + // Apply the transaction to the current state + gas, err = sm.ProcessTransaction(tx, ca, state, false) + addTotalGas(gas) + fmt.Println("gas used by tx", gas) + + if tx.CreatesContract() { + if err == nil { + // Create a new state object and the transaction + // as it's data provider. + contract := sm.MakeStateObject(state, tx) + if contract != nil { + fmt.Println(Disassemble(contract.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) + fmt.Println("gas used by eval", gas) + addTotalGas(gas) + fmt.Println("total =", totalGasUsed) + + fmt.Println("script len =", len(script)) + + if err != nil { + err = fmt.Errorf("[STATE] Error during init script run %v", err) + return + } + contract.script = script + state.UpdateStateObject(contract) + } else { + err = fmt.Errorf("[STATE] Unable to create contract") + } + } else { + err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) + } + } else { + // Find the state object at the "recipient" address. If + // there's an object attempt to run the script. + stateObject := state.GetStateObject(tx.Recipient) + if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { + _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) + addTotalGas(gas) + } + } + + parent := sm.bc.GetBlock(block.PrevHash) + total := new(big.Int).Add(block.GasUsed, totalGasUsed) + limit := block.CalcGasLimit(parent) + if total.Cmp(limit) > 0 { + state.Revert(snapshot) + err = GasLimitError(total, limit) + } + + return +} + +// Apply transactions uses the transaction passed to it and applies them onto +// the current processing state. +func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { + // Process each transaction/contract + var receipts []*Receipt + var validTxs []*Transaction + var ignoredTxs []*Transaction // Transactions which go over the gasLimit + + totalUsedGas := big.NewInt(0) + + for _, tx := range txs { + usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) + if err != nil { + if IsNonceErr(err) { + continue + } + if IsGasLimitErr(err) { + ignoredTxs = append(ignoredTxs, tx) + // We need to figure out if we want to do something with thse txes + ethutil.Config.Log.Debugln("Gastlimit:", err) + continue + } + + ethutil.Config.Log.Infoln(err) + } + + accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) + receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + + receipts = append(receipts, receipt) + validTxs = append(validTxs, tx) + } + + fmt.Println("################# MADE\n", receipts, "\n############################") + + // Update the total gas used for the block (to be mined) + block.GasUsed = totalUsedGas + + return receipts, validTxs +} diff --git a/ethchain/error.go b/ethchain/error.go index 29896bc59..2cf09a1ec 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -79,3 +79,20 @@ func IsNonceErr(err error) bool { return ok } + +type OutOfGasErr struct { + Message string +} + +func OutOfGasError() *OutOfGasErr { + return &OutOfGasErr{Message: "Out of gas"} +} +func (self *OutOfGasErr) Error() string { + return self.Message +} + +func IsOutOfGasErr(err error) bool { + _, ok := err.(*OutOfGasErr) + + return ok +} diff --git a/ethchain/stack.go b/ethchain/stack.go index bf34e6ea9..37d1f84b9 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -111,6 +111,12 @@ func (m *Memory) Set(offset, size int64, value []byte) { copy(m.store[offset:offset+size], value) } +func (m *Memory) Resize(size uint64) { + if uint64(m.Len()) < size { + m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) + } +} + func (m *Memory) Get(offset, size int64) []byte { return m.store[offset : offset+size] } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 7b44ba3b8..f44afecac 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -108,8 +108,86 @@ func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObj return nil } -func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { - fmt.Printf("state root before update %x\n", state.Root()) +type StateTransition struct { + coinbase []byte + tx *Transaction + gas *big.Int + state *State + block *Block + + cb, rec, sen *StateObject +} + +func NewStateTransition(coinbase []byte, gas *big.Int, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +} + +func (self *StateTransition) Coinbase() *StateObject { + if self.cb != nil { + return self.cb + } + + self.cb = self.state.GetAccount(self.coinbase) + return self.cb +} +func (self *StateTransition) Sender() *StateObject { + if self.sen != nil { + return self.sen + } + + self.sen = self.state.GetAccount(self.tx.Sender()) + return self.sen +} +func (self *StateTransition) Receiver() *StateObject { + if self.tx.CreatesContract() { + return nil + } + + if self.rec != nil { + return self.rec + } + + self.rec = self.state.GetAccount(self.tx.Recipient) + return self.rec +} + +func (self *StateTransition) UseGas(amount *big.Int) error { + if self.gas.Cmp(amount) < 0 { + return OutOfGasError() + } + self.gas.Sub(self.gas, amount) + + return nil +} + +func (self *StateTransition) AddGas(amount *big.Int) { + self.gas.Add(self.gas, amount) +} + +func (self *StateTransition) BuyGas() error { + var err error + + sender := self.Sender() + if sender.Amount.Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) + } + + coinbase := self.Coinbase() + err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + if err != nil { + return err + } + self.state.UpdateStateObject(coinbase) + + self.AddGas(self.tx.Gas) + sender.SubAmount(self.tx.GasValue()) + + return nil +} + +func (self *StateManager) TransitionState(st *StateTransition) (err error) { + //snapshot := st.state.Snapshot() + defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) @@ -117,173 +195,144 @@ func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObj } }() - gas = new(big.Int) - addGas := func(g *big.Int) { gas.Add(gas, g) } - addGas(GasTx) - - // Get the sender - sender := state.GetAccount(tx.Sender()) + var ( + tx = st.tx + sender = st.Sender() + receiver *StateObject + ) if sender.Nonce != tx.Nonce { - err = NonceError(tx.Nonce, sender.Nonce) - return + return NonceError(tx.Nonce, sender.Nonce) } sender.Nonce += 1 defer func() { - //state.UpdateStateObject(sender) // Notify all subscribers self.Ethereum.Reactor().Post("newTx:post", tx) }() - txTotalBytes := big.NewInt(int64(len(tx.Data))) - txTotalBytes.Div(txTotalBytes, ethutil.Big32) - addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + if err = st.BuyGas(); err != nil { + return err + } - rGas := new(big.Int).Set(gas) - rGas.Mul(gas, tx.GasPrice) + receiver = st.Receiver() - // 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, rGas) - if sender.Amount.Cmp(totAmount) < 0 { - state.UpdateStateObject(sender) - err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) - return + if err = st.UseGas(GasTx); err != nil { + return err } - coinbase.BuyGas(gas, tx.GasPrice) - state.UpdateStateObject(coinbase) - - // Get the receiver - receiver := state.GetAccount(tx.Recipient) + dataPrice := big.NewInt(int64(len(tx.Data))) + dataPrice.Mul(dataPrice, GasData) + if err = st.UseGas(dataPrice); err != nil { + return err + } - // Send Tx to self - if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - // Subtract the fee - sender.SubAmount(rGas) - } else { - // Subtract the amount from the senders account - sender.SubAmount(totAmount) + if receiver == nil { // Contract + receiver = self.MakeStateObject(st.state, tx) + if receiver == nil { + return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) + } + } - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(tx.Value) - state.UpdateStateObject(receiver) + if err = self.transferValue(st, sender, receiver); err != nil { + return err } - state.UpdateStateObject(sender) + if tx.CreatesContract() { + fmt.Println(Disassemble(receiver.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) + code, err := self.Eval(st, receiver.Init(), receiver) + if err != nil { + return fmt.Errorf("Error during init script run %v", err) + } - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + receiver.script = code + } - return + st.state.UpdateStateObject(sender) + st.state.UpdateStateObject(receiver) + + return nil } -// Apply transactions uses the transaction passed to it and applies them onto -// the current processing state. -func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { - // Process each transaction/contract - var receipts []*Receipt - var validTxs []*Transaction - var ignoredTxs []*Transaction // Transactions which go over the gasLimit +func (self *StateManager) transferValue(st *StateTransition, sender, receiver *StateObject) error { + if sender.Amount.Cmp(st.tx.Value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", st.tx.Value, sender.Amount) + } + + // Subtract the amount from the senders account + sender.SubAmount(st.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(st.tx.Value) - totalUsedGas := big.NewInt(0) + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], st.tx.Value, st.tx.Hash()) - for _, tx := range txs { - usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) + return nil +} + +func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { + var ( + receipts Receipts + handled, unhandled Transactions + totalUsedGas = big.NewInt(0) + err error + ) + +done: + for i, tx := range txs { + txGas := new(big.Int).Set(tx.Gas) + st := NewStateTransition(coinbase, tx.Gas, tx, state, block) + err = self.TransitionState(st) if err != nil { - if IsNonceErr(err) { - continue - } - if IsGasLimitErr(err) { - ignoredTxs = append(ignoredTxs, tx) - // We need to figure out if we want to do something with thse txes - ethutil.Config.Log.Debugln("Gastlimit:", err) + switch { + case IsNonceErr(err): + err = nil // ignore error continue - } + case IsGasLimitErr(err): + unhandled = txs[i:] - ethutil.Config.Log.Infoln(err) + break done + default: + ethutil.Config.Log.Infoln(err) + } } - accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) + txGas.Sub(txGas, st.gas) + accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} receipts = append(receipts, receipt) - validTxs = append(validTxs, tx) + handled = append(handled, tx) } fmt.Println("################# MADE\n", receipts, "\n############################") - // Update the total gas used for the block (to be mined) - block.GasUsed = totalUsedGas + parent.GasUsed = totalUsedGas - return receipts, validTxs + return receipts, handled, unhandled, err } -func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { - /* - Applies transactions to the given state and creates new - state objects where needed. - - If said objects needs to be created - run the initialization script provided by the transaction and - assume there's a return value. The return value will be set to - the script section of the state object. - */ +func (self *StateManager) Eval(st *StateTransition, script []byte, context *StateObject) (ret []byte, err error) { var ( - addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } - gas = new(big.Int) - script []byte + tx = st.tx + block = st.block + initiator = st.Sender() ) - totalGasUsed = big.NewInt(0) - snapshot := state.Snapshot() - ca := state.GetAccount(coinbase) - // Apply the transaction to the current state - gas, err = sm.ProcessTransaction(tx, ca, state, false) - addTotalGas(gas) - - if tx.CreatesContract() { - if err == nil { - // Create a new state object and the transaction - // as it's data provider. - contract := sm.MakeStateObject(state, tx) - if contract != nil { - fmt.Println(Disassemble(contract.Init())) - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) - addTotalGas(gas) - - if err != nil { - err = fmt.Errorf("[STATE] Error during init script run %v", err) - return - } - contract.script = script - state.UpdateStateObject(contract) - } else { - err = fmt.Errorf("[STATE] Unable to create contract") - } - } else { - err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) - } - } else { - // Find the state object at the "recipient" address. If - // there's an object attempt to run the script. - stateObject := state.GetStateObject(tx.Recipient) - if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { - _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) - addTotalGas(gas) - } - } - - parent := sm.bc.GetBlock(block.PrevHash) - total := new(big.Int).Add(block.GasUsed, totalGasUsed) - limit := block.CalcGasLimit(parent) - if total.Cmp(limit) > 0 { - state.Revert(snapshot) - err = GasLimitError(total, limit) - } + closure := NewClosure(initiator, context, script, st.state, st.gas, tx.GasPrice) + vm := NewVm(st.state, self, RuntimeVars{ + Origin: initiator.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + }) + ret, _, err = closure.Call(vm, tx.Data, nil) return } @@ -325,7 +374,8 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea fmt.Println(block.Receipts()) // Process the transactions on to current block - sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) + //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) + sm.ProcessTransactions(block.Coinbase, state, block, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -464,35 +514,6 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { - account := state.GetAccount(tx.Sender()) - - err = account.ConvertGas(tx.Gas, tx.GasPrice) - if err != nil { - ethutil.Config.Log.Debugln(err) - return - } - - closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) - vm := NewVm(state, sm, RuntimeVars{ - Origin: account.Address(), - BlockNumber: block.BlockInfo().Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: tx.Value, - //Price: tx.GasPrice, - }) - ret, gas, err = closure.Call(vm, tx.Data, nil) - - // Update the account (refunds) - state.UpdateStateObject(account) - state.UpdateStateObject(object) - - return -} - func (sm *StateManager) notifyChanges(state *State) { for addr, stateObject := range state.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index a1dd531de..b92374882 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -135,7 +135,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) BuyGas(gas, price *big.Int) error { rGas := new(big.Int).Set(gas) - rGas.Mul(gas, price) + rGas.Mul(rGas, price) self.AddAmount(rGas) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 32dbd8388..7aaab2fd1 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -46,15 +46,18 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { return tx } +func (self *Transaction) GasValue() *big.Int { + return new(big.Int).Mul(self.Gas, self.GasPrice) +} + +func (self *Transaction) TotalValue() *big.Int { + v := self.GasValue() + return v.Add(v, self.Value) +} + func (tx *Transaction) Hash() []byte { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - /* - if tx.contractCreation { - data = append(data, tx.Init) - } - */ - return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } @@ -185,6 +188,7 @@ type Receipt struct { PostState []byte CumulativeGasUsed *big.Int } +type Receipts []*Receipt func NewRecieptFromValue(val *ethutil.Value) *Receipt { r := &Receipt{} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 52c850ba3..6538b0029 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -220,7 +220,7 @@ out: // Call blocking version. pool.addTransaction(tx) - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + ethutil.Config.Log.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) diff --git a/ethchain/types.go b/ethchain/types.go index fdfd5792b..ee70a8d28 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -21,8 +21,10 @@ const ( NEG = 0x09 LT = 0x0a GT = 0x0b - EQ = 0x0c - NOT = 0x0d + SLT = 0x0c + SGT = 0x0d + EQ = 0x0e + NOT = 0x0f // 0x10 range - bit ops AND = 0x10 @@ -128,6 +130,8 @@ var opCodeToString = map[OpCode]string{ NEG: "NEG", LT: "LT", GT: "GT", + SLT: "SLT", + SGT: "SGT", EQ: "EQ", NOT: "NOT", diff --git a/ethchain/vm.go b/ethchain/vm.go index ebdc58659..e17264697 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" + "math" _ "math" "math/big" ) @@ -18,6 +19,7 @@ var ( GasCreate = big.NewInt(100) GasCall = big.NewInt(20) GasMemory = big.NewInt(1) + GasData = big.NewInt(5) GasTx = big.NewInt(500) ) @@ -116,9 +118,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro gas.Add(gas, amount) } + var newMemSize uint64 = 0 switch op { - case SHA3: - setStepGasUsage(GasSha) case SLOAD: setStepGasUsage(GasSLoad) case SSTORE: @@ -135,27 +136,61 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro setStepGasUsage(new(big.Int).Mul(mult, GasSStore)) case BALANCE: setStepGasUsage(GasBalance) - case CREATE: + case MSTORE: + require(2) + newMemSize = stack.Peek().Uint64() + 32 + case MSTORE8: + require(2) + newMemSize = stack.Peek().Uint64() + 1 + case RETURN: + require(2) + + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() + case SHA3: + require(2) + + setStepGasUsage(GasSha) + + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() + case CALLDATACOPY: require(3) - args := stack.Get(big.NewInt(3)) - initSize := new(big.Int).Add(args[1], args[0]) + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() + case CODECOPY: + require(3) - setStepGasUsage(CalculateTxGas(initSize)) + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() case CALL: + require(7) setStepGasUsage(GasCall) - case MLOAD, MSIZE, MSTORE8, MSTORE: - setStepGasUsage(GasMemory) + + x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() + y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() + + newMemSize = uint64(math.Max(float64(x), float64(y))) + case CREATE: + require(3) + setStepGasUsage(GasCreate) + + newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() default: setStepGasUsage(GasStep) } + newMemSize = (newMemSize + 31) / 32 * 32 + if newMemSize > uint64(mem.Len()) { + m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 + setStepGasUsage(big.NewInt(int64(m))) + } + if !closure.UseGas(gas) { ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + mem.Resize(newMemSize) + switch op { case LOG: stack.Print() @@ -340,6 +375,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALLDATACOPY: case CODESIZE: case CODECOPY: + var ( + size = int64(len(closure.Script)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + code := closure.Script[cOff : cOff+l] + + mem.Set(mOff, l, code) case GASPRICE: stack.Push(closure.Price) @@ -448,7 +500,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) - closure.UseGas(gas) + //closure.UseGas(gas) // Create the closure c := NewClosure(closure.callee, @@ -498,12 +550,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if contract != nil { // Prepay for the gas - // If gas is set to 0 use all remaining gas for the next call - if gas.Cmp(big.NewInt(0)) == 0 { - // Copy - gas = new(big.Int).Set(closure.Gas) - } - closure.UseGas(gas) + //closure.UseGas(gas) // Add the value to the state object contract.AddAmount(value) -- cgit v1.2.3 From 5e2bf12a31e3e3a026d0f8d28c2d5bba919fc224 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:57:52 +0200 Subject: Refactored state transitioning to its own model --- ethchain/deprecated.go | 11 +++ ethchain/state_manager.go | 202 +--------------------------------------------- 2 files changed, 13 insertions(+), 200 deletions(-) (limited to 'ethchain') diff --git a/ethchain/deprecated.go b/ethchain/deprecated.go index ed2697e2a..0985fa25d 100644 --- a/ethchain/deprecated.go +++ b/ethchain/deprecated.go @@ -7,6 +7,17 @@ import ( "math/big" ) +func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) + if contract != nil { + state.states[string(tx.CreationAddress())] = contract.state + + return contract + } + + return nil +} + func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { account := state.GetAccount(tx.Sender()) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f44afecac..576afa8d3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -97,182 +97,6 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { - contract := MakeContract(tx, state) - if contract != nil { - state.states[string(tx.CreationAddress())] = contract.state - - return contract - } - - return nil -} - -type StateTransition struct { - coinbase []byte - tx *Transaction - gas *big.Int - state *State - block *Block - - cb, rec, sen *StateObject -} - -func NewStateTransition(coinbase []byte, gas *big.Int, tx *Transaction, state *State, block *Block) *StateTransition { - return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} -} - -func (self *StateTransition) Coinbase() *StateObject { - if self.cb != nil { - return self.cb - } - - self.cb = self.state.GetAccount(self.coinbase) - return self.cb -} -func (self *StateTransition) Sender() *StateObject { - if self.sen != nil { - return self.sen - } - - self.sen = self.state.GetAccount(self.tx.Sender()) - return self.sen -} -func (self *StateTransition) Receiver() *StateObject { - if self.tx.CreatesContract() { - return nil - } - - if self.rec != nil { - return self.rec - } - - self.rec = self.state.GetAccount(self.tx.Recipient) - return self.rec -} - -func (self *StateTransition) UseGas(amount *big.Int) error { - if self.gas.Cmp(amount) < 0 { - return OutOfGasError() - } - self.gas.Sub(self.gas, amount) - - return nil -} - -func (self *StateTransition) AddGas(amount *big.Int) { - self.gas.Add(self.gas, amount) -} - -func (self *StateTransition) BuyGas() error { - var err error - - sender := self.Sender() - if sender.Amount.Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) - } - - coinbase := self.Coinbase() - err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) - if err != nil { - return err - } - self.state.UpdateStateObject(coinbase) - - self.AddGas(self.tx.Gas) - sender.SubAmount(self.tx.GasValue()) - - return nil -} - -func (self *StateManager) TransitionState(st *StateTransition) (err error) { - //snapshot := st.state.Snapshot() - - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("%v", r) - } - }() - - var ( - tx = st.tx - sender = st.Sender() - receiver *StateObject - ) - - if sender.Nonce != tx.Nonce { - return NonceError(tx.Nonce, sender.Nonce) - } - - sender.Nonce += 1 - defer func() { - // Notify all subscribers - self.Ethereum.Reactor().Post("newTx:post", tx) - }() - - if err = st.BuyGas(); err != nil { - return err - } - - receiver = st.Receiver() - - if err = st.UseGas(GasTx); err != nil { - return err - } - - dataPrice := big.NewInt(int64(len(tx.Data))) - dataPrice.Mul(dataPrice, GasData) - if err = st.UseGas(dataPrice); err != nil { - return err - } - - if receiver == nil { // Contract - receiver = self.MakeStateObject(st.state, tx) - if receiver == nil { - return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) - } - } - - if err = self.transferValue(st, sender, receiver); err != nil { - return err - } - - if tx.CreatesContract() { - fmt.Println(Disassemble(receiver.Init())) - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) - code, err := self.Eval(st, receiver.Init(), receiver) - if err != nil { - return fmt.Errorf("Error during init script run %v", err) - } - - receiver.script = code - } - - st.state.UpdateStateObject(sender) - st.state.UpdateStateObject(receiver) - - return nil -} - -func (self *StateManager) transferValue(st *StateTransition, sender, receiver *StateObject) error { - if sender.Amount.Cmp(st.tx.Value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", st.tx.Value, sender.Amount) - } - - // Subtract the amount from the senders account - sender.SubAmount(st.tx.Value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(st.tx.Value) - - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], st.tx.Value, st.tx.Hash()) - - return nil -} - func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { var ( receipts Receipts @@ -284,8 +108,8 @@ func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, blo done: for i, tx := range txs { txGas := new(big.Int).Set(tx.Gas) - st := NewStateTransition(coinbase, tx.Gas, tx, state, block) - err = self.TransitionState(st) + st := NewStateTransition(coinbase, tx, state, block) + err = st.TransitionState() if err != nil { switch { case IsNonceErr(err): @@ -315,28 +139,6 @@ done: return receipts, handled, unhandled, err } -func (self *StateManager) Eval(st *StateTransition, script []byte, context *StateObject) (ret []byte, err error) { - var ( - tx = st.tx - block = st.block - initiator = st.Sender() - ) - - closure := NewClosure(initiator, context, script, st.state, st.gas, tx.GasPrice) - vm := NewVm(st.state, self, RuntimeVars{ - Origin: initiator.Address(), - BlockNumber: block.BlockInfo().Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: tx.Value, - }) - ret, _, err = closure.Call(vm, tx.Data, nil) - - return -} - func (sm *StateManager) Process(block *Block, dontReact bool) error { if !sm.bc.HasBlock(block.PrevHash) { return ParentError(block.PrevHash) -- cgit v1.2.3 From cebf4e3697dcd20e290ff56ad6e5dfca2059c063 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:58:01 +0200 Subject: Refactored state transitioning to its own model --- ethchain/state_transition.go | 206 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 ethchain/state_transition.go (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go new file mode 100644 index 000000000..6ec9205e9 --- /dev/null +++ b/ethchain/state_transition.go @@ -0,0 +1,206 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type StateTransition struct { + coinbase []byte + tx *Transaction + gas *big.Int + state *State + block *Block + + cb, rec, sen *StateObject +} + +func NewStateTransition(coinbase []byte, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +} + +func (self *StateTransition) Coinbase() *StateObject { + if self.cb != nil { + return self.cb + } + + self.cb = self.state.GetAccount(self.coinbase) + return self.cb +} +func (self *StateTransition) Sender() *StateObject { + if self.sen != nil { + return self.sen + } + + self.sen = self.state.GetAccount(self.tx.Sender()) + return self.sen +} +func (self *StateTransition) Receiver() *StateObject { + if self.tx.CreatesContract() { + return nil + } + + if self.rec != nil { + return self.rec + } + + self.rec = self.state.GetAccount(self.tx.Recipient) + return self.rec +} + +func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) + if contract != nil { + state.states[string(tx.CreationAddress())] = contract.state + + return contract + } + + return nil +} + +func (self *StateTransition) UseGas(amount *big.Int) error { + if self.gas.Cmp(amount) < 0 { + return OutOfGasError() + } + self.gas.Sub(self.gas, amount) + + return nil +} + +func (self *StateTransition) AddGas(amount *big.Int) { + self.gas.Add(self.gas, amount) +} + +func (self *StateTransition) BuyGas() error { + var err error + + sender := self.Sender() + if sender.Amount.Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) + } + + coinbase := self.Coinbase() + err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + if err != nil { + return err + } + self.state.UpdateStateObject(coinbase) + + self.AddGas(self.tx.Gas) + sender.SubAmount(self.tx.GasValue()) + + return nil +} + +func (self *StateTransition) TransitionState() (err error) { + //snapshot := st.state.Snapshot() + + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + var ( + tx = self.tx + sender = self.Sender() + receiver *StateObject + ) + + if sender.Nonce != tx.Nonce { + return NonceError(tx.Nonce, sender.Nonce) + } + + sender.Nonce += 1 + defer func() { + // Notify all subscribers + //self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + if err = self.BuyGas(); err != nil { + return err + } + + receiver = self.Receiver() + + if err = self.UseGas(GasTx); err != nil { + return err + } + + dataPrice := big.NewInt(int64(len(tx.Data))) + dataPrice.Mul(dataPrice, GasData) + if err = self.UseGas(dataPrice); err != nil { + return err + } + + if receiver == nil { // Contract + receiver = self.MakeStateObject(self.state, tx) + if receiver == nil { + return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) + } + } + + if err = self.transferValue(sender, receiver); err != nil { + return err + } + + if tx.CreatesContract() { + fmt.Println(Disassemble(receiver.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) + code, err := self.Eval(receiver.Init(), receiver) + if err != nil { + return fmt.Errorf("Error during init script run %v", err) + } + + receiver.script = code + } + + self.state.UpdateStateObject(sender) + self.state.UpdateStateObject(receiver) + + return nil +} + +func (self *StateTransition) transferValue(sender, receiver *StateObject) error { + if sender.Amount.Cmp(self.tx.Value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.tx.Value, sender.Amount) + } + + // Subtract the amount from the senders account + sender.SubAmount(self.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.tx.Value) + + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + + return nil +} + +func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { + var ( + tx = self.tx + block = self.block + initiator = self.Sender() + state = self.state + ) + + closure := NewClosure(initiator, context, script, state, self.gas, tx.GasPrice) + vm := NewVm(state, nil, RuntimeVars{ + Origin: initiator.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + }) + ret, _, err = closure.Call(vm, tx.Data, nil) + + return +} -- cgit v1.2.3 From c734dde982c4ce778afa074e94efb09e552dbd84 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 13:06:27 +0200 Subject: comments & refactor --- ethchain/state_manager.go | 4 +++- ethchain/state_transition.go | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 576afa8d3..c68d5e001 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -124,6 +124,9 @@ done: } } + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + txGas.Sub(txGas, st.gas) accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} @@ -158,7 +161,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea hash := block.Hash() if sm.bc.HasBlock(hash) { - //fmt.Println("[STATE] We already have this block, ignoring") return nil } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 6ec9205e9..1256d019c 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -6,6 +6,22 @@ import ( "math/big" ) +/* + * The State transitioning model + * + * A state transition is a change made when a transaction is applied to the current world state + * The state transitioning model does all all the necessary work to work out a valid new state root. + * 1) Nonce handling + * 2) Pre pay / buy gas of the coinbase (miner) + * 3) Create a new state object if the recipient is \0*32 + * 4) Value transfer + * == If contract creation == + * 4a) Attempt to run transaction data + * 4b) If valid, use result as code for the new state object + * == end == + * 5) Run Script section + * 6) Derive new state root + */ type StateTransition struct { coinbase []byte tx *Transaction @@ -115,10 +131,6 @@ func (self *StateTransition) TransitionState() (err error) { } sender.Nonce += 1 - defer func() { - // Notify all subscribers - //self.Ethereum.Reactor().Post("newTx:post", tx) - }() if err = self.BuyGas(); err != nil { return err -- cgit v1.2.3 From 81245473486dd680b7121d4b227ca8a57d07b4b1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 16:06:27 +0200 Subject: Moving a head closer to interop --- ethchain/closure.go | 26 ++++++++++++++------------ ethchain/state_object.go | 8 +++++--- ethchain/state_transition.go | 32 ++++++++++++++++++++++++-------- ethchain/vm.go | 31 ++++++++++++++++++------------- 4 files changed, 61 insertions(+), 36 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 5c9c3e47c..32b297e90 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -17,7 +17,7 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee ClosureRef + caller ClosureRef object *StateObject Script []byte State *State @@ -28,12 +28,14 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { - c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} +func NewClosure(caller ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { + c := &Closure{caller: caller, object: object, Script: script, State: state, Args: nil} - // In most cases gas, price and value are pointers to transaction objects + // Gas should be a pointer so it can safely be reduced through the run + // This pointer will be off the state transition + c.Gas = gas //new(big.Int).Set(gas) + // In most cases price and value are pointers to transaction objects // and we don't want the transaction's values to change. - c.Gas = new(big.Int).Set(gas) c.Price = new(big.Int).Set(price) c.UsedGas = new(big.Int) @@ -83,11 +85,11 @@ func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, e } func (c *Closure) Return(ret []byte) []byte { - // Return the remaining gas to the callee - // If no callee is present return it to + // Return the remaining gas to the caller + // If no caller is present return it to // the origin (i.e. contract or tx) - if c.callee != nil { - c.callee.ReturnGas(c.Gas, c.Price, c.State) + if c.caller != nil { + c.caller.ReturnGas(c.Gas, c.Price, c.State) } else { c.object.ReturnGas(c.Gas, c.Price, c.State) } @@ -107,7 +109,7 @@ func (c *Closure) UseGas(gas *big.Int) bool { return true } -// Implement the Callee interface +// Implement the caller interface func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { // Return the gas to the closure c.Gas.Add(c.Gas, gas) @@ -118,8 +120,8 @@ func (c *Closure) Object() *StateObject { return c.object } -func (c *Closure) Callee() ClosureRef { - return c.callee +func (c *Closure) Caller() ClosureRef { + return c.caller } func (c *Closure) N() *big.Int { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index b92374882..12ebf8e9b 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -77,7 +77,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) - //fmt.Println("storing", val.BigInt(), "@", num) + //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } @@ -102,8 +102,10 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { - remainder := new(big.Int).Mul(gas, price) - c.AddAmount(remainder) + /* + remainder := new(big.Int).Mul(gas, price) + c.AddAmount(remainder) + */ } func (c *StateObject) AddAmount(amount *big.Int) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1256d019c..a080c5602 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -116,7 +116,7 @@ func (self *StateTransition) TransitionState() (err error) { defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("%v", r) + err = fmt.Errorf("state transition err %v", r) } }() @@ -126,41 +126,51 @@ func (self *StateTransition) TransitionState() (err error) { receiver *StateObject ) + // Make sure this transaction's nonce is correct if sender.Nonce != tx.Nonce { return NonceError(tx.Nonce, sender.Nonce) } + // Increment the nonce for the next transaction sender.Nonce += 1 + // Pre-pay gas / Buy gas of the coinbase account if err = self.BuyGas(); err != nil { return err } + // Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve) receiver = self.Receiver() + // Transaction gas if err = self.UseGas(GasTx); err != nil { return err } + // Pay data gas dataPrice := big.NewInt(int64(len(tx.Data))) dataPrice.Mul(dataPrice, GasData) if err = self.UseGas(dataPrice); err != nil { return err } - if receiver == nil { // Contract + // If the receiver is nil it's a contract (\0*32). + if receiver == nil { + // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) if receiver == nil { return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) } } + // Transfer value from sender to receiver if err = self.transferValue(sender, receiver); err != nil { return err } + // Process the init code and create 'valid' contract if tx.CreatesContract() { - fmt.Println(Disassemble(receiver.Init())) + //fmt.Println(Disassemble(receiver.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. @@ -173,6 +183,10 @@ func (self *StateTransition) TransitionState() (err error) { receiver.script = code } + // Return remaining gas + remaining := new(big.Int).Mul(self.gas, tx.GasPrice) + sender.AddAmount(remaining) + self.state.UpdateStateObject(sender) self.state.UpdateStateObject(receiver) @@ -184,12 +198,14 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.tx.Value, sender.Amount) } - // Subtract the amount from the senders account - sender.SubAmount(self.tx.Value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.tx.Value) + if self.tx.Value.Cmp(ethutil.Big0) > 0 { + // Subtract the amount from the senders account + sender.SubAmount(self.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.tx.Value) - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + } return nil } diff --git a/ethchain/vm.go b/ethchain/vm.go index e17264697..f0059f6ac 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -114,14 +114,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } gas := new(big.Int) - setStepGasUsage := func(amount *big.Int) { + addStepGasUsage := func(amount *big.Int) { gas.Add(gas, amount) } + addStepGasUsage(GasStep) + var newMemSize uint64 = 0 switch op { + case STOP: + case SUICIDE: case SLOAD: - setStepGasUsage(GasSLoad) + gas.Set(GasSLoad) case SSTORE: var mult *big.Int y, x := stack.Peekn() @@ -133,12 +137,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { mult = ethutil.Big1 } - setStepGasUsage(new(big.Int).Mul(mult, GasSStore)) + gas = new(big.Int).Mul(mult, GasSStore) case BALANCE: - setStepGasUsage(GasBalance) + gas.Set(GasBalance) case MSTORE: require(2) newMemSize = stack.Peek().Uint64() + 32 + case MLOAD: + case MSTORE8: require(2) newMemSize = stack.Peek().Uint64() + 1 @@ -149,7 +155,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SHA3: require(2) - setStepGasUsage(GasSha) + gas.Set(GasSha) newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() case CALLDATACOPY: @@ -162,7 +168,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() case CALL: require(7) - setStepGasUsage(GasCall) + gas.Set(GasCall) + addStepGasUsage(stack.data[stack.Len()-1]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -170,17 +177,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro newMemSize = uint64(math.Max(float64(x), float64(y))) case CREATE: require(3) - setStepGasUsage(GasCreate) + gas.Set(GasCreate) newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() - default: - setStepGasUsage(GasStep) } newMemSize = (newMemSize + 31) / 32 * 32 if newMemSize > uint64(mem.Len()) { m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 - setStepGasUsage(big.NewInt(int64(m))) + addStepGasUsage(big.NewInt(int64(m))) } if !closure.UseGas(gas) { @@ -355,7 +360,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) case CALLER: - stack.Push(ethutil.BigD(closure.Callee().Address())) + stack.Push(ethutil.BigD(closure.caller.Address())) case CALLVALUE: stack.Push(vm.vars.Value) case CALLDATALOAD: @@ -492,7 +497,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro snapshot := vm.state.Snapshot() // Generate a new address - addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N()) + addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) // Create a new contract contract := NewContract(addr, value, []byte("")) // Set the init script @@ -503,7 +508,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro //closure.UseGas(gas) // Create the closure - c := NewClosure(closure.callee, + c := NewClosure(closure.caller, closure.Object(), contract.initScript, vm.state, -- cgit v1.2.3 From 63883bf27d8b87f601e1603e9024a279b91bffb7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 14 Jun 2014 11:46:09 +0200 Subject: Moving closer to interop --- ethchain/asm.go | 2 +- ethchain/block_chain.go | 2 ++ ethchain/state_transition.go | 16 ++++++++++------ ethchain/types.go | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 277326ff9..c267f9b55 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -28,7 +28,7 @@ func Disassemble(script []byte) (asm []string) { if len(data) == 0 { data = []byte{0} } - asm = append(asm, fmt.Sprintf("0x%x", data)) + asm = append(asm, fmt.Sprintf("%#x", data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 8cede2403..19b5248d7 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -55,6 +55,8 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { nil, "") + block.MinGasPrice = big.NewInt(10000000000000) + if bc.CurrentBlock != nil { var mul *big.Int if block.Time < lastBlockTime+42 { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index a080c5602..5ded0cddd 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -131,14 +131,21 @@ func (self *StateTransition) TransitionState() (err error) { return NonceError(tx.Nonce, sender.Nonce) } - // Increment the nonce for the next transaction - sender.Nonce += 1 - // Pre-pay gas / Buy gas of the coinbase account if err = self.BuyGas(); err != nil { return err } + // XXX Transactions after this point are considered valid. + + defer func() { + self.state.UpdateStateObject(sender) + self.state.UpdateStateObject(receiver) + }() + + // Increment the nonce for the next transaction + sender.Nonce += 1 + // Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve) receiver = self.Receiver() @@ -187,9 +194,6 @@ func (self *StateTransition) TransitionState() (err error) { remaining := new(big.Int).Mul(self.gas, tx.GasPrice) sender.AddAmount(remaining) - self.state.UpdateStateObject(sender) - self.state.UpdateStateObject(receiver) - return nil } diff --git a/ethchain/types.go b/ethchain/types.go index ee70a8d28..d89fad147 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -226,7 +226,7 @@ var opCodeToString = map[OpCode]string{ func (o OpCode) String() string { str := opCodeToString[o] if len(str) == 0 { - return fmt.Sprintf("Missing opcode 0x%x", int(o)) + return fmt.Sprintf("Missing opcode %#x", int(o)) } return str -- cgit v1.2.3 From 5871dbaf5a832a4fd34bdb22cf479d6b0b4da9fb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Jun 2014 00:10:42 +0200 Subject: Set contract addr for new transactions --- ethchain/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 7aaab2fd1..3d52e4f73 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -25,7 +25,7 @@ type Transaction struct { } func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} + return &Transaction{Recipient: ContractAddr, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { -- cgit v1.2.3 From d80f999a215b74e23d21f3548486f996c3eb028d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Jun 2014 00:11:06 +0200 Subject: Run contracts --- ethchain/state_transition.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5ded0cddd..2e2a51f72 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -188,6 +188,13 @@ func (self *StateTransition) TransitionState() (err error) { } receiver.script = code + } else { + if len(receiver.Script()) > 0 { + _, err := self.Eval(receiver.Script(), receiver) + if err != nil { + return fmt.Errorf("Error during code execution %v", err) + } + } } // Return remaining gas -- cgit v1.2.3 From 8198fd7913ea4066afb5c0cf5e57fa5ec4888fac Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 00:51:04 +0200 Subject: Cache whole objects instead of states only --- ethchain/state.go | 98 +++++++++++++++++++++++++++++++++++++++++++++++- ethchain/state_object.go | 21 +++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 5af748e00..f413fb8ed 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -16,14 +16,17 @@ type State struct { // Nested states states map[string]*State + stateObjects map[string]*StateObject + manifest *Manifest } // Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie, states: make(map[string]*State), manifest: NewManifest()} + return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } +/* // Resets the trie and all siblings func (s *State) Reset() { s.trie.Undo() @@ -43,6 +46,35 @@ func (s *State) Sync() { s.trie.Sync() } +*/ + +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + stateObject.state.Reset() + } +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + stateObject.state.Sync() + } + + s.trie.Sync() +} // Purges the current trie. func (s *State) Purge() int { @@ -54,6 +86,7 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { it.Each(cb) } +/* func (s *State) GetStateObject(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { @@ -78,7 +111,6 @@ func (s *State) UpdateStateObject(object *StateObject) { if object.state != nil && s.states[string(addr)] == nil { s.states[string(addr)] = object.state - //fmt.Printf("update cached #%d %x addr: %x\n", object.state.trie.Cache().Len(), object.state.Root(), addr[0:4]) } ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) @@ -96,13 +128,66 @@ func (s *State) GetAccount(addr []byte) (account *StateObject) { account = NewStateObjectFromBytes(addr, []byte(data)) } + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + account.state = cachedStateObject + } + return } +*/ + +func (self *State) UpdateStateObject(stateObject *StateObject) { + addr := stateObject.Address() + + if self.stateObjects[string(addr)] == nil { + self.stateObjects[string(addr)] = stateObject + } + + ethutil.Config.Db.Put(ethutil.Sha3Bin(stateObject.Script()), stateObject.Script()) + + self.trie.Update(string(addr), string(stateObject.RlpEncode())) + + self.manifest.AddObjectChange(stateObject) +} + +func (self *State) GetStateObject(addr []byte) *StateObject { + stateObject := self.stateObjects[string(addr)] + if stateObject != nil { + return stateObject + } + + data := self.trie.Get(string(addr)) + if len(data) == 0 { + return nil + } + + stateObject = NewStateObjectFromBytes(addr, []byte(data)) + self.stateObjects[string(addr)] = stateObject + + return stateObject +} + +func (self *State) GetOrNewStateObject(addr []byte) *StateObject { + stateObject := self.GetStateObject(addr) + if stateObject == nil { + stateObject = NewStateObject(addr) + self.stateObjects[string(addr)] = stateObject + } + + return stateObject +} + +func (self *State) GetAccount(addr []byte) *StateObject { + return self.GetOrNewStateObject(addr) +} func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } +/* func (s *State) Copy() *State { state := NewState(s.trie.Copy()) for k, subState := range s.states { @@ -111,6 +196,15 @@ func (s *State) Copy() *State { return state } +*/ +func (self *State) Copy() *State { + state := NewState(self.trie.Copy()) + for k, stateObject := range self.stateObjects { + state.stateObjects[k] = stateObject.Copy() + } + + return state +} func (s *State) Snapshot() *State { return s.Copy() diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 12ebf8e9b..3775d436c 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -38,6 +38,10 @@ func MakeContract(tx *Transaction, state *State) *StateObject { return nil } +func NewStateObject(addr []byte) *StateObject { + return &StateObject{address: addr, Amount: new(big.Int)} +} + func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { contract := &StateObject{address: address, Amount: Amount, Nonce: 0} contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) @@ -146,6 +150,23 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { return nil } +func (self *StateObject) Copy() *StateObject { + stCopy := &StateObject{} + stCopy.address = make([]byte, len(self.address)) + copy(stCopy.address, self.address) + stCopy.Amount = new(big.Int).Set(self.Amount) + stCopy.ScriptHash = make([]byte, len(self.ScriptHash)) + copy(stCopy.ScriptHash, self.ScriptHash) + stCopy.Nonce = self.Nonce + stCopy.state = self.state.Copy() + stCopy.script = make([]byte, len(self.script)) + copy(stCopy.script, self.script) + stCopy.initScript = make([]byte, len(self.initScript)) + copy(stCopy.initScript, self.initScript) + + return stCopy +} + // Returns the address of the contract/account func (c *StateObject) Address() []byte { return c.address -- cgit v1.2.3 From 02d8ad030fd1293a03cf905d50533678aaea40fd Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 10:35:35 +0200 Subject: Keeping old code for reference --- ethchain/state.go | 177 +++++++++++++++++++++++++++--------------------------- 1 file changed, 89 insertions(+), 88 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index f413fb8ed..9a9d0a278 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -26,28 +26,6 @@ func NewState(trie *ethutil.Trie) *State { return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } -/* -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, state := range s.states { - state.Reset() - } -} - -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, state := range s.states { - state.Sync() - } - - s.trie.Sync() -} -*/ - // Resets the trie and all siblings func (s *State) Reset() { s.trie.Undo() @@ -86,58 +64,6 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { it.Each(cb) } -/* -func (s *State) GetStateObject(addr []byte) *StateObject { - data := s.trie.Get(string(addr)) - if data == "" { - return nil - } - - stateObject := NewStateObjectFromBytes(addr, []byte(data)) - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) - stateObject.state = cachedStateObject - } - - return stateObject -} - -// Updates any given state object -func (s *State) UpdateStateObject(object *StateObject) { - addr := object.Address() - - if object.state != nil && s.states[string(addr)] == nil { - s.states[string(addr)] = object.state - } - - ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) - - s.trie.Update(string(addr), string(object.RlpEncode())) - - s.manifest.AddObjectChange(object) -} - -func (s *State) GetAccount(addr []byte) (account *StateObject) { - data := s.trie.Get(string(addr)) - if data == "" { - account = NewAccount(addr, big.NewInt(0)) - } else { - account = NewStateObjectFromBytes(addr, []byte(data)) - } - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - account.state = cachedStateObject - } - - return -} -*/ - func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() @@ -187,23 +113,17 @@ func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } -/* -func (s *State) Copy() *State { - state := NewState(s.trie.Copy()) - for k, subState := range s.states { - state.states[k] = subState.Copy() - } - - return state -} -*/ func (self *State) Copy() *State { - state := NewState(self.trie.Copy()) - for k, stateObject := range self.stateObjects { - state.stateObjects[k] = stateObject.Copy() + if self.trie != nil { + state := NewState(self.trie.Copy()) + for k, stateObject := range self.stateObjects { + state.stateObjects[k] = stateObject.Copy() + } + + return state } - return state + return nil } func (s *State) Snapshot() *State { @@ -259,3 +179,84 @@ func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage } + +/* + +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, state := range s.states { + state.Reset() + } +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, state := range s.states { + state.Sync() + } + + s.trie.Sync() +} +func (s *State) GetStateObject(addr []byte) *StateObject { + data := s.trie.Get(string(addr)) + if data == "" { + return nil + } + + stateObject := NewStateObjectFromBytes(addr, []byte(data)) + + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) + stateObject.state = cachedStateObject + } + + return stateObject +} + +// Updates any given state object +func (s *State) UpdateStateObject(object *StateObject) { + addr := object.Address() + + if object.state != nil && s.states[string(addr)] == nil { + s.states[string(addr)] = object.state + } + + ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) + + s.trie.Update(string(addr), string(object.RlpEncode())) + + s.manifest.AddObjectChange(object) +} + +func (s *State) GetAccount(addr []byte) (account *StateObject) { + data := s.trie.Get(string(addr)) + if data == "" { + account = NewAccount(addr, big.NewInt(0)) + } else { + account = NewStateObjectFromBytes(addr, []byte(data)) + } + + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + account.state = cachedStateObject + } + + return +} + +func (s *State) Copy() *State { + state := NewState(s.trie.Copy()) + for k, subState := range s.states { + state.states[k] = subState.Copy() + } + + return state +} +*/ -- cgit v1.2.3 From 1d76e433f7866763674e4ef06a4a4d9463276490 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 10:40:21 +0200 Subject: Removed some comments --- ethchain/state_transition.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 2e2a51f72..94546e556 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -102,7 +102,7 @@ func (self *StateTransition) BuyGas() error { if err != nil { return err } - self.state.UpdateStateObject(coinbase) + //self.state.UpdateStateObject(coinbase) self.AddGas(self.tx.Gas) sender.SubAmount(self.tx.GasValue()) @@ -177,7 +177,6 @@ func (self *StateTransition) TransitionState() (err error) { // Process the init code and create 'valid' contract if tx.CreatesContract() { - //fmt.Println(Disassemble(receiver.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. -- cgit v1.2.3 From 15d1f753f7ac2f72ce0637135a17d86b29f15515 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:13:06 +0200 Subject: Removed old fees --- ethchain/fees.go | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'ethchain') diff --git a/ethchain/fees.go b/ethchain/fees.go index c0a5d2d88..743be86a2 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -4,30 +4,6 @@ import ( "math/big" ) -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(5) -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 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) -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) -} -- cgit v1.2.3 From 7b55bcf4840fc11315ffd055ce7d419ac9baf168 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:13:19 +0200 Subject: Removed old fees --- ethchain/transaction_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 6538b0029..24836222a 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -179,7 +179,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) - totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + totAmount := new(big.Int).Set(tx.Value) // 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 { -- cgit v1.2.3 From 9f62d441a7c785b88f89d52643a9deaa822af15e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:14:01 +0200 Subject: Moved gas limit err check to buy gas --- ethchain/state_manager.go | 8 +++--- ethchain/state_object.go | 21 ++++++++++++--- ethchain/state_transition.go | 4 +-- ethchain/vm.go | 63 ++++++++++++++++++++++---------------------- 4 files changed, 56 insertions(+), 40 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c68d5e001..4b1b872cc 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -97,7 +97,7 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { +func (self *StateManager) ProcessTransactions(coinbase *StateObject, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { var ( receipts Receipts handled, unhandled Transactions @@ -177,9 +177,12 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } fmt.Println(block.Receipts()) + coinbase := state.GetOrNewStateObject(block.Coinbase) + coinbase.gasPool = block.CalcGasLimit(parent) + // Process the transactions on to current block //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) - sm.ProcessTransactions(block.Coinbase, state, block, parent, block.Transactions()) + sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -194,7 +197,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea return err } - //if !sm.compState.Cmp(state) { if !block.State().Cmp(state) { return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 3775d436c..03f4c9219 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -17,6 +17,11 @@ type StateObject struct { state *State script []byte initScript []byte + + // Total gas pool is the total amount of gas currently + // left if this object is the coinbase. Gas is directly + // purchased of the coinbase. + gasPool *big.Int } // Converts an transaction in to a state object @@ -139,14 +144,22 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { return nil } +func (self *StateObject) SetGasPool(gasLimit *big.Int) { + self.gasPool = new(big.Int).Set(gasLimit) + + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x fuel (+ %v)", self.Address(), self.gasPool) +} + func (self *StateObject) BuyGas(gas, price *big.Int) error { + if self.gasPool.Cmp(gas) < 0 { + return GasLimitError(self.gasPool, gas) + } + rGas := new(big.Int).Set(gas) rGas.Mul(rGas, price) self.AddAmount(rGas) - // TODO Do sub from TotalGasPool - // and check if enough left return nil } @@ -158,7 +171,9 @@ func (self *StateObject) Copy() *StateObject { stCopy.ScriptHash = make([]byte, len(self.ScriptHash)) copy(stCopy.ScriptHash, self.ScriptHash) stCopy.Nonce = self.Nonce - stCopy.state = self.state.Copy() + if self.state != nil { + stCopy.state = self.state.Copy() + } stCopy.script = make([]byte, len(self.script)) copy(stCopy.script, self.script) stCopy.initScript = make([]byte, len(self.initScript)) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 94546e556..76936aa7c 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -32,8 +32,8 @@ type StateTransition struct { cb, rec, sen *StateObject } -func NewStateTransition(coinbase []byte, tx *Transaction, state *State, block *Block) *StateTransition { - return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase.Address(), tx, new(big.Int), state, block, coinbase, nil, nil} } func (self *StateTransition) Coinbase() *StateObject { diff --git a/ethchain/vm.go b/ethchain/vm.go index f0059f6ac..2ba0e2ef3 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -169,7 +169,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: require(7) gas.Set(GasCall) - addStepGasUsage(stack.data[stack.Len()-1]) + addStepGasUsage(stack.data[stack.Len()-2]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -529,6 +529,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.state.UpdateStateObject(contract) } case CALL: + // TODO RE-WRITE require(7) // Closure addr addr := stack.Pop() @@ -538,46 +539,44 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro inSize, inOffset := stack.Popn() // Pop return size and offset retSize, retOffset := stack.Popn() - // Make sure there's enough gas - if closure.Gas.Cmp(gas) < 0 { - stack.Push(ethutil.BigFalse) - - break - } // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) snapshot := vm.state.Snapshot() - // Fetch the contract which will serve as the closure body - contract := vm.state.GetStateObject(addr.Bytes()) - - if contract != nil { - // Prepay for the gas - //closure.UseGas(gas) + closure.object.Nonce += 1 + if closure.object.Amount.Cmp(value) < 0 { + ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) - // Add the value to the state object - contract.AddAmount(value) - - // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, _, err := closure.Call(vm, args, hook) - if err != nil { - stack.Push(ethutil.BigFalse) - // Reset the changes applied this object - vm.state.Revert(snapshot) + stack.Push(ethutil.BigFalse) + } else { + // Fetch the contract which will serve as the closure body + contract := vm.state.GetStateObject(addr.Bytes()) + + if contract != nil { + // Add the value to the state object + contract.AddAmount(value) + + // Create a new callable closure + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) + // Executer the closure and get the return value (if any) + ret, _, err := closure.Call(vm, args, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + // Reset the changes applied this object + vm.state.Revert(snapshot) + } else { + stack.Push(ethutil.BigTrue) + + vm.state.UpdateStateObject(contract) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } } else { - stack.Push(ethutil.BigTrue) - - vm.state.UpdateStateObject(contract) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) + ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) + stack.Push(ethutil.BigFalse) } - } else { - ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) - stack.Push(ethutil.BigFalse) } case RETURN: require(2) -- cgit v1.2.3 From 48bca30e61f869a00111abe5d818ac7379854616 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:51:16 +0200 Subject: Fixed minor issue with the gas pool --- ethchain/state_manager.go | 2 +- ethchain/state_object.go | 4 ++-- ethchain/state_transition.go | 14 ++++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4b1b872cc..36bb14846 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -178,7 +178,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea fmt.Println(block.Receipts()) coinbase := state.GetOrNewStateObject(block.Coinbase) - coinbase.gasPool = block.CalcGasLimit(parent) + coinbase.SetGasPool(block.CalcGasLimit(parent)) // Process the transactions on to current block //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 03f4c9219..337c5a394 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -120,13 +120,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - ethutil.Config.Log.Debugf("%x: #%d %v (+ %v)", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - ethutil.Config.Log.Debugf("%x: #%d %v (- %v)", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 76936aa7c..5beef61b4 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -113,12 +113,14 @@ func (self *StateTransition) BuyGas() error { func (self *StateTransition) TransitionState() (err error) { //snapshot := st.state.Snapshot() - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("state transition err %v", r) - } - }() + /* + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("state transition err %v", r) + } + }() + */ var ( tx = self.tx -- cgit v1.2.3 From 8b15732c1e8a1a666ae7469bc43d989918ce754a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 12:04:56 +0200 Subject: Check for nil receiver --- ethchain/state_transition.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5beef61b4..c88f4727f 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -141,8 +141,13 @@ func (self *StateTransition) TransitionState() (err error) { // XXX Transactions after this point are considered valid. defer func() { - self.state.UpdateStateObject(sender) - self.state.UpdateStateObject(receiver) + if sender != nil { + self.state.UpdateStateObject(sender) + } + + if receiver != nil { + self.state.UpdateStateObject(receiver) + } }() // Increment the nonce for the next transaction -- cgit v1.2.3 From 0d7763283952a57e5421565cdda19ecabe3222f7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 12:25:18 +0200 Subject: Refund gas --- ethchain/state_object.go | 9 +++++++++ ethchain/state_transition.go | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 337c5a394..2c9dfb713 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -163,6 +163,15 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { return nil } +func (self *StateObject) RefundGas(gas, price *big.Int) { + self.gasPool.Add(self.gasPool, gas) + + rGas := new(big.Int).Set(gas) + rGas.Mul(rGas, price) + + self.Amount.Sub(self.Amount, rGas) +} + func (self *StateObject) Copy() *StateObject { stCopy := &StateObject{} stCopy.address = make([]byte, len(self.address)) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index c88f4727f..25efd64cc 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -110,6 +110,15 @@ func (self *StateTransition) BuyGas() error { return nil } +func (self *StateTransition) RefundGas() { + coinbase, sender := self.Coinbase(), self.Sender() + coinbase.RefundGas(self.gas, self.tx.GasPrice) + + // Return remaining gas + remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice) + sender.AddAmount(remaining) +} + func (self *StateTransition) TransitionState() (err error) { //snapshot := st.state.Snapshot() @@ -141,6 +150,8 @@ func (self *StateTransition) TransitionState() (err error) { // XXX Transactions after this point are considered valid. defer func() { + self.RefundGas() + if sender != nil { self.state.UpdateStateObject(sender) } @@ -148,6 +159,8 @@ func (self *StateTransition) TransitionState() (err error) { if receiver != nil { self.state.UpdateStateObject(receiver) } + + self.state.UpdateStateObject(self.Coinbase()) }() // Increment the nonce for the next transaction @@ -203,10 +216,6 @@ func (self *StateTransition) TransitionState() (err error) { } } - // Return remaining gas - remaining := new(big.Int).Mul(self.gas, tx.GasPrice) - sender.AddAmount(remaining) - return nil } -- cgit v1.2.3 From 887debb0559b283962530bb42998a67dd1b69347 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 18:20:38 +0200 Subject: comment --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 2c9dfb713..1445bcd82 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -147,7 +147,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x fuel (+ %v)", self.Address(), self.gasPool) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: fuel (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { -- cgit v1.2.3 From 53e30f750dd0c91279bfebe01bb12fd170cb74ff Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 11:06:06 +0200 Subject: Removal of manual updating of state objects * You'll only ever need to update the state by calling Update. Update will take care of the updating of it's child state objects. --- ethchain/state.go | 27 +++++++++++++++++++++++++-- ethchain/state_manager.go | 4 +++- ethchain/state_object.go | 26 +++++++++++++++----------- ethchain/state_transition.go | 26 +++++++++++++------------- ethchain/vm.go | 19 +++++++------------ 5 files changed, 63 insertions(+), 39 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 9a9d0a278..f5a3d3071 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -38,12 +38,16 @@ func (s *State) Reset() { stateObject.state.Reset() } + + s.Empty() } // Syncs the trie and all siblings func (s *State) Sync() { // Sync all nested states for _, stateObject := range s.stateObjects { + s.UpdateStateObject(stateObject) + if stateObject.state == nil { continue } @@ -52,6 +56,18 @@ func (s *State) Sync() { } s.trie.Sync() + + s.Empty() +} + +func (self *State) Empty() { + self.stateObjects = make(map[string]*StateObject) +} + +func (self *State) Update() { + for _, stateObject := range self.stateObjects { + self.UpdateStateObject(stateObject) + } } // Purges the current trie. @@ -68,6 +84,7 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() if self.stateObjects[string(addr)] == nil { + panic("?") self.stateObjects[string(addr)] = stateObject } @@ -98,13 +115,19 @@ func (self *State) GetStateObject(addr []byte) *StateObject { func (self *State) GetOrNewStateObject(addr []byte) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil { - stateObject = NewStateObject(addr) - self.stateObjects[string(addr)] = stateObject + stateObject = self.NewStateObject(addr) } return stateObject } +func (self *State) NewStateObject(addr []byte) *StateObject { + stateObject := NewStateObject(addr) + self.stateObjects[string(addr)] = stateObject + + return stateObject +} + func (self *State) GetAccount(addr []byte) *StateObject { return self.GetOrNewStateObject(addr) } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 36bb14846..a0051181f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -181,7 +181,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea coinbase.SetGasPool(block.CalcGasLimit(parent)) // Process the transactions on to current block - //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) // Block validation @@ -197,6 +196,9 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea return err } + // Update the state with pending changes + state.Update() + if !block.State().Cmp(state) { return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 1445bcd82..5fc738fee 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -4,8 +4,15 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" + "strings" ) +type Code []byte + +func (self Code) String() string { + return strings.Join(Disassemble(self), " ") +} + type StateObject struct { // Address of the object address []byte @@ -15,8 +22,8 @@ type StateObject struct { Nonce uint64 // Contract related attributes state *State - script []byte - initScript []byte + script Code + initScript Code // Total gas pool is the total amount of gas currently // left if this object is the coinbase. Gas is directly @@ -30,12 +37,9 @@ func MakeContract(tx *Transaction, state *State) *StateObject { if tx.IsContract() { addr := tx.CreationAddress() - value := tx.Value - contract := NewContract(addr, value, ZeroHash256) - + contract := state.NewStateObject(addr) contract.initScript = tx.Data - - state.UpdateStateObject(contract) + contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, "")) return contract } @@ -120,13 +124,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -197,12 +201,12 @@ func (c *StateObject) Address() []byte { } // Returns the main script body -func (c *StateObject) Script() []byte { +func (c *StateObject) Script() Code { return c.script } // Returns the initialization script -func (c *StateObject) Init() []byte { +func (c *StateObject) Init() Code { return c.initScript } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 25efd64cc..23175b0f3 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -67,13 +67,8 @@ func (self *StateTransition) Receiver() *StateObject { func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject { contract := MakeContract(tx, state) - if contract != nil { - state.states[string(tx.CreationAddress())] = contract.state - return contract - } - - return nil + return contract } func (self *StateTransition) UseGas(amount *big.Int) error { @@ -137,6 +132,8 @@ func (self *StateTransition) TransitionState() (err error) { receiver *StateObject ) + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", tx.Hash()) + // Make sure this transaction's nonce is correct if sender.Nonce != tx.Nonce { return NonceError(tx.Nonce, sender.Nonce) @@ -152,15 +149,17 @@ func (self *StateTransition) TransitionState() (err error) { defer func() { self.RefundGas() - if sender != nil { - self.state.UpdateStateObject(sender) - } + /* + if sender != nil { + self.state.UpdateStateObject(sender) + } - if receiver != nil { - self.state.UpdateStateObject(receiver) - } + if receiver != nil { + self.state.UpdateStateObject(receiver) + } - self.state.UpdateStateObject(self.Coinbase()) + self.state.UpdateStateObject(self.Coinbase()) + */ }() // Increment the nonce for the next transaction @@ -209,6 +208,7 @@ func (self *StateTransition) TransitionState() (err error) { receiver.script = code } else { if len(receiver.Script()) > 0 { + fmt.Println(receiver.Script()) _, err := self.Eval(receiver.Script(), receiver) if err != nil { return fmt.Errorf("Error during code execution %v", err) diff --git a/ethchain/vm.go b/ethchain/vm.go index 2ba0e2ef3..77a08faa6 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -95,9 +95,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro step := 0 prevStep := 0 - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("# op\n") - } + ethutil.Config.Log.Debugf("# op\n") for { prevStep = step @@ -109,9 +107,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } + + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -525,8 +522,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.state.Revert(snapshot) } else { stack.Push(ethutil.BigD(addr)) - - vm.state.UpdateStateObject(contract) } case CALL: // TODO RE-WRITE @@ -569,8 +564,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigTrue) - vm.state.UpdateStateObject(contract) - mem.Set(retOffset.Int64(), retSize.Int64(), ret) } } else { @@ -589,9 +582,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - vm.state.UpdateStateObject(receiver) - closure.object.state.Purge() + trie := closure.object.state.trie + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + trie.Delete(key) + }) fallthrough case STOP: // Stop the closure -- cgit v1.2.3 From 3621988e15c025d2bd7b80e4691a6b236574f0a1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 11:07:37 +0200 Subject: Removed deprecated states --- ethchain/deprecated.go | 236 ------------------------------------------------- ethchain/state.go | 6 +- 2 files changed, 2 insertions(+), 240 deletions(-) delete mode 100644 ethchain/deprecated.go (limited to 'ethchain') diff --git a/ethchain/deprecated.go b/ethchain/deprecated.go deleted file mode 100644 index 0985fa25d..000000000 --- a/ethchain/deprecated.go +++ /dev/null @@ -1,236 +0,0 @@ -package ethchain - -import ( - "bytes" - "fmt" - "github.com/ethereum/eth-go/ethutil" - "math/big" -) - -func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { - contract := MakeContract(tx, state) - if contract != nil { - state.states[string(tx.CreationAddress())] = contract.state - - return contract - } - - return nil -} - -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { - account := state.GetAccount(tx.Sender()) - - err = account.ConvertGas(tx.Gas, tx.GasPrice) - if err != nil { - ethutil.Config.Log.Debugln(err) - return - } - - closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) - vm := NewVm(state, sm, RuntimeVars{ - Origin: account.Address(), - BlockNumber: block.BlockInfo().Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: tx.Value, - //Price: tx.GasPrice, - }) - ret, gas, err = closure.Call(vm, tx.Data, nil) - - // Update the account (refunds) - state.UpdateStateObject(account) - state.UpdateStateObject(object) - - return -} - -func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { - fmt.Printf("state root before update %x\n", state.Root()) - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("%v", r) - } - }() - - gas = new(big.Int) - addGas := func(g *big.Int) { gas.Add(gas, g) } - addGas(GasTx) - - // Get the sender - sender := state.GetAccount(tx.Sender()) - - if sender.Nonce != tx.Nonce { - err = NonceError(tx.Nonce, sender.Nonce) - return - } - - sender.Nonce += 1 - defer func() { - //state.UpdateStateObject(sender) - // Notify all subscribers - self.Ethereum.Reactor().Post("newTx:post", tx) - }() - - txTotalBytes := big.NewInt(int64(len(tx.Data))) - //fmt.Println("txTotalBytes", txTotalBytes) - //txTotalBytes.Div(txTotalBytes, ethutil.Big32) - addGas(new(big.Int).Mul(txTotalBytes, GasData)) - - rGas := new(big.Int).Set(gas) - rGas.Mul(gas, tx.GasPrice) - - // 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, rGas) - if sender.Amount.Cmp(totAmount) < 0 { - state.UpdateStateObject(sender) - err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) - return - } - - coinbase.BuyGas(gas, tx.GasPrice) - state.UpdateStateObject(coinbase) - fmt.Printf("1. root %x\n", state.Root()) - - // Get the receiver - receiver := state.GetAccount(tx.Recipient) - - // Send Tx to self - if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - // Subtract the fee - sender.SubAmount(rGas) - } else { - // Subtract the amount from the senders account - sender.SubAmount(totAmount) - state.UpdateStateObject(sender) - fmt.Printf("3. root %x\n", state.Root()) - - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(tx.Value) - state.UpdateStateObject(receiver) - fmt.Printf("2. root %x\n", state.Root()) - } - - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) - - return -} - -func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { - /* - Applies transactions to the given state and creates new - state objects where needed. - - If said objects needs to be created - run the initialization script provided by the transaction and - assume there's a return value. The return value will be set to - the script section of the state object. - */ - var ( - addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } - gas = new(big.Int) - script []byte - ) - totalGasUsed = big.NewInt(0) - snapshot := state.Snapshot() - - ca := state.GetAccount(coinbase) - // Apply the transaction to the current state - gas, err = sm.ProcessTransaction(tx, ca, state, false) - addTotalGas(gas) - fmt.Println("gas used by tx", gas) - - if tx.CreatesContract() { - if err == nil { - // Create a new state object and the transaction - // as it's data provider. - contract := sm.MakeStateObject(state, tx) - if contract != nil { - fmt.Println(Disassemble(contract.Init())) - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) - fmt.Println("gas used by eval", gas) - addTotalGas(gas) - fmt.Println("total =", totalGasUsed) - - fmt.Println("script len =", len(script)) - - if err != nil { - err = fmt.Errorf("[STATE] Error during init script run %v", err) - return - } - contract.script = script - state.UpdateStateObject(contract) - } else { - err = fmt.Errorf("[STATE] Unable to create contract") - } - } else { - err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) - } - } else { - // Find the state object at the "recipient" address. If - // there's an object attempt to run the script. - stateObject := state.GetStateObject(tx.Recipient) - if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { - _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) - addTotalGas(gas) - } - } - - parent := sm.bc.GetBlock(block.PrevHash) - total := new(big.Int).Add(block.GasUsed, totalGasUsed) - limit := block.CalcGasLimit(parent) - if total.Cmp(limit) > 0 { - state.Revert(snapshot) - err = GasLimitError(total, limit) - } - - return -} - -// Apply transactions uses the transaction passed to it and applies them onto -// the current processing state. -func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { - // Process each transaction/contract - var receipts []*Receipt - var validTxs []*Transaction - var ignoredTxs []*Transaction // Transactions which go over the gasLimit - - totalUsedGas := big.NewInt(0) - - for _, tx := range txs { - usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) - if err != nil { - if IsNonceErr(err) { - continue - } - if IsGasLimitErr(err) { - ignoredTxs = append(ignoredTxs, tx) - // We need to figure out if we want to do something with thse txes - ethutil.Config.Log.Debugln("Gastlimit:", err) - continue - } - - ethutil.Config.Log.Infoln(err) - } - - accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) - receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} - - receipts = append(receipts, receipt) - validTxs = append(validTxs, tx) - } - - fmt.Println("################# MADE\n", receipts, "\n############################") - - // Update the total gas used for the block (to be mined) - block.GasUsed = totalUsedGas - - return receipts, validTxs -} diff --git a/ethchain/state.go b/ethchain/state.go index f5a3d3071..993f1fb08 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -13,8 +13,6 @@ import ( type State struct { // The trie for this structure trie *ethutil.Trie - // Nested states - states map[string]*State stateObjects map[string]*StateObject @@ -23,7 +21,7 @@ type State struct { // Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} + return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } // Resets the trie and all siblings @@ -155,7 +153,7 @@ func (s *State) Snapshot() *State { func (s *State) Revert(snapshot *State) { s.trie = snapshot.trie - s.states = snapshot.states + s.stateObjects = snapshot.stateObjects } func (s *State) Put(key, object []byte) { -- cgit v1.2.3 From 34c8045d5be6488e9800c24e1e696e1b912f344c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 18:05:46 +0200 Subject: Fixed issue where JUMPI would do an equally check with 1 instead of GT --- ethchain/state.go | 2 ++ ethchain/state_transition.go | 22 ++-------------------- ethchain/transaction.go | 2 +- ethchain/vm.go | 14 +++++++++----- 4 files changed, 14 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 993f1fb08..616ab77e0 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -120,6 +120,8 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(+) %x\n", addr) + stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 23175b0f3..dc465bbbd 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -97,7 +97,6 @@ func (self *StateTransition) BuyGas() error { if err != nil { return err } - //self.state.UpdateStateObject(coinbase) self.AddGas(self.tx.Gas) sender.SubAmount(self.tx.GasValue()) @@ -115,7 +114,7 @@ func (self *StateTransition) RefundGas() { } func (self *StateTransition) TransitionState() (err error) { - //snapshot := st.state.Snapshot() + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", self.tx.Hash()) /* defer func() { @@ -132,8 +131,6 @@ func (self *StateTransition) TransitionState() (err error) { receiver *StateObject ) - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", tx.Hash()) - // Make sure this transaction's nonce is correct if sender.Nonce != tx.Nonce { return NonceError(tx.Nonce, sender.Nonce) @@ -146,26 +143,11 @@ func (self *StateTransition) TransitionState() (err error) { // XXX Transactions after this point are considered valid. - defer func() { - self.RefundGas() - - /* - if sender != nil { - self.state.UpdateStateObject(sender) - } - - if receiver != nil { - self.state.UpdateStateObject(receiver) - } - - self.state.UpdateStateObject(self.Coinbase()) - */ - }() + defer self.RefundGas() // Increment the nonce for the next transaction sender.Nonce += 1 - // Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve) receiver = self.Receiver() // Transaction gas diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 3d52e4f73..9044f586e 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -65,7 +65,7 @@ func (tx *Transaction) CreatesContract() bool { return tx.contractCreation } -/* Depricated */ +/* Deprecated */ func (tx *Transaction) IsContract() bool { return tx.CreatesContract() } diff --git a/ethchain/vm.go b/ethchain/vm.go index 77a08faa6..690433180 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -120,7 +120,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro var newMemSize uint64 = 0 switch op { case STOP: + gas.Set(ethutil.Big0) case SUICIDE: + gas.Set(ethutil.Big0) case SLOAD: gas.Set(GasSLoad) case SSTORE: @@ -296,6 +298,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case EQ: require(2) x, y := stack.Popn() + fmt.Printf("%x == %x\n", x, y) // x == y if x.Cmp(y) == 0 { stack.Push(ethutil.BigTrue) @@ -365,12 +368,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro offset := stack.Pop().Int64() var data []byte - if len(closure.Args) >= int(offset+32) { - data = closure.Args[offset : offset+32] + if len(closure.Args) >= int(offset) { + l := int64(math.Min(float64(offset+32), float64(len(closure.Args)))) + data = closure.Args[offset : offset+l] } else { data = []byte{0} } + fmt.Println("CALLDATALOAD", string(data), len(data), "==", len(closure.Args)) stack.Push(ethutil.BigD(data)) case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) @@ -452,12 +457,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) - //fmt.Println("get", val.BigInt(), "@", loc) stack.Push(val.BigInt()) case SSTORE: require(2) val, loc := stack.Popn() - //fmt.Println("storing", val, "@", loc) + fmt.Println("storing", string(val.Bytes()), "@", string(loc.Bytes())) closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest @@ -471,7 +475,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case JUMPI: require(2) cond, pos := stack.Popn() - if cond.Cmp(ethutil.BigTrue) == 0 { + if cond.Cmp(ethutil.BigTrue) >= 0 { pc = pos //pc.Sub(pc, ethutil.Big1) continue -- cgit v1.2.3 From ca79360fd7621a96382c0304e74e0d1f39b739fc Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 18:49:26 +0200 Subject: Verbose logging for VM --- ethchain/state_transition.go | 1 + ethchain/vm.go | 45 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index dc465bbbd..c70dc54b4 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -236,6 +236,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by Diff: block.Difficulty, Value: tx.Value, }) + vm.Verbose = true ret, _, err = closure.Call(vm, tx.Data, nil) return diff --git a/ethchain/vm.go b/ethchain/vm.go index 690433180..7a4e30a33 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -45,6 +45,10 @@ type Vm struct { state *State stateManager *StateManager + + Verbose bool + + logStr string } type RuntimeVars struct { @@ -58,6 +62,23 @@ type RuntimeVars struct { Value *big.Int } +func (self *Vm) Printf(format string, v ...interface{}) *Vm { + if self.Verbose { + self.logStr += fmt.Sprintf(format, v...) + } + + return self +} + +func (self *Vm) Endl() *Vm { + if self.Verbose { + ethutil.Config.Log.Infoln(self.logStr) + self.logStr = "" + } + + return self +} + func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { return &Vm{vars: vars, state: state, stateManager: stateManager} } @@ -95,8 +116,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro step := 0 prevStep := 0 - ethutil.Config.Log.Debugf("# op\n") - for { prevStep = step // The base for all big integer arithmetic @@ -108,7 +127,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) + //ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -193,6 +213,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + vm.Printf(" (g) %-3v (%v)", gas, closure.Gas) + mem.Resize(newMemSize) switch op { @@ -428,6 +450,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, a.Sub(a, big.NewInt(1))) step += int(op) - int(PUSH1) + 1 + + vm.Printf(" => %#x", data.Bytes()) case POP: require(1) stack.Pop() @@ -448,11 +472,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + + vm.Printf(" => %#x", val) case MSTORE8: require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) + + vm.Printf(" => %#x", val) case SLOAD: require(1) loc := stack.Pop() @@ -466,18 +494,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) + + vm.Printf(" => %#x", val) case JUMP: require(1) pc = stack.Pop() // Reduce pc by one because of the increment that's at the end of this for loop - //pc.Sub(pc, ethutil.Big1) + vm.Printf(" ~> %v", pc).Endl() + continue case JUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) >= 0 { pc = pos - //pc.Sub(pc, ethutil.Big1) + + vm.Printf(" ~> %v", pc).Endl() + continue } case PC: @@ -603,6 +636,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, ethutil.Big1) + vm.Endl() + if hook != nil { if !hook(prevStep, op, mem, stack, closure.Object()) { return nil, nil -- cgit v1.2.3 From 8a885c2606fbf675770cf40b31f9ceb5ef8acae9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 00:25:58 +0200 Subject: Fixed GT and LT --- ethchain/asm.go | 2 +- ethchain/types.go | 2 +- ethchain/vm.go | 35 ++++++++++++++++++++++++----------- 3 files changed, 26 insertions(+), 13 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index c267f9b55..277326ff9 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -28,7 +28,7 @@ func Disassemble(script []byte) (asm []string) { if len(data) == 0 { data = []byte{0} } - asm = append(asm, fmt.Sprintf("%#x", data)) + asm = append(asm, fmt.Sprintf("0x%x", data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/types.go b/ethchain/types.go index d89fad147..ee70a8d28 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -226,7 +226,7 @@ var opCodeToString = map[OpCode]string{ func (o OpCode) String() string { str := opCodeToString[o] if len(str) == 0 { - return fmt.Sprintf("Missing opcode %#x", int(o)) + return fmt.Sprintf("Missing opcode 0x%x", int(o)) } return str diff --git a/ethchain/vm.go b/ethchain/vm.go index 7a4e30a33..9dbc13ead 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -97,7 +97,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } }() - ethutil.Config.Log.Debugf("[VM] Running closure %x\n", closure.object.Address()) + ethutil.Config.Log.Debugf("[VM] Running %x\n", closure.object.Address()) // Memory for the current closure mem := &Memory{} @@ -301,7 +301,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(base) case LT: require(2) - x, y := stack.Popn() + y, x := stack.Popn() // x < y if x.Cmp(y) < 0 { stack.Push(ethutil.BigTrue) @@ -310,7 +310,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } case GT: require(2) - x, y := stack.Popn() + y, x := stack.Popn() + vm.Printf(" %v > %v", x, y) + // x > y if x.Cmp(y) > 0 { stack.Push(ethutil.BigTrue) @@ -382,7 +384,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) case CALLER: - stack.Push(ethutil.BigD(closure.caller.Address())) + caller := closure.caller.Address() + stack.Push(ethutil.BigD(caller)) + + vm.Printf(" => %x", caller) case CALLVALUE: stack.Push(vm.vars.Value) case CALLDATALOAD: @@ -397,10 +402,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro data = []byte{0} } - fmt.Println("CALLDATALOAD", string(data), len(data), "==", len(closure.Args)) + vm.Printf(" => 0x%x", data) + stack.Push(ethutil.BigD(data)) case CALLDATASIZE: - stack.Push(big.NewInt(int64(len(closure.Args)))) + l := int64(len(closure.Args)) + stack.Push(big.NewInt(l)) + + vm.Printf(" => %d", l) case CALLDATACOPY: case CODESIZE: case CODECOPY: @@ -451,7 +460,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro step += int(op) - int(PUSH1) + 1 - vm.Printf(" => %#x", data.Bytes()) + vm.Printf(" => 0x%x", data.Bytes()) case POP: require(1) stack.Pop() @@ -473,19 +482,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) - vm.Printf(" => %#x", val) + vm.Printf(" => 0x%x", val) case MSTORE8: require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) - vm.Printf(" => %#x", val) + vm.Printf(" => 0x%x", val) case SLOAD: require(1) loc := stack.Pop() val := closure.GetMem(loc) stack.Push(val.BigInt()) + + vm.Printf(" {} 0x%x", val) case SSTORE: require(2) val, loc := stack.Popn() @@ -495,7 +506,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) - vm.Printf(" => %#x", val) + vm.Printf(" => 0x%x", val) case JUMP: require(1) pc = stack.Pop() @@ -509,9 +520,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if cond.Cmp(ethutil.BigTrue) >= 0 { pc = pos - vm.Printf(" ~> %v", pc).Endl() + vm.Printf(" (t) ~> %v", pc).Endl() continue + } else { + vm.Printf(" (f)") } case PC: stack.Push(pc) -- cgit v1.2.3 From 2565a79575c6a6b839a6585c9ad3ebbcf7db9115 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 00:32:48 +0200 Subject: Swapped vars --- ethchain/vm.go | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 9dbc13ead..f83258430 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -226,28 +226,28 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(2) x, y := stack.Popn() // (x + y) % 2 ** 256 - base.Add(x, y) + base.Add(y, x) // Pop result back on the stack stack.Push(base) case SUB: require(2) x, y := stack.Popn() // (x - y) % 2 ** 256 - base.Sub(x, y) + base.Sub(y, x) // Pop result back on the stack stack.Push(base) case MUL: require(2) x, y := stack.Popn() // (x * y) % 2 ** 256 - base.Mul(x, y) + base.Mul(y, x) // Pop result back on the stack stack.Push(base) case DIV: require(2) x, y := stack.Popn() // floor(x / y) - base.Div(x, y) + base.Div(y, x) // Pop result back on the stack stack.Push(base) case SDIV: @@ -270,7 +270,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case MOD: require(2) x, y := stack.Popn() - base.Mod(x, y) + base.Mod(y, x) stack.Push(base) case SMOD: require(2) @@ -292,7 +292,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case EXP: require(2) x, y := stack.Popn() - base.Exp(x, y, Pow256) + base.Exp(y, x, Pow256) stack.Push(base) case NEG: @@ -302,6 +302,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case LT: require(2) y, x := stack.Popn() + vm.Printf(" %v < %v", x, y) // x < y if x.Cmp(y) < 0 { stack.Push(ethutil.BigTrue) @@ -342,20 +343,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case AND: require(2) x, y := stack.Popn() - if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - + stack.Push(base.And(y, x)) case OR: require(2) x, y := stack.Popn() - if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } + stack.Push(base.Or(y, x)) case XOR: require(2) x, y := stack.Popn() -- cgit v1.2.3 From dc9c9369e0b44873dedfdf37195268f0e524872d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 00:36:23 +0200 Subject: log --- ethchain/vm.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index f83258430..b8ba72c7e 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -323,7 +323,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case EQ: require(2) x, y := stack.Popn() - fmt.Printf("%x == %x\n", x, y) + vm.Printf(" %v == %v", y, x) + // x == y if x.Cmp(y) == 0 { stack.Push(ethutil.BigTrue) @@ -343,15 +344,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case AND: require(2) x, y := stack.Popn() + vm.Printf(" %v & %v", y, x) + stack.Push(base.And(y, x)) case OR: require(2) x, y := stack.Popn() + vm.Printf(" %v | %v", y, x) + stack.Push(base.Or(y, x)) case XOR: require(2) x, y := stack.Popn() - stack.Push(base.Xor(x, y)) + vm.Printf(" %v ^ %v", y, x) + + stack.Push(base.Xor(y, x)) case BYTE: require(2) val, th := stack.Popn() -- cgit v1.2.3 From 3bc57fe5b5182cd2e0ae0c6b53b3bbb02ce34304 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 13:48:08 +0200 Subject: CALLDATALOAD return 32 byte at all times --- ethchain/vm.go | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index b8ba72c7e..5a15ba81b 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -225,29 +225,41 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case ADD: require(2) x, y := stack.Popn() - // (x + y) % 2 ** 256 + vm.Printf(" %v + %v", y, x) + base.Add(y, x) + + vm.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) case SUB: require(2) x, y := stack.Popn() - // (x - y) % 2 ** 256 + vm.Printf(" %v - %v", y, x) + base.Sub(y, x) + + vm.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) case MUL: require(2) x, y := stack.Popn() - // (x * y) % 2 ** 256 + vm.Printf(" %v * %v", y, x) + base.Mul(y, x) + + vm.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) case DIV: require(2) x, y := stack.Popn() - // floor(x / y) + vm.Printf(" %v / %v", y, x) + base.Div(y, x) + + vm.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) case SDIV: @@ -270,7 +282,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case MOD: require(2) x, y := stack.Popn() + + vm.Printf(" %v %% %v", y, x) + base.Mod(y, x) + + vm.Printf(" = %v", base) stack.Push(base) case SMOD: require(2) @@ -292,8 +309,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case EXP: require(2) x, y := stack.Popn() + + vm.Printf(" %v ** %v", y, x) + base.Exp(y, x, Pow256) + vm.Printf(" = %v", base) + stack.Push(base) case NEG: require(1) @@ -393,12 +415,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) offset := stack.Pop().Int64() - var data []byte + data := make([]byte, 32) if len(closure.Args) >= int(offset) { l := int64(math.Min(float64(offset+32), float64(len(closure.Args)))) - data = closure.Args[offset : offset+l] - } else { - data = []byte{0} + + copy(data, closure.Args[offset:l]) } vm.Printf(" => 0x%x", data) @@ -499,13 +520,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SSTORE: require(2) val, loc := stack.Popn() - fmt.Println("storing", string(val.Bytes()), "@", string(loc.Bytes())) closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) - vm.Printf(" => 0x%x", val) + vm.Printf(" {0x%x} 0x%x", loc, val) case JUMP: require(1) pc = stack.Pop() @@ -519,7 +539,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if cond.Cmp(ethutil.BigTrue) >= 0 { pc = pos - vm.Printf(" (t) ~> %v", pc).Endl() + vm.Printf(" ~> %v (t)", pc).Endl() continue } else { -- cgit v1.2.3 From f911087eab6b31fcdbc22a9a74c0be410e8f0177 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 13:48:42 +0200 Subject: Logging --- ethchain/state_transition.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index c70dc54b4..8a6565e56 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -89,7 +89,7 @@ func (self *StateTransition) BuyGas() error { sender := self.Sender() if sender.Amount.Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Amount) } coinbase := self.Coinbase() @@ -181,7 +181,8 @@ func (self *StateTransition) TransitionState() (err error) { // Evaluate the initialization script // and use the return value as the // script section for the state object. - //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) + ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Init()) + code, err := self.Eval(receiver.Init(), receiver) if err != nil { return fmt.Errorf("Error during init script run %v", err) @@ -190,7 +191,8 @@ func (self *StateTransition) TransitionState() (err error) { receiver.script = code } else { if len(receiver.Script()) > 0 { - fmt.Println(receiver.Script()) + ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Script()) + _, err := self.Eval(receiver.Script(), receiver) if err != nil { return fmt.Errorf("Error during code execution %v", err) -- cgit v1.2.3 From 731f55a05db44fcd5191bd7af6c99f4a4433e342 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:41:17 +0200 Subject: Reset state when a transition fails --- ethchain/state.go | 7 ++- ethchain/state_transition.go | 132 ++++++++++++++++++++++++++++--------------- 2 files changed, 93 insertions(+), 46 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 616ab77e0..98fcb24db 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -78,11 +78,16 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { it.Each(cb) } +func (self *State) ResetStateObject(stateObject *StateObject) { + stateObject.state.Reset() + + delete(self.stateObjects, string(stateObject.Address())) +} + func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() if self.stateObjects[string(addr)] == nil { - panic("?") self.stateObjects[string(addr)] = stateObject } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8a6565e56..8757246a0 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -23,17 +23,36 @@ import ( * 6) Derive new state root */ type StateTransition struct { - coinbase []byte - tx *Transaction - gas *big.Int - state *State - block *Block + coinbase, receiver []byte + tx *Transaction + gas, gasPrice *big.Int + value *big.Int + data []byte + state *State + block *Block cb, rec, sen *StateObject } +func Transition(coinbase, sender, receiver, data []byte, gas, gasPrice, value *big.Int, state *State, block *Block) (ret []byte, err error) { + stateTransition := &StateTransition{ + coinbase: coinbase, + receiver: receiver, + cb: state.GetOrNewStateObject(coinbase), + rec: state.GetOrNewStateObject(receiver), + sen: state.GetOrNewStateObject(sender), + gas: gas, + gasPrice: gasPrice, + value: value, + state: state, + block: block, + } + + return stateTransition.Transition() +} + func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { - return &StateTransition{coinbase.Address(), tx, new(big.Int), state, block, coinbase, nil, nil} + return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} } func (self *StateTransition) Coinbase() *StateObject { @@ -53,7 +72,7 @@ func (self *StateTransition) Sender() *StateObject { return self.sen } func (self *StateTransition) Receiver() *StateObject { - if self.tx.CreatesContract() { + if self.tx != nil && self.tx.CreatesContract() { return nil } @@ -113,6 +132,25 @@ func (self *StateTransition) RefundGas() { sender.AddAmount(remaining) } +func (self *StateTransition) preCheck() (err error) { + var ( + tx = self.tx + sender = self.Sender() + ) + + // Make sure this transaction's nonce is correct + if sender.Nonce != tx.Nonce { + return NonceError(tx.Nonce, sender.Nonce) + } + + // Pre-pay gas / Buy gas of the coinbase account + if err = self.BuyGas(); err != nil { + return err + } + + return nil +} + func (self *StateTransition) TransitionState() (err error) { ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", self.tx.Hash()) @@ -125,26 +163,25 @@ func (self *StateTransition) TransitionState() (err error) { }() */ + // XXX Transactions after this point are considered valid. + if err = self.preCheck(); err != nil { + return + } + + defer self.RefundGas() + + _, err = self.Transition() + + return +} + +func (self *StateTransition) Transition() (ret []byte, err error) { var ( tx = self.tx sender = self.Sender() receiver *StateObject ) - // Make sure this transaction's nonce is correct - if sender.Nonce != tx.Nonce { - return NonceError(tx.Nonce, sender.Nonce) - } - - // Pre-pay gas / Buy gas of the coinbase account - if err = self.BuyGas(); err != nil { - return err - } - - // XXX Transactions after this point are considered valid. - - defer self.RefundGas() - // Increment the nonce for the next transaction sender.Nonce += 1 @@ -152,14 +189,14 @@ func (self *StateTransition) TransitionState() (err error) { // Transaction gas if err = self.UseGas(GasTx); err != nil { - return err + return } // Pay data gas - dataPrice := big.NewInt(int64(len(tx.Data))) + dataPrice := big.NewInt(int64(len(self.data))) dataPrice.Mul(dataPrice, GasData) if err = self.UseGas(dataPrice); err != nil { - return err + return } // If the receiver is nil it's a contract (\0*32). @@ -167,25 +204,28 @@ func (self *StateTransition) TransitionState() (err error) { // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) if receiver == nil { - return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) + return nil, fmt.Errorf("Unable to create contract") } } // Transfer value from sender to receiver if err = self.transferValue(sender, receiver); err != nil { - return err + return } // Process the init code and create 'valid' contract - if tx.CreatesContract() { + if IsContractAddr(self.receiver) { // Evaluate the initialization script // and use the return value as the // script section for the state object. + self.data = nil ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Init()) code, err := self.Eval(receiver.Init(), receiver) if err != nil { - return fmt.Errorf("Error during init script run %v", err) + self.state.ResetStateObject(receiver) + + return nil, fmt.Errorf("Error during init script run %v", err) } receiver.script = code @@ -193,53 +233,55 @@ func (self *StateTransition) TransitionState() (err error) { if len(receiver.Script()) > 0 { ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Script()) - _, err := self.Eval(receiver.Script(), receiver) + ret, err = self.Eval(receiver.Script(), receiver) if err != nil { - return fmt.Errorf("Error during code execution %v", err) + self.state.ResetStateObject(receiver) + + return nil, fmt.Errorf("Error during code execution %v", err) } } } - return nil + return } func (self *StateTransition) transferValue(sender, receiver *StateObject) error { - if sender.Amount.Cmp(self.tx.Value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.tx.Value, sender.Amount) + if sender.Amount.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) } - if self.tx.Value.Cmp(ethutil.Big0) > 0 { - // Subtract the amount from the senders account - sender.SubAmount(self.tx.Value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.tx.Value) + //if self.value.Cmp(ethutil.Big0) > 0 { + // Subtract the amount from the senders account + sender.SubAmount(self.value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) - } + //ethutil.Config.Log.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) + //} return nil } func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { var ( - tx = self.tx block = self.block initiator = self.Sender() state = self.state ) - closure := NewClosure(initiator, context, script, state, self.gas, tx.GasPrice) + closure := NewClosure(initiator, context, script, state, self.gas, self.gasPrice) vm := NewVm(state, nil, RuntimeVars{ Origin: initiator.Address(), - BlockNumber: block.BlockInfo().Number, + Block: block, + BlockNumber: block.Number, PrevHash: block.PrevHash, Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, - Value: tx.Value, + Value: self.value, }) vm.Verbose = true - ret, _, err = closure.Call(vm, tx.Data, nil) + ret, _, err = closure.Call(vm, self.data, nil) return } -- cgit v1.2.3 From 5ea7598408321dcc15ae3dc2f2a740c9c2c644e1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:42:14 +0200 Subject: Update after each transition instead of at the end. Updating the state /after/ the entire transition creates invalid receipts. --- ethchain/state_manager.go | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a0051181f..b20ea401c 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -127,6 +127,9 @@ done: // Notify all subscribers self.Ethereum.Reactor().Post("newTx:post", tx) + // Update the state with pending changes + state.Update() + txGas.Sub(txGas, st.gas) accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} @@ -135,8 +138,6 @@ done: handled = append(handled, tx) } - fmt.Println("################# MADE\n", receipts, "\n############################") - parent.GasUsed = totalUsedGas return receipts, handled, unhandled, err @@ -154,7 +155,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) error { } // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) error { +func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) (err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -175,32 +176,42 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { return ParentError(block.PrevHash) } - fmt.Println(block.Receipts()) coinbase := state.GetOrNewStateObject(block.Coinbase) coinbase.SetGasPool(block.CalcGasLimit(parent)) + fmt.Println(block.Receipts()) + // Process the transactions on to current block - sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + receipts, _, _, _ := sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + defer func() { + if err != nil { + if len(receipts) == len(block.Receipts()) { + for i, receipt := range block.Receipts() { + ethutil.Config.Log.Debugf("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) + } + } else { + ethutil.Config.Log.Debugln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) + } + } + }() // Block validation - if err := sm.ValidateBlock(block); err != nil { + if err = sm.ValidateBlock(block); err != nil { fmt.Println("[SM] Error validating block:", err) return err } // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err := sm.AccumelateRewards(state, block); err != nil { + if err = sm.AccumelateRewards(state, block); err != nil { fmt.Println("[SM] Error accumulating reward", err) return err } - // Update the state with pending changes - state.Update() - if !block.State().Cmp(state) { - return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + return } // Calculate the new total difficulty and sync back to the db -- cgit v1.2.3 From 1b431f29e5c2283fb3d7a0c035e7ec575a563ca7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:42:28 +0200 Subject: Added missing types --- ethchain/types.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/types.go b/ethchain/types.go index ee70a8d28..9e7269f74 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -166,6 +166,7 @@ var opCodeToString = map[OpCode]string{ GASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution + POP: "POP", DUP: "DUP", SWAP: "SWAP", MLOAD: "MLOAD", -- cgit v1.2.3 From 7e6684d92600bc7def9469abea6d7abf33439017 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:42:47 +0200 Subject: Method for checking contract addresses --- ethchain/transaction.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 9044f586e..34ab357a1 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -10,6 +10,10 @@ import ( var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +func IsContractAddr(addr []byte) bool { + return bytes.Compare(addr, ContractAddr) == 0 +} + type Transaction struct { Nonce uint64 Recipient []byte @@ -149,7 +153,7 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() - if bytes.Compare(tx.Recipient, ContractAddr) == 0 { + if IsContractAddr(tx.Recipient) { tx.contractCreation = true } } -- cgit v1.2.3 From 9104dcc29c96baf645ff567bdd6800dc30b2784a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:45:29 +0200 Subject: Fixed call --- ethchain/vm.go | 77 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 35 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 5a15ba81b..6c30c9417 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -53,7 +53,8 @@ type Vm struct { type RuntimeVars struct { Origin []byte - BlockNumber uint64 + Block *Block + BlockNumber *big.Int PrevHash []byte Coinbase []byte Time int64 @@ -90,14 +91,14 @@ var isRequireError = false func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err error) { // Recover from any require exception defer func() { - if r := recover(); r != nil /*&& isRequireError*/ { + if r := recover(); r != nil { ret = closure.Return(nil) err = fmt.Errorf("%v", r) fmt.Println("vm err", err) } }() - ethutil.Config.Log.Debugf("[VM] Running %x\n", closure.object.Address()) + ethutil.Config.Log.Debugf("[VM] (~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) // Memory for the current closure mem := &Memory{} @@ -128,7 +129,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro op := OpCode(val.Uint()) vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - //ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -188,7 +188,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: require(7) gas.Set(GasCall) - addStepGasUsage(stack.data[stack.Len()-2]) + addStepGasUsage(stack.data[stack.Len()-1]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -208,9 +208,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } if !closure.UseGas(gas) { - ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) + err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas) - return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) + closure.UseGas(closure.Gas) + + return closure.Return(nil), err } vm.Printf(" (g) %-3v (%v)", gas, closure.Gas) @@ -431,7 +433,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.Printf(" => %d", l) case CALLDATACOPY: + panic("not implemented") case CODESIZE: + stack.Push(big.NewInt(int64(len(closure.Script)))) case CODECOPY: var ( size = int64(len(closure.Script)) @@ -461,7 +465,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case TIMESTAMP: stack.Push(big.NewInt(vm.vars.Time)) case NUMBER: - stack.Push(big.NewInt(int64(vm.vars.BlockNumber))) + stack.Push(vm.vars.BlockNumber) case DIFFICULTY: stack.Push(vm.vars.Diff) case GASLIMIT: @@ -595,10 +599,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: // TODO RE-WRITE require(7) - // Closure addr - addr := stack.Pop() + + vm.Endl() + + gas := stack.Pop() // Pop gas and value of the stack. - gas, value := stack.Popn() + value, addr := stack.Popn() // Pop input size and offset inSize, inOffset := stack.Popn() // Pop return size and offset @@ -607,37 +613,34 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - snapshot := vm.state.Snapshot() + //snapshot := vm.state.Snapshot() - closure.object.Nonce += 1 if closure.object.Amount.Cmp(value) < 0 { ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) stack.Push(ethutil.BigFalse) } else { - // Fetch the contract which will serve as the closure body - contract := vm.state.GetStateObject(addr.Bytes()) - - if contract != nil { - // Add the value to the state object - contract.AddAmount(value) - - // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, _, err := closure.Call(vm, args, hook) - if err != nil { - stack.Push(ethutil.BigFalse) - // Reset the changes applied this object - vm.state.Revert(snapshot) - } else { - stack.Push(ethutil.BigTrue) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) - } - } else { - ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) + stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) + + closure.object.SubAmount(value) + // Add the value to the state object + stateObject.AddAmount(value) + + // Create a new callable closure + closure := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) + // Executer the closure and get the return value (if any) + ret, _, err := closure.Call(vm, args, hook) + if err != nil { stack.Push(ethutil.BigFalse) + + // Reset the changes applied this object + vm.state.ResetStateObject(stateObject) + + ethutil.Config.Log.Debugf("Closure execution failed. %v\n", err) + } else { + stack.Push(ethutil.BigTrue) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } } case RETURN: @@ -645,6 +648,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) + vm.Printf(" => 0x%x", ret).Endl() + return closure.Return(ret), nil case SUICIDE: require(1) @@ -659,6 +664,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure + vm.Endl() + return closure.Return(nil), nil default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) -- cgit v1.2.3 From 80ffe1610c87bc56f625797a4f839a931af70558 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:45:46 +0200 Subject: Removed log --- ethchain/state_manager.go | 2 -- 1 file changed, 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index b20ea401c..59cd8eec6 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -180,8 +180,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea coinbase := state.GetOrNewStateObject(block.Coinbase) coinbase.SetGasPool(block.CalcGasLimit(parent)) - fmt.Println(block.Receipts()) - // Process the transactions on to current block receipts, _, _, _ := sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) defer func() { -- cgit v1.2.3 From 933aa63b7d302cff4287ba2814f3bd0f7744ed8e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 21:41:37 +0200 Subject: Length check on get --- ethchain/stack.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/stack.go b/ethchain/stack.go index 37d1f84b9..a9fa2e522 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -2,7 +2,7 @@ package ethchain import ( "fmt" - _ "github.com/ethereum/eth-go/ethutil" + "math" "math/big" ) @@ -118,7 +118,13 @@ func (m *Memory) Resize(size uint64) { } func (m *Memory) Get(offset, size int64) []byte { - return m.store[offset : offset+size] + if len(m.store) > int(offset) { + end := int(math.Min(float64(len(m.store)), float64(offset+size))) + + return m.store[offset:end] + } + + return nil } func (m *Memory) Len() int { -- cgit v1.2.3 From 0b8ba1d55b6b4cdb63e0967790e34b1b499b638f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:41:28 +0200 Subject: Renamed snapshot to copy/set and added it back to the VM --- ethchain/state.go | 15 ++++++--------- ethchain/vm.go | 39 ++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 98fcb24db..a08dfac83 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -79,9 +79,9 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { } func (self *State) ResetStateObject(stateObject *StateObject) { - stateObject.state.Reset() - delete(self.stateObjects, string(stateObject.Address())) + + stateObject.state.Reset() } func (self *State) UpdateStateObject(stateObject *StateObject) { @@ -154,13 +154,10 @@ func (self *State) Copy() *State { return nil } -func (s *State) Snapshot() *State { - return s.Copy() -} - -func (s *State) Revert(snapshot *State) { - s.trie = snapshot.trie - s.stateObjects = snapshot.stateObjects +func (self *State) Set(state *State) { + //s.trie = snapshot.trie + //s.stateObjects = snapshot.stateObjects + self = state } func (s *State) Put(key, object []byte) { diff --git a/ethchain/vm.go b/ethchain/vm.go index 6c30c9417..fc3c37dc1 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -1,12 +1,9 @@ package ethchain import ( - _ "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" - _ "github.com/obscuren/secp256k1-go" "math" - _ "math" "math/big" ) @@ -49,6 +46,8 @@ type Vm struct { Verbose bool logStr string + + err error } type RuntimeVars struct { @@ -128,11 +127,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { - gas.Add(gas, amount) + if amount.Cmp(ethutil.Big0) >= 0 { + gas.Add(gas, amount) + } } addStepGasUsage(GasStep) @@ -215,6 +214,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), err } + vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) vm.Printf(" (g) %-3v (%v)", gas, closure.Gas) mem.Resize(newMemSize) @@ -491,6 +491,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case DUP: require(1) stack.Push(stack.Peek()) + + vm.Printf(" => 0x%x", stack.Peek().Bytes()) case SWAP: require(2) x, y := stack.Popn() @@ -524,7 +526,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SSTORE: require(2) val, loc := stack.Popn() - closure.SetStorage(loc, ethutil.NewValue(val)) + + // FIXME This should be handled in the Trie it self + if val.Cmp(big.NewInt(0)) != 0 { + closure.SetStorage(loc, ethutil.NewValue(val)) + } // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) @@ -564,7 +570,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Snapshot the current stack so we are able to // revert back to it later. - snapshot := vm.state.Snapshot() + snapshot := vm.state.Copy() // Generate a new address addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) @@ -592,12 +598,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigFalse) // Revert the state as it was before. - vm.state.Revert(snapshot) + vm.state.Set(snapshot) } else { stack.Push(ethutil.BigD(addr)) } case CALL: - // TODO RE-WRITE require(7) vm.Endl() @@ -613,13 +618,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - //snapshot := vm.state.Snapshot() - if closure.object.Amount.Cmp(value) < 0 { ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) stack.Push(ethutil.BigFalse) } else { + snapshot := vm.state.Copy() + stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) closure.object.SubAmount(value) @@ -633,10 +638,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if err != nil { stack.Push(ethutil.BigFalse) - // Reset the changes applied this object - vm.state.ResetStateObject(stateObject) - ethutil.Config.Log.Debugf("Closure execution failed. %v\n", err) + + vm.err = err + vm.state.Set(snapshot) } else { stack.Push(ethutil.BigTrue) @@ -648,7 +653,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) - vm.Printf(" => 0x%x", ret).Endl() + vm.Printf(" => (%d) 0x%x", len(ret), ret).Endl() return closure.Return(ret), nil case SUICIDE: @@ -664,7 +669,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure - vm.Endl() + vm.Printf(" (g) %v", closure.Gas).Endl() return closure.Return(nil), nil default: -- cgit v1.2.3 From 6fcc6a2f7c35f10a8be3fc90bab39f2865adace9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:41:42 +0200 Subject: Changed copy/set --- ethchain/state_object.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5fc738fee..5b64c3b37 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -48,7 +48,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { } func NewStateObject(addr []byte) *StateObject { - return &StateObject{address: addr, Amount: new(big.Int)} + return &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} } func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { @@ -176,6 +176,26 @@ func (self *StateObject) RefundGas(gas, price *big.Int) { self.Amount.Sub(self.Amount, rGas) } +func (self *StateObject) Copy() *StateObject { + stateObject := NewStateObject(self.Address()) + stateObject.Amount.Set(self.Amount) + stateObject.ScriptHash = ethutil.CopyBytes(self.ScriptHash) + stateObject.Nonce = self.Nonce + if self.state != nil { + stateObject.state = self.state.Copy() + } + stateObject.script = ethutil.CopyBytes(self.script) + stateObject.initScript = ethutil.CopyBytes(self.initScript) + //stateObject.gasPool.Set(self.gasPool) + + return self +} + +func (self *StateObject) Set(stateObject *StateObject) { + self = stateObject +} + +/* func (self *StateObject) Copy() *StateObject { stCopy := &StateObject{} stCopy.address = make([]byte, len(self.address)) @@ -194,6 +214,7 @@ func (self *StateObject) Copy() *StateObject { return stCopy } +*/ // Returns the address of the contract/account func (c *StateObject) Address() []byte { -- cgit v1.2.3 From 8f29f6a4d4e2c62d3eff0dfd84cc8cab59dd28e8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:42:26 +0200 Subject: Removed some logging --- ethchain/state_manager.go | 2 ++ ethchain/state_transition.go | 17 ++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 59cd8eec6..36ba1731c 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -281,10 +281,12 @@ func (sm *StateManager) ValidateBlock(block *Block) error { return ValidationError("Block timestamp less then prev block %v", diff) } + /* XXX // 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 !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8757246a0..5f4588e48 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -219,25 +219,23 @@ func (self *StateTransition) Transition() (ret []byte, err error) { // and use the return value as the // script section for the state object. self.data = nil - ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Init()) - code, err := self.Eval(receiver.Init(), receiver) - if err != nil { + code, err, deepErr := self.Eval(receiver.Init(), receiver) + if err != nil || deepErr { self.state.ResetStateObject(receiver) - return nil, fmt.Errorf("Error during init script run %v", err) + return nil, fmt.Errorf("Error during init script run %v (deepErr = %v)", err, deepErr) } receiver.script = code } else { if len(receiver.Script()) > 0 { - ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Script()) - - ret, err = self.Eval(receiver.Script(), receiver) + var deepErr bool + ret, err, deepErr = self.Eval(receiver.Script(), receiver) if err != nil { self.state.ResetStateObject(receiver) - return nil, fmt.Errorf("Error during code execution %v", err) + return nil, fmt.Errorf("Error during code execution %v (deepErr = %v)", err, deepErr) } } } @@ -262,7 +260,7 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return nil } -func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { +func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error, deepErr bool) { var ( block = self.block initiator = self.Sender() @@ -282,6 +280,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by }) vm.Verbose = true ret, _, err = closure.Call(vm, self.data, nil) + deepErr = vm.err != nil return } -- cgit v1.2.3 From 09f37bd0235198145974db6430da0c429d2a0e79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:45:44 +0200 Subject: Returned to single method --- ethchain/state_transition.go | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5f4588e48..1f5b4f959 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -34,23 +34,6 @@ type StateTransition struct { cb, rec, sen *StateObject } -func Transition(coinbase, sender, receiver, data []byte, gas, gasPrice, value *big.Int, state *State, block *Block) (ret []byte, err error) { - stateTransition := &StateTransition{ - coinbase: coinbase, - receiver: receiver, - cb: state.GetOrNewStateObject(coinbase), - rec: state.GetOrNewStateObject(receiver), - sen: state.GetOrNewStateObject(sender), - gas: gas, - gasPrice: gasPrice, - value: value, - state: state, - block: block, - } - - return stateTransition.Transition() -} - func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} } @@ -168,20 +151,14 @@ func (self *StateTransition) TransitionState() (err error) { return } - defer self.RefundGas() - - _, err = self.Transition() - - return -} - -func (self *StateTransition) Transition() (ret []byte, err error) { var ( tx = self.tx sender = self.Sender() receiver *StateObject ) + defer self.RefundGas() + // Increment the nonce for the next transaction sender.Nonce += 1 @@ -204,7 +181,7 @@ func (self *StateTransition) Transition() (ret []byte, err error) { // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) if receiver == nil { - return nil, fmt.Errorf("Unable to create contract") + return fmt.Errorf("Unable to create contract") } } @@ -224,18 +201,18 @@ func (self *StateTransition) Transition() (ret []byte, err error) { if err != nil || deepErr { self.state.ResetStateObject(receiver) - return nil, fmt.Errorf("Error during init script run %v (deepErr = %v)", err, deepErr) + return fmt.Errorf("Error during init script run %v (deepErr = %v)", err, deepErr) } receiver.script = code } else { if len(receiver.Script()) > 0 { var deepErr bool - ret, err, deepErr = self.Eval(receiver.Script(), receiver) + _, err, deepErr = self.Eval(receiver.Script(), receiver) if err != nil { self.state.ResetStateObject(receiver) - return nil, fmt.Errorf("Error during code execution %v (deepErr = %v)", err, deepErr) + return fmt.Errorf("Error during code execution %v (deepErr = %v)", err, deepErr) } } } -- cgit v1.2.3 From 0c6b41f4c9edf33cf36b5e044b62e29161d50b07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 01:10:20 +0200 Subject: CALLDATACOPY --- ethchain/vm.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index fc3c37dc1..b9e8353fb 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -433,9 +433,28 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.Printf(" => %d", l) case CALLDATACOPY: - panic("not implemented") + var ( + size = int64(len(closure.Args)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + code := closure.Args[cOff : cOff+l] + + mem.Set(mOff, l, code) case CODESIZE: - stack.Push(big.NewInt(int64(len(closure.Script)))) + l := big.NewInt(int64(len(closure.Script))) + stack.Push(l) + + vm.Printf(" => %d", l) case CODECOPY: var ( size = int64(len(closure.Script)) -- cgit v1.2.3 From 7fb5e993e3a1cc2251bba7af1c85ed1d024b4b50 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 20:11:40 +0200 Subject: Moved 0 check to state object for now --- ethchain/state_object.go | 7 +++++++ ethchain/vm.go | 26 ++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5b64c3b37..17391963f 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -90,6 +90,13 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) + + // FIXME This should be handled in the Trie it self + if val.BigInt().Cmp(ethutil.Big0) == 0 { + c.state.trie.Delete(string(addr)) + return + } + //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } diff --git a/ethchain/vm.go b/ethchain/vm.go index b9e8353fb..bacd05ba5 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -325,21 +325,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(base) case LT: require(2) - y, x := stack.Popn() - vm.Printf(" %v < %v", x, y) + x, y := stack.Popn() + vm.Printf(" %v < %v", y, x) // x < y - if x.Cmp(y) < 0 { + if y.Cmp(x) < 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) } case GT: require(2) - y, x := stack.Popn() - vm.Printf(" %v > %v", x, y) + x, y := stack.Popn() + vm.Printf(" %v > %v", y, x) // x > y - if x.Cmp(y) > 0 { + if y.Cmp(x) > 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) @@ -520,7 +520,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case MLOAD: require(1) offset := stack.Pop() - stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) + val := ethutil.BigD(mem.Get(offset.Int64(), 32)) + stack.Push(val) + + vm.Printf(" => 0x%x", val.Bytes()) case MSTORE: // Store the value at stack top-1 in to memory at location stack top require(2) // Pop value of the stack @@ -541,15 +544,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.GetMem(loc) stack.Push(val.BigInt()) - vm.Printf(" {} 0x%x", val) + vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val) case SSTORE: require(2) val, loc := stack.Popn() - // FIXME This should be handled in the Trie it self - if val.Cmp(big.NewInt(0)) != 0 { - closure.SetStorage(loc, ethutil.NewValue(val)) - } + //if val.Cmp(big.NewInt(0)) != 0 { + closure.SetStorage(loc, ethutil.NewValue(val)) + //} // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) -- cgit v1.2.3 From 931ae0f116ca65c3758524160bf21e28f06db50e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 20:12:08 +0200 Subject: Append zero's in R & S --- ethchain/transaction.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 34ab357a1..29b167355 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -150,8 +150,11 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() tx.v = byte(decoder.Get(6).Uint()) - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() + + r := make([]byte, 32-len(decoder.Get(7).Bytes())) + s := make([]byte, 32-len(decoder.Get(8).Bytes())) + tx.r = append(r, decoder.Get(7).Bytes()...) + tx.s = append(s, decoder.Get(8).Bytes()...) if IsContractAddr(tx.Recipient) { tx.contractCreation = true @@ -175,7 +178,8 @@ func (tx *Transaction) String() string { `, tx.Hash(), len(tx.Recipient) == 0, - tx.Sender(), + //tx.Sender(), + nil, tx.Recipient, tx.Nonce, tx.GasPrice, -- cgit v1.2.3 From bb1641e4ecd92884f219d77acd5348ceb0782490 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:23:18 +0200 Subject: Clean up & refactored methods --- ethchain/state_manager.go | 53 ++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 36ba1731c..7444d5180 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -143,45 +143,31 @@ done: return receipts, handled, unhandled, err } -func (sm *StateManager) Process(block *Block, dontReact bool) error { - if !sm.bc.HasBlock(block.PrevHash) { - return ParentError(block.PrevHash) - } - - parent := sm.bc.GetBlock(block.PrevHash) - - return sm.ProcessBlock(parent.State(), parent, block, dontReact) - -} - -// Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) (err error) { +func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() - hash := block.Hash() - if sm.bc.HasBlock(hash) { + if sm.bc.HasBlock(block.Hash()) { return nil } + if !sm.bc.HasBlock(block.PrevHash) { + return ParentError(block.PrevHash) + } + + var ( + parent = sm.bc.GetBlock(block.PrevHash) + state = parent.State() + ) + // 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 state.Reset() - // 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 !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { - return ParentError(block.PrevHash) - } - - coinbase := state.GetOrNewStateObject(block.Coinbase) - coinbase.SetGasPool(block.CalcGasLimit(parent)) - - // Process the transactions on to current block - receipts, _, _, _ := sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + receipts, err := sm.ApplyDiff(state, parent, block) defer func() { if err != nil { if len(receipts) == len(block.Receipts()) { @@ -194,6 +180,10 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } }() + if err != nil { + return err + } + // Block validation if err = sm.ValidateBlock(block); err != nil { fmt.Println("[SM] Error validating block:", err) @@ -237,6 +227,17 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea return nil } + +func (sm *StateManager) ApplyDiff(state *State, parent, block *Block) (receipts Receipts, err error) { + coinbase := state.GetOrNewStateObject(block.Coinbase) + coinbase.SetGasPool(block.CalcGasLimit(parent)) + + // Process the transactions on to current block + receipts, _, _, _ = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + + return receipts, nil +} + func (sm *StateManager) CalculateTD(block *Block) bool { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { -- cgit v1.2.3 From 842d52db7b98fb309ed99ccc4b65ca3973fb81ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:23:51 +0200 Subject: Make sure that public key always uses 64 bytes --- ethchain/transaction.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 29b167355..2ab681030 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -89,11 +89,12 @@ func (tx *Transaction) Signature(key []byte) []byte { 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) + r := make([]byte, 32-len(tx.r)) + s := make([]byte, 32-len(tx.s)) + r = append(r, ethutil.CopyBytes(tx.r)...) + s = append(s, ethutil.CopyBytes(tx.s)...) - sig := append(dst, tx.s...) + sig := append(r, s...) sig = append(sig, tx.v-27) pubkey, _ := secp256k1.RecoverPubkey(hash, sig) @@ -127,6 +128,8 @@ func (tx *Transaction) Sign(privk []byte) error { func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + // TODO Remove prefixing zero's + return append(data, tx.v, tx.r, tx.s) } @@ -151,10 +154,8 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Data = decoder.Get(5).Bytes() tx.v = byte(decoder.Get(6).Uint()) - r := make([]byte, 32-len(decoder.Get(7).Bytes())) - s := make([]byte, 32-len(decoder.Get(8).Bytes())) - tx.r = append(r, decoder.Get(7).Bytes()...) - tx.s = append(s, decoder.Get(8).Bytes()...) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() if IsContractAddr(tx.Recipient) { tx.contractCreation = true @@ -178,8 +179,7 @@ func (tx *Transaction) String() string { `, tx.Hash(), len(tx.Recipient) == 0, - //tx.Sender(), - nil, + tx.Sender(), tx.Recipient, tx.Nonce, tx.GasPrice, -- cgit v1.2.3 From 803e4807ede157db36030c6415a4f515f723ccf0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:26:31 +0200 Subject: Removed comments --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 17391963f..0a2e28ded 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -94,10 +94,10 @@ func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { // FIXME This should be handled in the Trie it self if val.BigInt().Cmp(ethutil.Big0) == 0 { c.state.trie.Delete(string(addr)) + return } - //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } -- cgit v1.2.3 From d890258af6de8c5ef9701826fb4ee7c353788ad5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:26:51 +0200 Subject: Minor fixes to vm output --- ethchain/vm.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index bacd05ba5..a2e1c60fd 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -358,10 +358,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case NOT: require(1) x := stack.Pop() - if x.Cmp(ethutil.BigFalse) == 0 { - stack.Push(ethutil.BigTrue) - } else { + if x.Cmp(ethutil.BigFalse) > 0 { stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) } // 0x10 range @@ -542,16 +542,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + stack.Push(val.BigInt()) - vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val) + vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val.Bytes()) case SSTORE: require(2) val, loc := stack.Popn() - - //if val.Cmp(big.NewInt(0)) != 0 { closure.SetStorage(loc, ethutil.NewValue(val)) - //} // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) @@ -690,7 +688,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure - vm.Printf(" (g) %v", closure.Gas).Endl() + vm.Endl() return closure.Return(nil), nil default: -- cgit v1.2.3 From 614624754d2dcaf9344a3efbfa880c9b0ddba6be Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 13:42:30 +0200 Subject: Let the state create the object --- ethchain/vm.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index a2e1c60fd..432bc4e6d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -594,7 +594,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Generate a new address addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) // Create a new contract - contract := NewContract(addr, value, []byte("")) + contract := vm.state.NewStateObject(addr) + contract.Amount = value + // Set the init script contract.initScript = mem.Get(offset.Int64(), size.Int64()) // Transfer all remaining gas to the new -- cgit v1.2.3 From b9e8a3e02493d5bbf23cfcab259e66f6ae166612 Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 23 Jun 2014 12:54:10 +0100 Subject: modified logging API - package vars for tagged loggers - weed out spurious fmt.PrintX and log.PrintX logging - tried to second guess loglevel for some :) --- ethchain/block_chain.go | 30 ++++++++++++++++-------------- ethchain/dagger.go | 10 ++++++---- ethchain/state.go | 2 +- ethchain/state_manager.go | 20 +++++++++++--------- ethchain/state_object.go | 6 +++--- ethchain/state_transition.go | 7 +++---- ethchain/transaction_pool.go | 20 ++++++++++---------- ethchain/vm.go | 15 +++++++++------ 8 files changed, 59 insertions(+), 51 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 19b5248d7..f964e0e3a 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -4,11 +4,13 @@ import ( "bytes" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "log" + "github.com/ethereum/eth-go/ethlog" "math" "math/big" ) +var chainlogger = ethlog.NewLogger("CHAIN") + type BlockChain struct { Ethereum EthManager // The famous, the fabulous Mister GENESIIIIIIS (block) @@ -129,38 +131,38 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte // Start with the newest block we got, all the way back to the common block we both know for _, block := range blocks { if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[CHAIN] We have found the common parent block, breaking") + chainlogger.Infoln("[CHAIN] We have found the common parent block, breaking") break } chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[CHAIN] Incoming chain difficulty:", chainDifficulty) + chainlogger.Infoln("Incoming chain difficulty:", chainDifficulty) curChainDifficulty := new(big.Int) block := bc.CurrentBlock for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { i++ if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[CHAIN] We have found the common parent block, breaking") + chainlogger.Infoln("We have found the common parent block, breaking") break } anOtherBlock := bc.GetBlock(block.PrevHash) if anOtherBlock == nil { // We do not want to count the genesis block for difficulty since that's not being sent - log.Println("[CHAIN] At genesis block, breaking") + chainlogger.Infoln("At genesis block, breaking") break } curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty) + chainlogger.Infoln("Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - log.Printf("[CHAIN] The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) + chainlogger.Infof("The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) bc.ResetTillBlockHash(commonBlockHash) return false } else { - log.Println("[CHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + chainlogger.Infoln("Our chain showed the incoming chain who is boss. Ignoring.") return true } } @@ -195,7 +197,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { var block *Block for ; block != nil; block = bc.GetBlock(block.PrevHash) { if bytes.Compare(block.Hash(), hash) == 0 { - log.Println("[CHAIN] We have arrived at the the common parent block, breaking") + chainlogger.Infoln("We have arrived at the the common parent block, breaking") break } err = ethutil.Config.Db.Delete(block.Hash()) @@ -203,7 +205,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { return err } } - log.Println("[CHAIN] Split chain deleted and reverted to common parent block.") + chainlogger.Infoln("Split chain deleted and reverted to common parent block.") return nil } @@ -286,7 +288,7 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() - ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + chainlogger.Infof("Last known block height #%d\n", bc.LastBlockNumber) } else { AddTestNetFunds(bc.genesisBlock) @@ -294,14 +296,14 @@ func (bc *BlockChain) setLastBlock() { // Prepare the genesis block bc.Add(bc.genesisBlock) - //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) + //chainlogger.Infof("root %x\n", bm.bc.genesisBlock.State().Root) //bm.bc.genesisBlock.PrintHash() } // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - ethutil.Config.Log.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) + chainlogger.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { @@ -358,6 +360,6 @@ func (bc *BlockChain) writeBlockInfo(block *Block) { func (bc *BlockChain) Stop() { if bc.CurrentBlock != nil { - log.Println("[CHAIN] Stopped") + chainlogger.Infoln("Stopped") } } diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 565e1e447..43725e336 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -2,14 +2,16 @@ package ethchain import ( "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethlog" "github.com/obscuren/sha3" "hash" - "log" "math/big" "math/rand" "time" ) +var powlogger = ethlog.NewLogger("POW") + type PoW interface { Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool @@ -29,14 +31,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - //ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") + //powlogger.Infoln("Received reactor event; breaking out.") return nil default: i++ if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - ethutil.Config.Log.Infoln("[POW] Hashing @", int64(hashes), "khash") + powlogger.Infoln("Hashing @", int64(hashes), "khash") } sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) @@ -81,7 +83,7 @@ func (dag *Dagger) Find(obj *big.Int, resChan chan int64) { rnd := r.Int63() res := dag.Eval(big.NewInt(rnd)) - log.Printf("rnd %v\nres %v\nobj %v\n", rnd, res, obj) + powlogger.Infof("rnd %v\nres %v\nobj %v\n", rnd, res, obj) if res.Cmp(obj) < 0 { // Post back result on the channel resChan <- rnd diff --git a/ethchain/state.go b/ethchain/state.go index a08dfac83..e28b91909 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -125,7 +125,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(+) %x\n", addr) + statelogger.Infof("(+) %x\n", addr) stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 36ba1731c..20e0a13a2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,14 +3,16 @@ package ethchain import ( "bytes" "container/list" - "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "github.com/ethereum/eth-go/ethlog" "math/big" "sync" "time" ) +var statelogger = ethlog.NewLogger("STATE") + type BlockProcessor interface { ProcessBlock(block *Block) } @@ -120,7 +122,7 @@ done: break done default: - ethutil.Config.Log.Infoln(err) + statelogger.Infoln(err) } } @@ -186,29 +188,29 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea if err != nil { if len(receipts) == len(block.Receipts()) { for i, receipt := range block.Receipts() { - ethutil.Config.Log.Debugf("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) + statelogger.Debugf("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) } } else { - ethutil.Config.Log.Debugln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) + statelogger.Warnln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) } } }() // Block validation if err = sm.ValidateBlock(block); err != nil { - fmt.Println("[SM] Error validating block:", err) + statelogger.Errorln("Error validating block:", err) return err } // I'm not sure, but I don't know if there should be thrown // any errors at this time. if err = sm.AccumelateRewards(state, block); err != nil { - fmt.Println("[SM] Error accumulating reward", err) + statelogger.Errorln("Error accumulating reward", err) return err } if !block.State().Cmp(state) { - err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + statelogger.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return } @@ -221,7 +223,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea sm.bc.Add(block) sm.notifyChanges(state) - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.Number, block.Hash()) + statelogger.Infof("Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) @@ -232,7 +234,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea sm.Ethereum.TxPool().RemoveInvalid(state) } else { - fmt.Println("total diff failed") + statelogger.Errorln("total diff failed") } return nil diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5b64c3b37..f53f47d7e 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -124,13 +124,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Infof("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -151,7 +151,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: fuel (+ %v)", self.Address(), self.gasPool) + statelogger.Infof("%x: fuel (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1f5b4f959..f84c3486b 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,7 +2,6 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -135,12 +134,12 @@ func (self *StateTransition) preCheck() (err error) { } func (self *StateTransition) TransitionState() (err error) { - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", self.tx.Hash()) + statelogger.Infof("(~) %x\n", self.tx.Hash()) /* defer func() { if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) + logger.Infoln(r) err = fmt.Errorf("state transition err %v", r) } }() @@ -231,7 +230,7 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(self.value) - //ethutil.Config.Log.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) + //statelogger.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) //} return nil diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 24836222a..44218ae28 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -3,15 +3,15 @@ package ethchain import ( "bytes" "container/list" - "errors" "fmt" - "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "log" + "github.com/ethereum/eth-go/ethlog" "math/big" "sync" ) +var txplogger = ethlog.NewLogger("TXP") + const ( txPoolQueueSize = 50 ) @@ -97,7 +97,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract fmt.Printf("state root before update %x\n", state.Root()) defer func() { if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) + txplogger.Infoln(r) err = fmt.Errorf("%v", r) } }() @@ -156,7 +156,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract fmt.Printf("state root after receiver update %x\n", state.Root()) } - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + txplogger.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) return } @@ -168,7 +168,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { block := pool.Ethereum.BlockChain().CurrentBlock // Something has gone horribly wrong if this happens if block == nil { - return errors.New("[TXPL] No last block on the block chain") + return fmt.Errorf("[TXPL] No last block on the block chain") } if len(tx.Recipient) != 20 { @@ -188,7 +188,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { if tx.IsContract() { if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { - return fmt.Errorf("[TXPL] Gasprice to low, %s given should be at least %d.", tx.GasPrice, minGasPrice) + return fmt.Errorf("[TXPL] Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice) } } @@ -215,12 +215,12 @@ out: // Validate the transaction err := pool.ValidateTransaction(tx) if err != nil { - ethutil.Config.Log.Debugln("Validating Tx failed", err) + txplogger.Debugln("Validating Tx failed", err) } else { // Call blocking version. pool.addTransaction(tx) - ethutil.Config.Log.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) @@ -282,5 +282,5 @@ func (pool *TxPool) Stop() { pool.Flush() - log.Println("[TXP] Stopped") + txplogger.Infoln("Stopped") } diff --git a/ethchain/vm.go b/ethchain/vm.go index b9e8353fb..75bcfd782 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -3,10 +3,13 @@ package ethchain import ( "fmt" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethlog" "math" "math/big" ) +var vmlogger = ethlog.NewLogger("VM") + var ( GasStep = big.NewInt(1) GasSha = big.NewInt(20) @@ -72,7 +75,7 @@ func (self *Vm) Printf(format string, v ...interface{}) *Vm { func (self *Vm) Endl() *Vm { if self.Verbose { - ethutil.Config.Log.Infoln(self.logStr) + vmlogger.Infoln(self.logStr) self.logStr = "" } @@ -93,11 +96,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if r := recover(); r != nil { ret = closure.Return(nil) err = fmt.Errorf("%v", r) - fmt.Println("vm err", err) + vmlogger.Errorln("vm err", err) } }() - ethutil.Config.Log.Debugf("[VM] (~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) // Memory for the current closure mem := &Memory{} @@ -638,7 +641,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro args := mem.Get(inOffset.Int64(), inSize.Int64()) if closure.object.Amount.Cmp(value) < 0 { - ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) stack.Push(ethutil.BigFalse) } else { @@ -657,7 +660,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if err != nil { stack.Push(ethutil.BigFalse) - ethutil.Config.Log.Debugf("Closure execution failed. %v\n", err) + vmlogger.Debugf("Closure execution failed. %v\n", err) vm.err = err vm.state.Set(snapshot) @@ -692,7 +695,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), nil default: - ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) + vmlogger.Debugf("Invalid opcode %x\n", op) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } -- cgit v1.2.3 From 16e8fc7427115e67096c6056b2ad9401803fcb44 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 16:11:55 +0200 Subject: Logging order --- ethchain/state_object.go | 1 - ethchain/vm.go | 13 ++++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 0a2e28ded..270c9a7f8 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -91,7 +91,6 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) - // FIXME This should be handled in the Trie it self if val.BigInt().Cmp(ethutil.Big0) == 0 { c.state.trie.Delete(string(addr)) diff --git a/ethchain/vm.go b/ethchain/vm.go index 432bc4e6d..4c6c5e24d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -93,7 +93,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if r := recover(); r != nil { ret = closure.Return(nil) err = fmt.Errorf("%v", r) - fmt.Println("vm err", err) + fmt.Println(err) } }() @@ -106,11 +106,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require := func(m int) { if stack.Len() < m { isRequireError = true - panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) + panic(fmt.Sprintf("stack err = %d, req = %d", stack.Len(), m)) } } - // Instruction pointer + // Program counter pc := big.NewInt(0) // Current step count step := 0 @@ -593,16 +593,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Generate a new address addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) + + vm.Printf(" (*) %x", addr).Endl() + // Create a new contract contract := vm.state.NewStateObject(addr) contract.Amount = value // Set the init script - contract.initScript = mem.Get(offset.Int64(), size.Int64()) + contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) - //closure.UseGas(gas) // Create the closure c := NewClosure(closure.caller, @@ -613,6 +615,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Price) // Call the closure and set the return value as // main script. + var err error c.Script, gas, err = c.Call(vm, nil, hook) if err != nil { -- cgit v1.2.3 From a02edf7a9306c9c0b2f0208152347b47f1a4e689 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Jun 2014 16:40:06 +0100 Subject: put back extra debug detail logging to the right places using logger.DebugDetailf --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 7d7352af4..26ad3e982 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -158,7 +158,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - statelogger.Infof("%x: fuel (+ %v)", self.Address(), self.gasPool) + statelogger.DebugDetailf("%x: fuel (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { -- cgit v1.2.3 From 39cb34850a573ea9b2ea73eb624139684502bc79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Jun 2014 11:25:43 +0200 Subject: Added instruction numbers --- ethchain/asm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 277326ff9..09d6af56f 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -18,7 +18,7 @@ func Disassemble(script []byte) (asm []string) { // Get the opcode (it must be an opcode!) op := OpCode(val) - asm = append(asm, fmt.Sprintf("%v", op)) + asm = append(asm, fmt.Sprintf("%04v: %v", pc, op)) switch op { case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: @@ -28,7 +28,7 @@ func Disassemble(script []byte) (asm []string) { if len(data) == 0 { data = []byte{0} } - asm = append(asm, fmt.Sprintf("0x%x", data)) + asm = append(asm, fmt.Sprintf("%04v: 0x%x", pc, data)) pc.Add(pc, big.NewInt(a-1)) } -- cgit v1.2.3 From 0ed19d9f2024744ba93d0e34db6939766b3cfed5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Jun 2014 11:26:42 +0200 Subject: Logging, variable rearrangement --- ethchain/block_chain.go | 11 +++++------ ethchain/vm.go | 31 +++++++++++++++---------------- 2 files changed, 20 insertions(+), 22 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 19b5248d7..286a158ba 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -174,18 +174,12 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { bc.LastBlockHash = bc.genesisBlock.Hash() bc.LastBlockNumber = 1 } else { - // TODO: Somehow this doesn't really give the right numbers, double check. - // TODO: Change logs into debug lines returnTo = bc.GetBlock(hash) bc.CurrentBlock = returnTo bc.LastBlockHash = returnTo.Hash() - //info := bc.BlockInfo(returnTo) bc.LastBlockNumber = returnTo.Number.Uint64() } - // XXX Why are we resetting? This is the block chain, it has nothing to do with states - //bc.Ethereum.StateManager().PrepareDefault(returnTo) - // Manually reset the last sync block err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { @@ -231,6 +225,11 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { // Get the block of the chain block := bc.GetBlock(currentHash) + if block == nil { + ethutil.Config.Log.Debugf("Unexpected error during GetChainFromHash: Unable to find %x\n", currentHash) + break + } + currentHash = block.PrevHash chain = append(chain, block.Value().Val) diff --git a/ethchain/vm.go b/ethchain/vm.go index 4c6c5e24d..199eaae50 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -99,22 +99,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro ethutil.Config.Log.Debugf("[VM] (~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) - // Memory for the current closure - mem := &Memory{} - // New stack (should this be shared?) - stack := NewStack() - require := func(m int) { - if stack.Len() < m { - isRequireError = true - panic(fmt.Sprintf("stack err = %d, req = %d", stack.Len(), m)) + var ( + op OpCode + + mem = &Memory{} + stack = NewStack() + pc = big.NewInt(0) + step = 0 + prevStep = 0 + require = func(m int) { + if stack.Len() < m { + isRequireError = true + panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) + } } - } - - // Program counter - pc := big.NewInt(0) - // Current step count - step := 0 - prevStep := 0 + ) for { prevStep = step @@ -125,7 +124,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the memory location of pc val := closure.Get(pc) // Get the opcode (it must be an opcode!) - op := OpCode(val.Uint()) + op = OpCode(val.Uint()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { -- cgit v1.2.3 From 853053a3b204ddf4ae935e70e0aa5b5d8994493e Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 26 Jun 2014 18:45:57 +0100 Subject: go fmt --- ethchain/block_chain.go | 2 +- ethchain/dagger.go | 3 +-- ethchain/state_manager.go | 2 +- ethchain/transaction_pool.go | 2 +- ethchain/vm.go | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 05b2564cf..d0fea6641 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,9 +2,9 @@ package ethchain import ( "bytes" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/eth-go/ethlog" "math" "math/big" ) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 43725e336..08c4826db 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -1,8 +1,8 @@ package ethchain import ( - "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" "hash" "math/big" @@ -31,7 +31,6 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - //powlogger.Infoln("Received reactor event; breaking out.") return nil default: i++ diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index e5941b165..312ba3084 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,9 +3,9 @@ package ethchain import ( "bytes" "container/list" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/eth-go/ethlog" "math/big" "sync" "time" diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 44218ae28..6ab8d83d9 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -4,8 +4,8 @@ import ( "bytes" "container/list" "fmt" - "github.com/ethereum/eth-go/ethwire" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethwire" "math/big" "sync" ) diff --git a/ethchain/vm.go b/ethchain/vm.go index 20d355674..82591e274 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,8 +2,8 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethutil" "math" "math/big" ) -- cgit v1.2.3 From 423beddf574383ec58246938f738f08cd50f031a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 27 Jun 2014 00:16:49 +0200 Subject: nil check --- ethchain/block_chain.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index d0fea6641..6e4c72b27 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -221,9 +221,16 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { startNumber := parentNumber + count num := lastNumber - for ; num > startNumber; currentHash = bc.GetBlock(currentHash).PrevHash { + for num > startNumber { num-- + + block := bc.GetBlock(currentHash) + if block == nil { + break + } + currentHash = block.PrevHash } + for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { // Get the block of the chain block := bc.GetBlock(currentHash) -- cgit v1.2.3 From 79009ca074d77561c655b65254103b4070b74c69 Mon Sep 17 00:00:00 2001 From: zelig Date: Fri, 27 Jun 2014 15:56:45 +0100 Subject: transitional ethutil.ReadConfig fixes in ethchain tests (they still fail! FIXME :) --- ethchain/block_chain_test.go | 10 +++++++++- ethchain/state_object_test.go | 4 ++-- ethchain/state_test.go | 2 +- ethchain/vm_test.go | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index ecaf8ca89..bbc96c823 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -1,6 +1,7 @@ package ethchain import ( + "container/list" "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" @@ -30,6 +31,10 @@ func (s *TestManager) PeerCount() int { return 0 } +func (s *TestManager) Peers() *list.List { + return list.New() +} + func (s *TestManager) BlockChain() *BlockChain { return s.blockChain } @@ -50,7 +55,8 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { } func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest", ethutil.LogStd, "") + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, err := ethdb.NewMemDatabase() if err != nil { @@ -71,12 +77,14 @@ func NewTestManager() *TestManager { return testManager } + func (tm *TestManager) AddFakeBlock(blk []byte) error { block := NewBlockFromBytes(blk) tm.Blocks = append(tm.Blocks, block) err := tm.StateManager().Process(block, false) return err } + func (tm *TestManager) CreateChain1() error { err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 32, 251, 128, 160, 4, 10, 11, 225, 132, 86, 146, 227, 229, 137, 164, 245, 16, 139, 219, 12, 251, 178, 154, 168, 210, 18, 84, 40, 250, 41, 124, 92, 169, 242, 246, 180, 192, 192}) err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 222, 229, 152, 228, 200, 163, 244, 144, 120, 18, 203, 253, 195, 185, 105, 131, 163, 226, 116, 40, 140, 68, 249, 198, 221, 152, 121, 0, 124, 11, 180, 125, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 224, 4, 132, 83, 48, 36, 250, 128, 160, 79, 58, 51, 246, 238, 249, 210, 253, 136, 83, 71, 134, 49, 114, 190, 189, 242, 78, 100, 238, 101, 84, 204, 176, 198, 25, 139, 151, 60, 84, 51, 126, 192, 192}) diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go index 91ed7c0dd..2588100d0 100644 --- a/ethchain/state_object_test.go +++ b/ethchain/state_object_test.go @@ -9,7 +9,7 @@ import ( ) func TestSync(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd, "") + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) @@ -28,7 +28,7 @@ func TestSync(t *testing.T) { } func TestObjectGet(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd, "") + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, _ := ethdb.NewMemDatabase() ethutil.Config.Db = db diff --git a/ethchain/state_test.go b/ethchain/state_test.go index 292129953..503bdddb4 100644 --- a/ethchain/state_test.go +++ b/ethchain/state_test.go @@ -7,7 +7,7 @@ import ( ) func TestSnapshot(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd, "") + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 518a88766..c569d89ae 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -12,7 +12,7 @@ import ( ) func TestRun4(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd, "") + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) -- cgit v1.2.3 From 707d413761927f5ad95298e666e297b820ad0901 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:26:58 +0100 Subject: refactor ethutil/trie to ethtrie --- ethchain/state.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index e28b91909..4c66a973e 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,6 +1,7 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -12,7 +13,7 @@ import ( // * Accounts type State struct { // The trie for this structure - trie *ethutil.Trie + trie *ethtrie.Trie stateObjects map[string]*StateObject @@ -20,7 +21,7 @@ type State struct { } // Create a new state from a given trie -func NewState(trie *ethutil.Trie) *State { +func NewState(trie *ethtrie.Trie) *State { return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } -- cgit v1.2.3 From dabaa4cce01586fd8b1b9314073a1d26f35355c8 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 18:30:05 +0100 Subject: change all modified calls to ethtrie, ethutil and ethcrypto functions --- ethchain/block.go | 16 +++++++++------- ethchain/block_chain.go | 2 +- ethchain/dagger.go | 3 ++- ethchain/genesis.go | 7 ++++--- ethchain/state.go | 5 +++-- ethchain/state_manager.go | 4 +++- ethchain/state_object.go | 11 +++++++---- ethchain/transaction.go | 7 ++++--- ethchain/vm.go | 5 +++-- 9 files changed, 36 insertions(+), 24 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index fee4a2d59..ed5b754f8 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -3,6 +3,8 @@ package ethchain import ( "bytes" "fmt" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" "strconv" @@ -102,18 +104,18 @@ func CreateBlock(root interface{}, } block.SetUncles([]*Block{}) - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) + block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, root)) return block } // Returns a hash of the block func (block *Block) Hash() []byte { - return ethutil.Sha3Bin(block.Value().Encode()) + return ethcrypto.Sha3Bin(block.Value().Encode()) } func (block *Block) HashNoNonce() []byte { - return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, + return ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, block.GasLimit, block.GasUsed, block.Time, block.Extra})) @@ -239,7 +241,7 @@ func (block *Block) SetUncles(uncles []*Block) { block.Uncles = uncles // Sha of the concatenated uncles - block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles())) + block.UncleSha = ethcrypto.Sha3Bin(ethutil.Encode(block.rlpUncles())) } func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { @@ -250,7 +252,7 @@ func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { func (block *Block) setTransactions(txs []*Transaction) { block.transactions = txs - trie := ethutil.NewTrie(ethutil.Config.Db, "") + trie := ethtrie.NewTrie(ethutil.Config.Db, "") for i, tx := range txs { trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) } @@ -287,7 +289,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() @@ -329,7 +331,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6e4c72b27..7a481ed7c 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -278,7 +278,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", } { - codedAddr := ethutil.FromHex(addr) + codedAddr := ethutil.Hex2Bytes(addr) account := block.state.GetAccount(codedAddr) account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 08c4826db..46b1081e9 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -1,6 +1,7 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" @@ -40,7 +41,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { powlogger.Infoln("Hashing @", int64(hashes), "khash") } - sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) + sha := ethcrypto.Sha3Bin(big.NewInt(r.Int63()).Bytes()) if pow.Verify(hash, diff, sha) { return sha } diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 359c47c26..54a3bc766 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -1,6 +1,7 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -11,13 +12,13 @@ import ( var ZeroHash256 = make([]byte, 32) var ZeroHash160 = make([]byte, 20) -var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) +var EmptyShaList = ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{})) var GenesisHeader = []interface{}{ // Previous hash (none) ZeroHash256, // Sha of uncles - ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{})), // Coinbase ZeroHash160, // Root state @@ -39,7 +40,7 @@ var GenesisHeader = []interface{}{ // Extra nil, // Nonce - ethutil.Sha3Bin(big.NewInt(42).Bytes()), + ethcrypto.Sha3Bin(big.NewInt(42).Bytes()), } var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}} diff --git a/ethchain/state.go b/ethchain/state.go index 4c66a973e..dc2d3c73b 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,6 +1,7 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -74,7 +75,7 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } -func (s *State) EachStorage(cb ethutil.EachCallback) { +func (s *State) EachStorage(cb ethtrie.EachCallback) { it := s.trie.NewIterator() it.Each(cb) } @@ -92,7 +93,7 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { self.stateObjects[string(addr)] = stateObject } - ethutil.Config.Db.Put(ethutil.Sha3Bin(stateObject.Script()), stateObject.Script()) + ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) self.trie.Update(string(addr), string(stateObject.RlpEncode())) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 312ba3084..f199e20ec 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "container/list" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -38,6 +39,7 @@ type EthManager interface { IsMining() bool IsListening() bool Peers() *list.List + KeyManager() *ethcrypto.KeyManager } type StateManager struct { @@ -293,7 +295,7 @@ func (sm *StateManager) ValidateBlock(block *Block) error { // Verify the nonce of the block. Return an error if it's not valid if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { - return ValidationError("Block's nonce is invalid (= %v)", ethutil.Hex(block.Nonce)) + return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce)) } return nil diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 480b4055d..e55540153 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -2,6 +2,8 @@ package ethchain import ( "fmt" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" "strings" @@ -39,7 +41,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { contract := state.NewStateObject(addr) contract.initScript = tx.Data - contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, "")) + contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) return contract } @@ -53,7 +55,7 @@ func NewStateObject(addr []byte) *StateObject { func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { contract := &StateObject{address: address, Amount: Amount, Nonce: 0} - contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) + contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) return contract } @@ -246,7 +248,7 @@ func (c *StateObject) RlpEncode() []byte { root = "" } - return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethutil.Sha3Bin(c.script)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethcrypto.Sha3Bin(c.script)}) } func (c *StateObject) RlpDecode(data []byte) { @@ -254,7 +256,8 @@ func (c *StateObject) RlpDecode(data []byte) { c.Nonce = decoder.Get(0).Uint() c.Amount = decoder.Get(1).BigInt() - c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.ScriptHash = decoder.Get(3).Bytes() diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2ab681030..11f786b36 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "fmt" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -62,7 +63,7 @@ func (self *Transaction) TotalValue() *big.Int { func (tx *Transaction) Hash() []byte { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) + return ethcrypto.Sha3Bin(ethutil.NewValue(data).Encode()) } func (tx *Transaction) CreatesContract() bool { @@ -75,7 +76,7 @@ func (tx *Transaction) IsContract() bool { } func (tx *Transaction) CreationAddress() []byte { - return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] + return ethcrypto.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } func (tx *Transaction) Signature(key []byte) []byte { @@ -111,7 +112,7 @@ func (tx *Transaction) Sender() []byte { return nil } - return ethutil.Sha3Bin(pubkey[1:])[12:] + return ethcrypto.Sha3Bin(pubkey[1:])[12:] } func (tx *Transaction) Sign(privk []byte) error { diff --git a/ethchain/vm.go b/ethchain/vm.go index 82591e274..66b5a9182 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,6 +2,7 @@ package ethchain import ( "fmt" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "math" @@ -398,7 +399,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SHA3: require(2) size, offset := stack.Popn() - data := ethutil.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) + data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) stack.Push(ethutil.BigD(data)) // 0x30 range @@ -594,7 +595,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro snapshot := vm.state.Copy() // Generate a new address - addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) + addr := ethcrypto.CreateAddress(closure.caller.Address(), closure.caller.N()) vm.Printf(" (*) %x", addr).Endl() -- cgit v1.2.3 From 8ddd4c4c52eef9f382a321fa880adba4a1e35ee2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 13:09:04 +0200 Subject: wip --- ethchain/state_manager.go | 3 ++- ethchain/state_object.go | 5 ++++- ethchain/state_transition.go | 45 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 312ba3084..48c6401e3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "container/list" + "fmt" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -200,7 +201,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { } if !block.State().Cmp(state) { - statelogger.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 480b4055d..edac4f6dc 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -48,7 +48,10 @@ func MakeContract(tx *Transaction, state *State) *StateObject { } func NewStateObject(addr []byte) *StateObject { - return &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} + object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} + object.state = NewState(ethutil.NewTrie(ethutil.Config.Db, "")) + + return object } func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index f84c3486b..4b4cbeb51 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -1,7 +1,9 @@ package ethchain import ( + "bytes" "fmt" + "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -236,6 +238,8 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return nil } +var testAddr = ethutil.FromHex("ec4f34c97e43fbb2816cfd95e388353c7181dab1") + func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error, deepErr bool) { var ( block = self.block @@ -258,5 +262,46 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by ret, _, err = closure.Call(vm, self.data, nil) deepErr = vm.err != nil + /* + if bytes.Compare(testAddr, context.Address()) == 0 { + trie := context.state.trie + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + fmt.Printf("%x : %x\n", key, v.Str()) + }) + fmt.Println("\n\n") + } + */ + + Paranoia := true + if Paranoia { + var ( + trie = context.state.trie + trie2 = ethutil.NewTrie(ethutil.Config.Db, "") + ) + + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + trie2.Update(key, v.Str()) + }) + + a := ethutil.NewValue(trie2.Root).Bytes() + b := ethutil.NewValue(context.state.trie.Root).Bytes() + if bytes.Compare(a, b) != 0 { + fmt.Printf("original: %x\n", trie.Root) + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + fmt.Printf("%x : %x\n", key, v.Str()) + }) + + fmt.Printf("new: %x\n", trie2.Root) + trie2.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + fmt.Printf("%x : %x\n", key, v.Str()) + }) + + return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false + } + } + return } -- cgit v1.2.3 From ed276cd7c241749a9cf8add4e2fae3d3608a7ea4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 20:03:31 +0200 Subject: Added Paranoia check for VM execution --- ethchain/state.go | 81 -------------------------------------------- ethchain/state_manager.go | 8 +++-- ethchain/state_test.go | 4 +-- ethchain/state_transition.go | 33 ++++++++---------- ethchain/vm_test.go | 8 ++--- 5 files changed, 26 insertions(+), 108 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index e28b91909..51d86fe2a 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -204,84 +204,3 @@ func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage } - -/* - -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, state := range s.states { - state.Reset() - } -} - -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, state := range s.states { - state.Sync() - } - - s.trie.Sync() -} -func (s *State) GetStateObject(addr []byte) *StateObject { - data := s.trie.Get(string(addr)) - if data == "" { - return nil - } - - stateObject := NewStateObjectFromBytes(addr, []byte(data)) - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) - stateObject.state = cachedStateObject - } - - return stateObject -} - -// Updates any given state object -func (s *State) UpdateStateObject(object *StateObject) { - addr := object.Address() - - if object.state != nil && s.states[string(addr)] == nil { - s.states[string(addr)] = object.state - } - - ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) - - s.trie.Update(string(addr), string(object.RlpEncode())) - - s.manifest.AddObjectChange(object) -} - -func (s *State) GetAccount(addr []byte) (account *StateObject) { - data := s.trie.Get(string(addr)) - if data == "" { - account = NewAccount(addr, big.NewInt(0)) - } else { - account = NewStateObjectFromBytes(addr, []byte(data)) - } - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - account.state = cachedStateObject - } - - return -} - -func (s *State) Copy() *State { - state := NewState(s.trie.Copy()) - for k, subState := range s.states { - state.states[k] = subState.Copy() - } - - return state -} -*/ diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 48c6401e3..363aa3da7 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -123,7 +123,8 @@ done: break done default: - statelogger.Infoln(err) + //statelogger.Infoln(err) + return nil, nil, nil, err } } @@ -236,7 +237,10 @@ func (sm *StateManager) ApplyDiff(state *State, parent, block *Block) (receipts coinbase.SetGasPool(block.CalcGasLimit(parent)) // Process the transactions on to current block - receipts, _, _, _ = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + receipts, _, _, err = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + if err != nil { + return nil, err + } return receipts, nil } diff --git a/ethchain/state_test.go b/ethchain/state_test.go index 503bdddb4..95be0f373 100644 --- a/ethchain/state_test.go +++ b/ethchain/state_test.go @@ -16,12 +16,12 @@ func TestSnapshot(t *testing.T) { state.UpdateStateObject(stateObject) stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42)) - snapshot := state.Snapshot() + snapshot := state.Copy() stateObject = state.GetStateObject([]byte("aa")) stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(43)) - state.Revert(snapshot) + state.Set(snapshot) stateObject = state.GetStateObject([]byte("aa")) if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 4b4cbeb51..b18091691 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -226,20 +226,14 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) } - //if self.value.Cmp(ethutil.Big0) > 0 { // Subtract the amount from the senders account sender.SubAmount(self.value) // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(self.value) - //statelogger.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) - //} - return nil } -var testAddr = ethutil.FromHex("ec4f34c97e43fbb2816cfd95e388353c7181dab1") - func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error, deepErr bool) { var ( block = self.block @@ -263,6 +257,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by deepErr = vm.err != nil /* + var testAddr = ethutil.FromHex("ec4f34c97e43fbb2816cfd95e388353c7181dab1") if bytes.Compare(testAddr, context.Address()) == 0 { trie := context.state.trie trie.NewIterator().Each(func(key string, v *ethutil.Value) { @@ -273,7 +268,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by } */ - Paranoia := true + Paranoia := true // TODO Create a flag for this if Paranoia { var ( trie = context.state.trie @@ -287,17 +282,19 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by a := ethutil.NewValue(trie2.Root).Bytes() b := ethutil.NewValue(context.state.trie.Root).Bytes() if bytes.Compare(a, b) != 0 { - fmt.Printf("original: %x\n", trie.Root) - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - v.Decode() - fmt.Printf("%x : %x\n", key, v.Str()) - }) - - fmt.Printf("new: %x\n", trie2.Root) - trie2.NewIterator().Each(func(key string, v *ethutil.Value) { - v.Decode() - fmt.Printf("%x : %x\n", key, v.Str()) - }) + /* + statelogger.Debugf("(o): %x\n", trie.Root) + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + statelogger.Debugf("%x : %x\n", key, v.Str()) + }) + + statelogger.Debugf("(c): %x\n", trie2.Root) + trie2.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + statelogger.Debugf("%x : %x\n", key, v.Str()) + }) + */ return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index c569d89ae..c8023cd79 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -5,9 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" - "github.com/obscuren/mutan" "math/big" - "strings" "testing" ) @@ -17,7 +15,7 @@ func TestRun4(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - callerScript, err := mutan.Compile(strings.NewReader(` + callerScript, err := ethutil.Compile(` this.store[this.origin()] = 10**20 hello := "world" @@ -31,7 +29,7 @@ func TestRun4(t *testing.T) { this.store[to] = this.store[to] + value } } - `), false) + `) if err != nil { fmt.Println(err) } @@ -55,7 +53,7 @@ func TestRun4(t *testing.T) { vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), - BlockNumber: 1, + BlockNumber: big.NewInt(1), PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), Time: 1, -- cgit v1.2.3 From 39263b674c1a8a13a1c29349a48b3cdc4c5948db Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 09:56:10 +0200 Subject: Paranoia --- ethchain/state_transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index b18091691..6837f92f7 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -268,7 +268,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by } */ - Paranoia := true // TODO Create a flag for this + Paranoia := ethutil.Config.Paranoia if Paranoia { var ( trie = context.state.trie -- cgit v1.2.3 From 92693e44599c44e606813d2c3259cc9f6f81a644 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 11:26:45 +0200 Subject: The dragon has been slain. Consensus reached! --- ethchain/state.go | 2 +- ethchain/state_manager.go | 5 +++-- ethchain/state_transition.go | 30 ++++++++++++++---------------- ethchain/vm.go | 29 +++++++++++++++++++++++++++-- 4 files changed, 45 insertions(+), 21 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 51d86fe2a..06a185f59 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -125,7 +125,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { - statelogger.Infof("(+) %x\n", addr) + //statelogger.Infof("(+) %x\n", addr) stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 363aa3da7..b0550607f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -123,8 +123,9 @@ done: break done default: - //statelogger.Infoln(err) - return nil, nil, nil, err + statelogger.Infoln(err) + err = nil + //return nil, nil, nil, err } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 6837f92f7..94c3de3d9 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -253,26 +253,22 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by Value: self.value, }) vm.Verbose = true - ret, _, err = closure.Call(vm, self.data, nil) - deepErr = vm.err != nil - /* - var testAddr = ethutil.FromHex("ec4f34c97e43fbb2816cfd95e388353c7181dab1") - if bytes.Compare(testAddr, context.Address()) == 0 { - trie := context.state.trie - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - v.Decode() - fmt.Printf("%x : %x\n", key, v.Str()) - }) - fmt.Println("\n\n") - } - */ + ret, err, deepErr = Call(vm, closure, self.data) + + return +} + +func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr bool) { + ret, _, err = closure.Call(vm, data, nil) + deepErr = vm.err != nil Paranoia := ethutil.Config.Paranoia if Paranoia { var ( - trie = context.state.trie - trie2 = ethutil.NewTrie(ethutil.Config.Db, "") + context = closure.object + trie = context.state.trie + trie2 = ethutil.NewTrie(ethutil.Config.Db, "") ) trie.NewIterator().Each(func(key string, v *ethutil.Value) { @@ -282,6 +278,8 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by a := ethutil.NewValue(trie2.Root).Bytes() b := ethutil.NewValue(context.state.trie.Root).Bytes() if bytes.Compare(a, b) != 0 { + // TODO FIXME ASAP + context.state.trie = trie2 /* statelogger.Debugf("(o): %x\n", trie.Root) trie.NewIterator().Each(func(key string, v *ethutil.Value) { @@ -296,7 +294,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by }) */ - return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false + //return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false } } diff --git a/ethchain/vm.go b/ethchain/vm.go index 82591e274..3851d0d70 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -346,6 +346,29 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } + + case SLT: + require(2) + x, y := stack.Popn() + vm.Printf(" %v < %v", y, x) + // x < y + if y.Cmp(x) < 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case SGT: + require(2) + x, y := stack.Popn() + vm.Printf(" %v > %v", y, x) + + // x > y + if y.Cmp(x) > 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case EQ: require(2) x, y := stack.Popn() @@ -660,7 +683,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Create a new callable closure closure := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) - ret, _, err := closure.Call(vm, args, hook) + //ret, _, err := closure.Call(vm, args, hook) + ret, err, _ := Call(vm, closure, args) if err != nil { stack.Push(ethutil.BigFalse) @@ -699,7 +723,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), nil default: - vmlogger.Debugf("Invalid opcode %x\n", op) + vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) + fmt.Println(Code(closure.Script)) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } -- cgit v1.2.3 From e798294a4b2049dc59df6ad4a3bc67c00916cb9f Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 1 Jul 2014 15:25:57 +0200 Subject: Update min GasLimit --- ethchain/block.go | 2 +- ethchain/dagger.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index fee4a2d59..1be8282fa 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -166,7 +166,7 @@ func (block *Block) CalcGasLimit(parent *Block) *big.Int { result := new(big.Int).Add(previous, curInt) result.Div(result, big.NewInt(1024)) - min := ethutil.BigPow(10, 4) + min := big.NewInt(125000) return ethutil.BigMax(min, result) /* diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 08c4826db..b586657b9 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -31,6 +31,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: + powlogger.Infoln("Breaking from mining") return nil default: i++ -- cgit v1.2.3 From d0959063d5f67dccc214f43344d88dce25ca167f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 15:28:12 +0200 Subject: Up --- ethchain/block_chain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6e4c72b27..ef56d674c 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -271,7 +271,7 @@ func AddTestNetFunds(block *Block) { for _, addr := range []string{ "51ba59315b3a95761d0863b05ccc7a7f54703d99", "e4157b34ea9615cfbde6b4fda419828124b70c78", - "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", + "b9c015918bdaba24b4ff057a92a3873d6eb201be", "6c386a4b26f73c802f34673f7248bb118f97424a", "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", "2ef47100e0787b915105fd5e3f4ff6752079d5cb", -- cgit v1.2.3 From ff5703fd9b089de67811af61de05637c62dc7a2c Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 1 Jul 2014 15:09:43 +0100 Subject: ethutil -> ethtrie.NewTrie --- ethchain/state_object.go | 2 +- ethchain/state_transition.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 7c9430af2..35928c899 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -51,7 +51,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { func NewStateObject(addr []byte) *StateObject { object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} - object.state = NewState(ethutil.NewTrie(ethutil.Config.Db, "")) + object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) return object } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 94c3de3d9..c382bcd60 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "fmt" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -268,7 +269,7 @@ func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr var ( context = closure.object trie = context.state.trie - trie2 = ethutil.NewTrie(ethutil.Config.Db, "") + trie2 = ethtrie.NewTrie(ethutil.Config.Db, "") ) trie.NewIterator().Each(func(key string, v *ethutil.Value) { -- cgit v1.2.3 From 00d3935aac3f5d50bae56650c45e49a8b8705099 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 23:59:18 +0200 Subject: Removed old method --- ethchain/closure.go | 6 ++--- ethchain/state.go | 6 ++++- ethchain/state_object.go | 67 ++++++++++++++++++++---------------------------- 3 files changed, 36 insertions(+), 43 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 32b297e90..966e8254a 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -10,7 +10,7 @@ import ( type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte - GetMem(*big.Int) *ethutil.Value + GetStorage(*big.Int) *ethutil.Value SetStorage(*big.Int, *ethutil.Value) N() *big.Int } @@ -43,8 +43,8 @@ func NewClosure(caller ClosureRef, object *StateObject, script []byte, state *St } // Retuns the x element in data slice -func (c *Closure) GetMem(x *big.Int) *ethutil.Value { - m := c.object.GetMem(x) +func (c *Closure) GetStorage(x *big.Int) *ethutil.Value { + m := c.object.GetStorage(x) if m == nil { return ethutil.EmptyValue() } diff --git a/ethchain/state.go b/ethchain/state.go index 8b6c2efb8..3d05ff582 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -66,7 +66,11 @@ func (self *State) Empty() { func (self *State) Update() { for _, stateObject := range self.stateObjects { - self.UpdateStateObject(stateObject) + if stateObject.remove { + self.trie.Delete(string(stateObject.Address())) + } else { + self.UpdateStateObject(stateObject) + } } } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 35928c899..cc9a801f9 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -31,6 +31,11 @@ type StateObject struct { // left if this object is the coinbase. Gas is directly // purchased of the coinbase. gasPool *big.Int + + // Mark for deletion + // When an object is marked for deletion it will be delete from the trie + // during the "update" phase of the state transition + remove bool } // Converts an transaction in to a state object @@ -77,15 +82,11 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { return object } -func (c *StateObject) State() *State { - return c.state -} - -func (c *StateObject) N() *big.Int { - return big.NewInt(int64(c.Nonce)) +func (self *StateObject) MarkForDeletion() { + self.remove = true } -func (c *StateObject) Addr(addr []byte) *ethutil.Value { +func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) } @@ -108,12 +109,7 @@ func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value { nb := ethutil.BigToBytes(num, 256) - return c.Addr(nb) -} - -/* DEPRECATED */ -func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { - return c.GetStorage(num) + return c.GetAddr(nb) } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { @@ -124,14 +120,6 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) } -// Return the gas back to the origin. Used by the Virtual machine or Closures -func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { - /* - remainder := new(big.Int).Mul(gas, price) - c.AddAmount(remainder) - */ -} - func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) @@ -148,6 +136,12 @@ func (c *StateObject) SetAmount(amount *big.Int) { c.Amount = amount } +// +// Gas setters and getters +// + +// Return the gas back to the origin. Used by the Virtual machine or Closures +func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) {} func (c *StateObject) ConvertGas(gas, price *big.Int) error { total := new(big.Int).Mul(gas, price) if total.Cmp(c.Amount) > 0 { @@ -206,26 +200,17 @@ func (self *StateObject) Set(stateObject *StateObject) { self = stateObject } -/* -func (self *StateObject) Copy() *StateObject { - stCopy := &StateObject{} - stCopy.address = make([]byte, len(self.address)) - copy(stCopy.address, self.address) - stCopy.Amount = new(big.Int).Set(self.Amount) - stCopy.ScriptHash = make([]byte, len(self.ScriptHash)) - copy(stCopy.ScriptHash, self.ScriptHash) - stCopy.Nonce = self.Nonce - if self.state != nil { - stCopy.state = self.state.Copy() - } - stCopy.script = make([]byte, len(self.script)) - copy(stCopy.script, self.script) - stCopy.initScript = make([]byte, len(self.initScript)) - copy(stCopy.initScript, self.initScript) +// +// Attribute accessors +// + +func (c *StateObject) State() *State { + return c.state +} - return stCopy +func (c *StateObject) N() *big.Int { + return big.NewInt(int64(c.Nonce)) } -*/ // Returns the address of the contract/account func (c *StateObject) Address() []byte { @@ -242,6 +227,10 @@ func (c *StateObject) Init() Code { return c.initScript } +// +// Encoding +// + // State object encoding methods func (c *StateObject) RlpEncode() []byte { var root interface{} -- cgit v1.2.3 From fd1d0bbde7e76b3376a3a932930bc099f223d8ff Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 00:05:48 +0200 Subject: Updated to generic padding function --- ethchain/transaction.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 11f786b36..da3f9bcf2 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -90,10 +90,9 @@ func (tx *Transaction) Signature(key []byte) []byte { func (tx *Transaction) PublicKey() []byte { hash := tx.Hash() - r := make([]byte, 32-len(tx.r)) - s := make([]byte, 32-len(tx.s)) - r = append(r, ethutil.CopyBytes(tx.r)...) - s = append(s, ethutil.CopyBytes(tx.s)...) + // TODO + r := ethutil.LeftPadBytes(tx.r, 32) + s := ethutil.LeftPadBytes(tx.s, 32) sig := append(r, s...) sig = append(sig, tx.v-27) -- cgit v1.2.3 From 1954ef47e67762f0308544e3a17976e4c3927e32 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 00:06:21 +0200 Subject: Suicide is deferred to update --- ethchain/vm.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index c5ccb3420..0b8799a12 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -150,7 +150,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SSTORE: var mult *big.Int y, x := stack.Peekn() - val := closure.GetMem(x) + val := closure.GetStorage(x) if val.IsEmpty() && len(y.Bytes()) > 0 { mult = ethutil.Big2 } else if !val.IsEmpty() && len(y.Bytes()) == 0 { @@ -567,7 +567,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SLOAD: require(1) loc := stack.Pop() - val := closure.GetMem(loc) + val := closure.GetStorage(loc) stack.Push(val.BigInt()) @@ -713,10 +713,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - trie := closure.object.state.trie - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - trie.Delete(key) - }) + closure.object.MarkForDeletion() + + /* + trie := closure.object.state.trie + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + trie.Delete(key) + }) + */ fallthrough case STOP: // Stop the closure -- cgit v1.2.3 From d15952c867f5c31fa68600754bd17c76a992a70e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 01:04:21 +0200 Subject: Moved debug hook to Vm directly --- ethchain/closure.go | 6 ++---- ethchain/state_transition.go | 2 +- ethchain/vm.go | 12 ++++++++---- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 966e8254a..cc769de30 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -74,12 +74,10 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool - -func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, error) { +func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) { c.Args = args - ret, err := vm.RunClosure(c, hook) + ret, err := vm.RunClosure(c) return ret, c.UsedGas, err } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index c382bcd60..9e7ef3efd 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -261,7 +261,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by } func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr bool) { - ret, _, err = closure.Call(vm, data, nil) + ret, _, err = closure.Call(vm, data) deepErr = vm.err != nil Paranoia := ethutil.Config.Paranoia diff --git a/ethchain/vm.go b/ethchain/vm.go index 0b8799a12..7acca9b36 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -52,8 +52,12 @@ type Vm struct { logStr string err error + + Hook DebugHook } +type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool + type RuntimeVars struct { Origin []byte Block *Block @@ -91,7 +95,7 @@ var Pow256 = ethutil.BigPow(2, 256) var isRequireError = false -func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err error) { +func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Recover from any require exception defer func() { if r := recover(); r != nil { @@ -642,7 +646,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Call the closure and set the return value as // main script. var err error - c.Script, gas, err = c.Call(vm, nil, hook) + c.Script, gas, err = c.Call(vm, nil) if err != nil { stack.Push(ethutil.BigFalse) @@ -738,8 +742,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.Endl() - if hook != nil { - if !hook(prevStep, op, mem, stack, closure.Object()) { + if vm.Hook != nil { + if !vm.Hook(prevStep, op, mem, stack, closure.Object()) { return nil, nil } } -- cgit v1.2.3 From 315d65280bab295765cdaeb12cfde753c5387ebc Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 11:30:14 +0200 Subject: Removed comment --- ethchain/vm.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 7acca9b36..cd7516db7 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -688,7 +688,6 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Create a new callable closure closure := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) - //ret, _, err := closure.Call(vm, args, hook) ret, err, _ := Call(vm, closure, args) if err != nil { stack.Push(ethutil.BigFalse) -- cgit v1.2.3 From e4d2d00d414704559b38f80a918030613ea1cdf4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 13:08:32 +0200 Subject: Added support for breakpoints on specific instructions --- ethchain/vm.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index cd7516db7..909b375ae 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -53,7 +53,10 @@ type Vm struct { err error - Hook DebugHook + // Debugging + Hook DebugHook + BreakPoints []int64 + Stepping bool } type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool @@ -742,9 +745,16 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vm.Endl() if vm.Hook != nil { - if !vm.Hook(prevStep, op, mem, stack, closure.Object()) { - return nil, nil + for _, instrNo := range vm.BreakPoints { + if pc.Cmp(big.NewInt(instrNo)) == 0 || vm.Stepping { + vm.Stepping = true + + if !vm.Hook(prevStep, op, mem, stack, closure.Object()) { + return nil, nil + } + } } } + } } -- cgit v1.2.3 From 40e3d2ab55f32c2458981533f5511e2f24a65c11 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 17:47:09 +0200 Subject: Changed CREATE --- ethchain/vm.go | 59 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 24 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 909b375ae..fa839b260 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -617,48 +617,59 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case CREATE: require(3) - value := stack.Pop() - size, offset := stack.Popn() + var ( + err error + value = stack.Pop() + size, offset = stack.Popn() - // Snapshot the current stack so we are able to - // revert back to it later. - snapshot := vm.state.Copy() + // Snapshot the current stack so we are able to + // revert back to it later. + snapshot = vm.state.Copy() + ) // Generate a new address addr := ethcrypto.CreateAddress(closure.caller.Address(), closure.caller.N()) + for i := int64(0); vm.state.GetStateObject(addr) != nil; i++ { + t := new(big.Int).Set(closure.caller.N()) + addr = ethcrypto.CreateAddress(closure.caller.Address(), t.Add(t, big.NewInt(i))) + } vm.Printf(" (*) %x", addr).Endl() // Create a new contract contract := vm.state.NewStateObject(addr) - contract.Amount = value - - // Set the init script - contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() - // Transfer all remaining gas to the new - // contract so it may run the init script - gas := new(big.Int).Set(closure.Gas) - - // Create the closure - c := NewClosure(closure.caller, - closure.Object(), - contract.initScript, - vm.state, - gas, - closure.Price) - // Call the closure and set the return value as - // main script. - var err error - c.Script, gas, err = c.Call(vm, nil) + if contract.Amount.Cmp(value) >= 0 { + closure.object.SubAmount(value) + contract.AddAmount(value) + + // Set the init script + contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() + // Transfer all remaining gas to the new + // contract so it may run the init script + gas := new(big.Int).Set(closure.Gas) + closure.UseGas(closure.Gas) + + // Create the closure + c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price) + // Call the closure and set the return value as + // main script. + c.Script, err, _ = Call(vm, c, nil) + } else { + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + } if err != nil { stack.Push(ethutil.BigFalse) // Revert the state as it was before. vm.state.Set(snapshot) + + vm.Printf("CREATE err %v", err) } else { stack.Push(ethutil.BigD(addr)) + vm.Printf("CREATE success") } + vm.Endl() case CALL: require(7) -- cgit v1.2.3 From 2f9bc2ab754ff85235ebb0b0b41b9b36ef30253a Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 17:47:33 +0200 Subject: Removed old code --- ethchain/state.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 3d05ff582..7ddf7916f 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -93,10 +93,6 @@ func (self *State) ResetStateObject(stateObject *StateObject) { func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() - if self.stateObjects[string(addr)] == nil { - self.stateObjects[string(addr)] = stateObject - } - ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) self.trie.Update(string(addr), string(stateObject.RlpEncode())) @@ -131,7 +127,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { - //statelogger.Infof("(+) %x\n", addr) + statelogger.Infof("(+) %x\n", addr) stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject -- cgit v1.2.3 From 35ae9e3aa89dc0e3be1cabed313996a7d49f6628 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 2 Jul 2014 17:48:10 +0200 Subject: Paranoia check --- ethchain/state_manager.go | 9 +++++++++ ethchain/state_transition.go | 16 ++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index dea82cae3..c42238e5c 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "math/big" @@ -204,7 +205,15 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return err } + if ethutil.Config.Paranoia { + valid, _ := ethtrie.ParanoiaCheck(state.trie) + if !valid { + err = fmt.Errorf("PARANOIA: World state trie comparison failed") + } + } + if !block.State().Cmp(state) { + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 9e7ef3efd..898344c2e 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -1,7 +1,6 @@ package ethchain import ( - "bytes" "fmt" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -264,23 +263,16 @@ func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr ret, _, err = closure.Call(vm, data) deepErr = vm.err != nil - Paranoia := ethutil.Config.Paranoia - if Paranoia { + if ethutil.Config.Paranoia { var ( context = closure.object trie = context.state.trie - trie2 = ethtrie.NewTrie(ethutil.Config.Db, "") ) - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - trie2.Update(key, v.Str()) - }) - - a := ethutil.NewValue(trie2.Root).Bytes() - b := ethutil.NewValue(context.state.trie.Root).Bytes() - if bytes.Compare(a, b) != 0 { + valid, t2 := ethtrie.ParanoiaCheck(trie) + if !valid { // TODO FIXME ASAP - context.state.trie = trie2 + context.state.trie = t2 /* statelogger.Debugf("(o): %x\n", trie.Root) trie.NewIterator().Each(func(key string, v *ethutil.Value) { -- cgit v1.2.3 From 5b8dde96026b123147733bb5cdf88b7774725015 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 3 Jul 2014 10:04:38 +0200 Subject: Fixed CREATE op. Fixes #87 --- ethchain/vm.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index fa839b260..35443a6ba 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -35,7 +35,6 @@ func CalculateTxGas(initSize *big.Int) *big.Int { } type Vm struct { - txPool *TxPool // Stack for processing contracts stack *Stack // non-persistent key/value memory storage @@ -628,11 +627,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { ) // Generate a new address - addr := ethcrypto.CreateAddress(closure.caller.Address(), closure.caller.N()) - for i := int64(0); vm.state.GetStateObject(addr) != nil; i++ { - t := new(big.Int).Set(closure.caller.N()) - addr = ethcrypto.CreateAddress(closure.caller.Address(), t.Add(t, big.NewInt(i))) + addr := ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce) + for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ { + ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce+i) } + closure.object.Nonce++ vm.Printf(" (*) %x", addr).Endl() @@ -643,7 +642,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { contract.AddAmount(value) // Set the init script - contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() + contract.initScript = mem.Get(offset.Int64(), size.Int64()) // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) @@ -653,7 +652,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price) // Call the closure and set the return value as // main script. - c.Script, err, _ = Call(vm, c, nil) + contract.script, err, _ = Call(vm, c, nil) } else { err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) } -- cgit v1.2.3 From 5d6713920625b82df2b55728b2cbb9f7f3df2025 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 3 Jul 2014 10:05:02 +0200 Subject: Fix --- ethchain/state_manager.go | 2 +- ethchain/state_transition.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c42238e5c..027c6a085 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -208,7 +208,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { if ethutil.Config.Paranoia { valid, _ := ethtrie.ParanoiaCheck(state.trie) if !valid { - err = fmt.Errorf("PARANOIA: World state trie comparison failed") + err = fmt.Errorf("PARANOIA: World state trie corruption") } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 898344c2e..31196d2d7 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -53,6 +53,7 @@ func (self *StateTransition) Sender() *StateObject { } self.sen = self.state.GetAccount(self.tx.Sender()) + return self.sen } func (self *StateTransition) Receiver() *StateObject { -- cgit v1.2.3 From 8baa0f84e70aafa3882ec477d3b3d401d462958b Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 3 Jul 2014 16:07:21 +0200 Subject: Fixed reverting error --- ethchain/state.go | 8 +++++--- ethchain/state_object.go | 5 ++--- ethchain/state_transition.go | 41 ++++++++++++++++------------------------- ethchain/vm.go | 13 ++++++------- 4 files changed, 29 insertions(+), 38 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 7ddf7916f..20af94fe8 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -157,9 +157,11 @@ func (self *State) Copy() *State { } func (self *State) Set(state *State) { - //s.trie = snapshot.trie - //s.stateObjects = snapshot.stateObjects - self = state + if state == nil { + panic("Tried setting 'state' to nil through 'Set'") + } + + *self = *state } func (s *State) Put(key, object []byte) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index cc9a801f9..b9d994321 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -191,13 +191,12 @@ func (self *StateObject) Copy() *StateObject { } stateObject.script = ethutil.CopyBytes(self.script) stateObject.initScript = ethutil.CopyBytes(self.initScript) - //stateObject.gasPool.Set(self.gasPool) - return self + return stateObject } func (self *StateObject) Set(stateObject *StateObject) { - self = stateObject + *self = *stateObject } // diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 31196d2d7..16e1f124b 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -192,6 +192,8 @@ func (self *StateTransition) TransitionState() (err error) { return } + //snapshot := self.state.Copy() + // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { // Evaluate the initialization script @@ -199,22 +201,25 @@ func (self *StateTransition) TransitionState() (err error) { // script section for the state object. self.data = nil - code, err, deepErr := self.Eval(receiver.Init(), receiver) - if err != nil || deepErr { + statelogger.Debugln("~> init") + code, err := self.Eval(receiver.Init(), receiver) + if err != nil { + //self.state.Set(snapshot) self.state.ResetStateObject(receiver) - return fmt.Errorf("Error during init script run %v (deepErr = %v)", err, deepErr) + return fmt.Errorf("Error during init execution %v", err) } receiver.script = code } else { if len(receiver.Script()) > 0 { - var deepErr bool - _, err, deepErr = self.Eval(receiver.Script(), receiver) + statelogger.Debugln("~> code") + _, err = self.Eval(receiver.Script(), receiver) if err != nil { + //self.state.Set(snapshot) self.state.ResetStateObject(receiver) - return fmt.Errorf("Error during code execution %v (deepErr = %v)", err, deepErr) + return fmt.Errorf("Error during code execution %v", err) } } } @@ -235,7 +240,7 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return nil } -func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error, deepErr bool) { +func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { var ( block = self.block initiator = self.Sender() @@ -255,14 +260,13 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by }) vm.Verbose = true - ret, err, deepErr = Call(vm, closure, self.data) + ret, err = Call(vm, closure, self.data) return } -func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr bool) { +func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) { ret, _, err = closure.Call(vm, data) - deepErr = vm.err != nil if ethutil.Config.Paranoia { var ( @@ -274,21 +278,8 @@ func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr if !valid { // TODO FIXME ASAP context.state.trie = t2 - /* - statelogger.Debugf("(o): %x\n", trie.Root) - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - v.Decode() - statelogger.Debugf("%x : %x\n", key, v.Str()) - }) - - statelogger.Debugf("(c): %x\n", trie2.Root) - trie2.NewIterator().Each(func(key string, v *ethutil.Value) { - v.Decode() - statelogger.Debugf("%x : %x\n", key, v.Str()) - }) - */ - - //return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false + + statelogger.Debugln("Warn: PARANOIA: Different state object roots during copy") } } diff --git a/ethchain/vm.go b/ethchain/vm.go index 35443a6ba..97379f8ea 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -82,7 +82,7 @@ func (self *Vm) Printf(format string, v ...interface{}) *Vm { func (self *Vm) Endl() *Vm { if self.Verbose { - vmlogger.Infoln(self.logStr) + vmlogger.Debugln(self.logStr) self.logStr = "" } @@ -652,7 +652,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price) // Call the closure and set the return value as // main script. - contract.script, err, _ = Call(vm, c, nil) + contract.script, err = Call(vm, c, nil) } else { err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) } @@ -690,25 +690,24 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(ethutil.BigFalse) } else { - snapshot := vm.state.Copy() + //snapshot := vm.state.Copy() stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) closure.object.SubAmount(value) - // Add the value to the state object stateObject.AddAmount(value) // Create a new callable closure closure := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) - ret, err, _ := Call(vm, closure, args) + ret, err := Call(vm, closure, args) if err != nil { stack.Push(ethutil.BigFalse) vmlogger.Debugf("Closure execution failed. %v\n", err) - vm.err = err - vm.state.Set(snapshot) + //vm.state.Set(snapshot) + vm.state.ResetStateObject(stateObject) } else { stack.Push(ethutil.BigTrue) -- cgit v1.2.3 From 198e5eeab9e2a7c359c12cdd5c8782dc56ae54ec Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 3 Jul 2014 15:08:06 +0100 Subject: EthManager interface extended with ClientIdentity() ethwire.ClientIdentity --- ethchain/state_manager.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index dea82cae3..babfbd061 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -41,6 +41,7 @@ type EthManager interface { IsListening() bool Peers() *list.List KeyManager() *ethcrypto.KeyManager + ClientIdentity() ethwire.ClientIdentity } type StateManager struct { -- cgit v1.2.3 From 7c41e413e4c596ac0010305be0f851353c065df6 Mon Sep 17 00:00:00 2001 From: Joey Zhou Date: Thu, 3 Jul 2014 11:31:47 -0700 Subject: typo, duplications --- ethchain/state_object.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index cc9a801f9..d974daea5 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -249,7 +249,6 @@ func (c *StateObject) RlpDecode(data []byte) { c.Nonce = decoder.Get(0).Uint() c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) - c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.ScriptHash = decoder.Get(3).Bytes() -- cgit v1.2.3 From cb7ebdf821adb4b022adcaea0973c8c7da2e2923 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 4 Jul 2014 00:12:21 +0200 Subject: Decreased timeout --- ethchain/vm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 97379f8ea..3a7aa8c58 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -698,9 +698,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stateObject.AddAmount(value) // Create a new callable closure - closure := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) + c := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) - ret, err := Call(vm, closure, args) + ret, err := Call(vm, c, args) if err != nil { stack.Push(ethutil.BigFalse) -- cgit v1.2.3 From 90eb4f1939f7b0389d5784b889cc0e5d2b3451f7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 4 Jul 2014 15:32:10 +0200 Subject: Debug output, minor fixes and tweaks * Script compile length fix * Transition fix --- ethchain/state_manager.go | 15 ++++++++++++++- ethchain/state_transition.go | 11 +++++------ ethchain/vm.go | 7 ++++--- 3 files changed, 23 insertions(+), 10 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index cec424583..f3fd92913 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -181,11 +181,24 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { if err != nil { if len(receipts) == len(block.Receipts()) { for i, receipt := range block.Receipts() { - statelogger.Debugf("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) + statelogger.Infof("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) } } else { statelogger.Warnln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) } + } else { + /* + for i, receipt := range receipts { + gu := new(big.Int) + if i != 0 { + gu.Sub(receipt.CumulativeGasUsed, receipts[i-1].CumulativeGasUsed) + } else { + gu.Set(receipt.CumulativeGasUsed) + } + + statelogger.Infof("[r] %v ~ %x (%x)\n", gu, receipt.PostState[0:4], receipt.Tx.Hash()) + } + */ } }() diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 16e1f124b..6ea9a837d 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -201,8 +201,7 @@ func (self *StateTransition) TransitionState() (err error) { // script section for the state object. self.data = nil - statelogger.Debugln("~> init") - code, err := self.Eval(receiver.Init(), receiver) + code, err := self.Eval(receiver.Init(), receiver, "init") if err != nil { //self.state.Set(snapshot) self.state.ResetStateObject(receiver) @@ -213,8 +212,7 @@ func (self *StateTransition) TransitionState() (err error) { receiver.script = code } else { if len(receiver.Script()) > 0 { - statelogger.Debugln("~> code") - _, err = self.Eval(receiver.Script(), receiver) + _, err = self.Eval(receiver.Script(), receiver, "code") if err != nil { //self.state.Set(snapshot) self.state.ResetStateObject(receiver) @@ -240,7 +238,7 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return nil } -func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { +func (self *StateTransition) Eval(script []byte, context *StateObject, typ string) (ret []byte, err error) { var ( block = self.block initiator = self.Sender() @@ -259,6 +257,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by Value: self.value, }) vm.Verbose = true + vm.Fn = typ ret, err = Call(vm, closure, self.data) @@ -279,7 +278,7 @@ func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) { // TODO FIXME ASAP context.state.trie = t2 - statelogger.Debugln("Warn: PARANOIA: Different state object roots during copy") + statelogger.Infoln("Warn: PARANOIA: Different state object roots during copy") } } diff --git a/ethchain/vm.go b/ethchain/vm.go index 3a7aa8c58..cfedadb08 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -56,6 +56,7 @@ type Vm struct { Hook DebugHook BreakPoints []int64 Stepping bool + Fn string } type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool @@ -107,7 +108,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } }() - vmlogger.Debugf("(~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.object.Address(), closure.Gas, closure.Args) var ( op OpCode @@ -577,7 +578,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(val.BigInt()) - vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val.Bytes()) + vm.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case SSTORE: require(2) val, loc := stack.Popn() @@ -586,7 +587,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) - vm.Printf(" {0x%x} 0x%x", loc, val) + vm.Printf(" {0x%x : 0x%x}", loc, val) case JUMP: require(1) pc = stack.Pop() -- cgit v1.2.3 From 584d1c61ec93df3417f2ce8ece041b81a5ec63a6 Mon Sep 17 00:00:00 2001 From: zelig Date: Fri, 4 Jul 2014 19:38:44 +0100 Subject: use ethreact.Event and ethreact.ReactorEngine --- ethchain/dagger.go | 5 +++-- ethchain/state_manager.go | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 4dda21ff5..adf1c2f05 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -3,6 +3,7 @@ package ethchain import ( "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" "hash" @@ -14,7 +15,7 @@ import ( var powlogger = ethlog.NewLogger("POW") type PoW interface { - Search(block *Block, reactChan chan ethutil.React) []byte + Search(block *Block, reactChan chan ethreact.Event) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -22,7 +23,7 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { +func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index cec424583..962f95b29 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -36,7 +37,7 @@ type EthManager interface { BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) - Reactor() *ethutil.ReactorEngine + Reactor() *ethreact.ReactorEngine PeerCount() int IsMining() bool IsListening() bool -- cgit v1.2.3 From b232acd04ef957fb65e1c49b330165535da7e871 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 5 Jul 2014 13:24:49 +0200 Subject: Debugging mode for vm --- ethchain/vm.go | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index cfedadb08..769333649 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -24,14 +24,10 @@ var ( GasTx = big.NewInt(500) ) -func CalculateTxGas(initSize *big.Int) *big.Int { - totalGas := new(big.Int) - - txTotalBytes := new(big.Int).Set(initSize) - txTotalBytes.Div(txTotalBytes, ethutil.Big32) - totalGas.Add(totalGas, new(big.Int).Mul(txTotalBytes, GasSStore)) - - return totalGas +type Debugger interface { + BreakHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool + StepHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool + BreakPoints() []int64 } type Vm struct { @@ -53,14 +49,13 @@ type Vm struct { err error // Debugging - Hook DebugHook + Dbg Debugger + BreakPoints []int64 Stepping bool Fn string } -type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool - type RuntimeVars struct { Origin []byte Block *Block @@ -754,12 +749,14 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vm.Endl() - if vm.Hook != nil { - for _, instrNo := range vm.BreakPoints { - if pc.Cmp(big.NewInt(instrNo)) == 0 || vm.Stepping { - vm.Stepping = true - - if !vm.Hook(prevStep, op, mem, stack, closure.Object()) { + if vm.Dbg != nil { + for _, instrNo := range vm.Dbg.BreakPoints() { + if pc.Cmp(big.NewInt(instrNo)) == 0 { + if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) { + return nil, nil + } + } else if vm.Stepping { + if !vm.Dbg.StepHook(prevStep, op, mem, stack, closure.Object()) { return nil, nil } } -- cgit v1.2.3 From d40cba3042564f3471aa20a5cf477cafcacc2189 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 10:53:20 +0200 Subject: changed state reset --- ethchain/state.go | 4 +++- ethchain/state_transition.go | 14 ++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 20af94fe8..5d023df7b 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -161,7 +161,9 @@ func (self *State) Set(state *State) { panic("Tried setting 'state' to nil through 'Set'") } - *self = *state + self.trie = state.trie + self.stateObjects = state.stateObjects + //*self = *state } func (s *State) Put(key, object []byte) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 6ea9a837d..a92aa4a33 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -164,8 +164,6 @@ func (self *StateTransition) TransitionState() (err error) { // Increment the nonce for the next transaction sender.Nonce += 1 - receiver = self.Receiver() - // Transaction gas if err = self.UseGas(GasTx); err != nil { return @@ -178,6 +176,10 @@ func (self *StateTransition) TransitionState() (err error) { return } + snapshot := self.state.Copy() + + receiver = self.Receiver() + // If the receiver is nil it's a contract (\0*32). if receiver == nil { // Create a new state object for the contract @@ -192,8 +194,6 @@ func (self *StateTransition) TransitionState() (err error) { return } - //snapshot := self.state.Copy() - // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { // Evaluate the initialization script @@ -203,8 +203,7 @@ func (self *StateTransition) TransitionState() (err error) { code, err := self.Eval(receiver.Init(), receiver, "init") if err != nil { - //self.state.Set(snapshot) - self.state.ResetStateObject(receiver) + self.state.Set(snapshot) return fmt.Errorf("Error during init execution %v", err) } @@ -214,8 +213,7 @@ func (self *StateTransition) TransitionState() (err error) { if len(receiver.Script()) > 0 { _, err = self.Eval(receiver.Script(), receiver, "code") if err != nil { - //self.state.Set(snapshot) - self.state.ResetStateObject(receiver) + self.state.Set(snapshot) return fmt.Errorf("Error during code execution %v", err) } -- cgit v1.2.3 From 6fe9b4ab5e839be96eb1c4a619bc14fab622d8d1 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Mon, 7 Jul 2014 10:59:16 +0200 Subject: Revert "ethreact - Feature/ethutil refactor" --- ethchain/dagger.go | 5 ++--- ethchain/state_manager.go | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index adf1c2f05..4dda21ff5 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -3,7 +3,6 @@ package ethchain import ( "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" "hash" @@ -15,7 +14,7 @@ import ( var powlogger = ethlog.NewLogger("POW") type PoW interface { - Search(block *Block, reactChan chan ethreact.Event) []byte + Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -23,7 +22,7 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { +func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 52a73beb8..f3fd92913 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -37,7 +36,7 @@ type EthManager interface { BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) - Reactor() *ethreact.ReactorEngine + Reactor() *ethutil.ReactorEngine PeerCount() int IsMining() bool IsListening() bool -- cgit v1.2.3 From 68fba4b781652c0181ca58cf176e96a303acffe4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 11:17:48 +0200 Subject: Fixed state reset on err --- ethchain/state_transition.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index a92aa4a33..10a795cb8 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -176,8 +176,6 @@ func (self *StateTransition) TransitionState() (err error) { return } - snapshot := self.state.Copy() - receiver = self.Receiver() // If the receiver is nil it's a contract (\0*32). @@ -194,6 +192,8 @@ func (self *StateTransition) TransitionState() (err error) { return } + snapshot := self.state.Copy() + // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { // Evaluate the initialization script -- cgit v1.2.3 From 96ac061e68ffd79f1aa22e12113b0cf58e418c5a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:58:28 +0200 Subject: Log change --- ethchain/block_chain.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index df735d679..f72a77706 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -294,7 +294,6 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() - chainlogger.Infof("Last known block height #%d\n", bc.LastBlockNumber) } else { AddTestNetFunds(bc.genesisBlock) @@ -309,7 +308,7 @@ func (bc *BlockChain) setLastBlock() { // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - chainlogger.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) + chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { -- cgit v1.2.3 From 42bb3d8aaeb4753ac491c31c746b065dbcbb3781 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:58:54 +0200 Subject: Removed old if statement. No longer needed --- ethchain/closure.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index cc769de30..1f7f8d703 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -84,13 +84,7 @@ func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) { func (c *Closure) Return(ret []byte) []byte { // Return the remaining gas to the caller - // If no caller is present return it to - // the origin (i.e. contract or tx) - if c.caller != nil { - c.caller.ReturnGas(c.Gas, c.Price, c.State) - } else { - c.object.ReturnGas(c.Gas, c.Price, c.State) - } + c.caller.ReturnGas(c.Gas, c.Price, c.State) return ret } -- cgit v1.2.3 From b01cb2406f94745277fe05dfa74c6e5d42af1c6a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:59:09 +0200 Subject: Fixed state reset case --- ethchain/state.go | 16 +++++++++++++++- ethchain/state_object.go | 1 + ethchain/state_transition.go | 16 +++++++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 5d023df7b..6abf21c39 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -67,11 +67,19 @@ func (self *State) Empty() { func (self *State) Update() { for _, stateObject := range self.stateObjects { if stateObject.remove { - self.trie.Delete(string(stateObject.Address())) + self.DeleteStateObject(stateObject) } else { + println(ethutil.Bytes2Hex(stateObject.Address())) self.UpdateStateObject(stateObject) } } + + // FIXME trie delete is broken + valid, t2 := ethtrie.ParanoiaCheck(self.trie) + if !valid { + self.trie = t2 + } + } // Purges the current trie. @@ -100,6 +108,12 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { self.manifest.AddObjectChange(stateObject) } +func (self *State) DeleteStateObject(stateObject *StateObject) { + self.trie.Delete(string(stateObject.Address())) + + delete(self.stateObjects, string(stateObject.Address())) +} + func (self *State) GetStateObject(addr []byte) *StateObject { stateObject := self.stateObjects[string(addr)] if stateObject != nil { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5a43de35c..2c7f36e65 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -84,6 +84,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { func (self *StateObject) MarkForDeletion() { self.remove = true + statelogger.Infof("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) } func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 10a795cb8..314d858f2 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -176,15 +176,23 @@ func (self *StateTransition) TransitionState() (err error) { return } - receiver = self.Receiver() + /* FIXME + * If tx goes TO "0", goes OOG during init, reverse changes, but initial endowment should happen. The ether is lost forever + */ + var snapshot *State // If the receiver is nil it's a contract (\0*32). - if receiver == nil { + if tx.CreatesContract() { + snapshot = self.state.Copy() + // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) + self.rec = receiver if receiver == nil { return fmt.Errorf("Unable to create contract") } + } else { + receiver = self.Receiver() } // Transfer value from sender to receiver @@ -192,7 +200,9 @@ func (self *StateTransition) TransitionState() (err error) { return } - snapshot := self.state.Copy() + if snapshot == nil { + snapshot = self.state.Copy() + } // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { -- cgit v1.2.3 From 78aad9a19268d02519e3d777061ebc7a877b0a1d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:59:32 +0200 Subject: Getting rid of deprecated methods --- ethchain/vm.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 769333649..71605b069 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -721,18 +721,12 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case SUICIDE: require(1) - receiver := vm.state.GetAccount(stack.Pop().Bytes()) + receiver := vm.state.GetOrNewStateObject(stack.Pop().Bytes()) + receiver.AddAmount(closure.object.Amount) closure.object.MarkForDeletion() - /* - trie := closure.object.state.trie - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - trie.Delete(key) - }) - */ - fallthrough case STOP: // Stop the closure vm.Endl() -- cgit v1.2.3 From 14d13167a723a0fa8ccfcf120131efe96cfc6256 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 7 Jul 2014 13:59:59 +0200 Subject: Remove debug println --- ethchain/state.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 6abf21c39..f5c038226 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -69,7 +69,6 @@ func (self *State) Update() { if stateObject.remove { self.DeleteStateObject(stateObject) } else { - println(ethutil.Bytes2Hex(stateObject.Address())) self.UpdateStateObject(stateObject) } } -- cgit v1.2.3 From 67e5689f874940c99e4742a5c8c2a6a194cb2003 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 12:51:19 +0200 Subject: Fixed BYTE opcode --- ethchain/vm.go | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 71605b069..3b58d6106 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -22,6 +22,9 @@ var ( GasMemory = big.NewInt(1) GasData = big.NewInt(5) GasTx = big.NewInt(500) + + LogTyPretty byte = 0x1 + LogTyDiff byte = 0x2 ) type Debugger interface { @@ -44,6 +47,7 @@ type Vm struct { Verbose bool + logTy byte logStr string err error @@ -69,7 +73,7 @@ type RuntimeVars struct { } func (self *Vm) Printf(format string, v ...interface{}) *Vm { - if self.Verbose { + if self.Verbose && self.logTy == LogTyPretty { self.logStr += fmt.Sprintf(format, v...) } @@ -77,7 +81,7 @@ func (self *Vm) Printf(format string, v ...interface{}) *Vm { } func (self *Vm) Endl() *Vm { - if self.Verbose { + if self.Verbose && self.logTy == LogTyPretty { vmlogger.Debugln(self.logStr) self.logStr = "" } @@ -86,7 +90,7 @@ func (self *Vm) Endl() *Vm { } func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { - return &Vm{vars: vars, state: state, stateManager: stateManager} + return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: LogTyPretty} } var Pow256 = ethutil.BigPow(2, 256) @@ -132,6 +136,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Get the opcode (it must be an opcode!) op = OpCode(val.Uint()) + // XXX Leave this Println intact. Don't change this to the log system. + // Used for creating diffs between implementations + if vm.logTy == LogTyDiff { + b := pc.Bytes() + if len(b) == 0 { + b = []byte{0} + } + + fmt.Printf("%x %x %x %x\n", closure.object.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) + } + gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { if amount.Cmp(ethutil.Big0) >= 0 { @@ -415,7 +430,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(2) val, th := stack.Popn() if th.Cmp(big.NewInt(32)) < 0 { - stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64())) + byt := big.NewInt(int64(val.Bytes()[th.Int64()])) + stack.Push(byt) + + vm.Printf(" => 0x%x", byt.Bytes()) } else { stack.Push(ethutil.BigFalse) } @@ -562,8 +580,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case MSTORE8: require(2) val, mStart := stack.Popn() - base.And(val, new(big.Int).SetInt64(0xff)) - mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) + //base.And(val, new(big.Int).SetInt64(0xff)) + //mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) + mem.store[mStart.Int64()] = byte(val.Int64() & 0xff) vm.Printf(" => 0x%x", val) case SLOAD: -- cgit v1.2.3 From e504088b79f55dd08749f08f434cb85a0033898f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:05:06 +0200 Subject: Consensus and bug fixes * Ensure that each state object has an address that is 20 bytes * Byte logging for vm * changed diff output --- ethchain/state.go | 9 ++++++-- ethchain/state_manager.go | 7 +++++++ ethchain/state_object.go | 53 +++++++++++++++++++++++++++++++++++++---------- ethchain/vm.go | 2 ++ 4 files changed, 58 insertions(+), 13 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index f5c038226..155366376 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -36,7 +37,8 @@ func (s *State) Reset() { continue } - stateObject.state.Reset() + //stateObject.state.Reset() + stateObject.Reset() } s.Empty() @@ -69,6 +71,10 @@ func (self *State) Update() { if stateObject.remove { self.DeleteStateObject(stateObject) } else { + stateObject.Sync() + + fmt.Printf("%x %x\n", stateObject.Address(), stateObject.state.Root()) + self.UpdateStateObject(stateObject) } } @@ -78,7 +84,6 @@ func (self *State) Update() { if !valid { self.trie = t2 } - } // Purges the current trie. diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f3fd92913..a5afa5096 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -66,6 +66,11 @@ type StateManager struct { // Mining state. The mining state is used purely and solely by the mining // operation. miningState *State + + // The last attempted block is mainly used for debugging purposes + // This does not have to be a valid block and will be set during + // 'Process' & canonical validation. + lastAttemptedBlock *Block } func NewStateManager(ethereum EthManager) *StateManager { @@ -165,6 +170,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return ParentError(block.PrevHash) } + sm.lastAttemptedBlock = block + var ( parent = sm.bc.GetBlock(block.PrevHash) state = parent.State() diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 2c7f36e65..ebc050863 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -27,6 +27,8 @@ type StateObject struct { script Code initScript Code + storage map[string]*ethutil.Value + // Total gas pool is the total amount of gas currently // left if this object is the coinbase. Gas is directly // purchased of the coinbase. @@ -38,6 +40,10 @@ type StateObject struct { remove bool } +func (self *StateObject) Reset() { + self.storage = make(map[string]*ethutil.Value) +} + // Converts an transaction in to a state object func MakeContract(tx *Transaction, state *State) *StateObject { // Create contract if there's no recipient @@ -55,14 +61,19 @@ func MakeContract(tx *Transaction, state *State) *StateObject { } func NewStateObject(addr []byte) *StateObject { - object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} + // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. + address := ethutil.LeftPadBytes(addr, 20) + + object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) + object.storage = make(map[string]*ethutil.Value) return object } func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { - contract := &StateObject{address: address, Amount: Amount, Nonce: 0} + contract := NewStateObject(address) + contract.Amount = Amount contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) return contract @@ -95,24 +106,43 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { - addr := ethutil.BigToBytes(num, 256) +func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value { + return self.getStorage(key.Bytes()) +} +func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) { + self.setStorage(key.Bytes(), value) +} - if val.BigInt().Cmp(ethutil.Big0) == 0 { - c.state.trie.Delete(string(addr)) +func (self *StateObject) getStorage(key []byte) *ethutil.Value { + k := ethutil.LeftPadBytes(key, 32) - return + value := self.storage[string(k)] + if value == nil { + value = self.GetAddr(k) + + self.storage[string(k)] = value } - c.SetAddr(addr, val) + return value } -func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value { - nb := ethutil.BigToBytes(num, 256) +func (self *StateObject) setStorage(key []byte, value *ethutil.Value) { + k := ethutil.LeftPadBytes(key, 32) - return c.GetAddr(nb) + self.storage[string(k)] = value } +func (self *StateObject) Sync() { + for key, value := range self.storage { + if value.BigInt().Cmp(ethutil.Big0) == 0 { + self.state.trie.Delete(string(key)) + continue + } + + self.SetAddr([]byte(key), value) + + } +} func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { if int64(len(c.script)-1) < pc.Int64() { return ethutil.NewValue(0) @@ -249,6 +279,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.Nonce = decoder.Get(0).Uint() c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.storage = make(map[string]*ethutil.Value) c.ScriptHash = decoder.Get(3).Bytes() diff --git a/ethchain/vm.go b/ethchain/vm.go index 3b58d6106..56456fdab 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -182,7 +182,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(2) newMemSize = stack.Peek().Uint64() + 32 case MLOAD: + require(1) + newMemSize = stack.Peek().Uint64() + 32 case MSTORE8: require(2) newMemSize = stack.Peek().Uint64() + 1 -- cgit v1.2.3 From b7ff773ecf78f8dd66a6615fc608cabee5a35ce6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:06:46 +0200 Subject: Removed debug log --- ethchain/state.go | 3 --- 1 file changed, 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 155366376..d93ab3e01 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,7 +1,6 @@ package ethchain import ( - "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -73,8 +72,6 @@ func (self *State) Update() { } else { stateObject.Sync() - fmt.Printf("%x %x\n", stateObject.Address(), stateObject.state.Root()) - self.UpdateStateObject(stateObject) } } -- cgit v1.2.3 From 9688ebef523fdd368f7d0596f4529b7e3bc26775 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 15:31:48 +0200 Subject: Return from execution immediately if there's no code --- ethchain/vm.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 56456fdab..c63b5392f 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -107,6 +107,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } }() + // Don't bother with the execution if there's no code. + if len(closure.Script) == 0 { + return closure.Return(nil), nil + } + vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.object.Address(), closure.Gas, closure.Args) var ( -- cgit v1.2.3 From 04561c4ddc363189bdb7377a271d6a734f09eae1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 17:58:16 +0200 Subject: Updated VM & added helper methods to state * VM BALANCE opcode updated to pop 1 item and use that to retrieve the address' balance * GetBalance and GetNonce on state that'll always return something valid --- ethchain/state.go | 151 ++++++++++++++++++++++++++++++------------------------ ethchain/vm.go | 20 ++++++-- 2 files changed, 101 insertions(+), 70 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index d93ab3e01..6d45c9e32 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -26,79 +26,36 @@ func NewState(trie *ethtrie.Trie) *State { return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, stateObject := range s.stateObjects { - if stateObject.state == nil { - continue - } - - //stateObject.state.Reset() - stateObject.Reset() - } - - s.Empty() +// Iterate over each storage address and yield callback +func (s *State) EachStorage(cb ethtrie.EachCallback) { + it := s.trie.NewIterator() + it.Each(cb) } -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, stateObject := range s.stateObjects { - s.UpdateStateObject(stateObject) - - if stateObject.state == nil { - continue - } - - stateObject.state.Sync() +// Retrieve the balance from the given address or 0 if object not found +func (self *State) GetBalance(addr []byte) *big.Int { + stateObject := self.GetStateObject(addr) + if stateObject != nil { + return stateObject.Amount } - s.trie.Sync() - - s.Empty() -} - -func (self *State) Empty() { - self.stateObjects = make(map[string]*StateObject) + return ethutil.Big0 } -func (self *State) Update() { - for _, stateObject := range self.stateObjects { - if stateObject.remove { - self.DeleteStateObject(stateObject) - } else { - stateObject.Sync() - - self.UpdateStateObject(stateObject) - } - } - - // FIXME trie delete is broken - valid, t2 := ethtrie.ParanoiaCheck(self.trie) - if !valid { - self.trie = t2 +func (self *State) GetNonce(addr []byte) uint64 { + stateObject := self.GetStateObject(addr) + if stateObject != nil { + return stateObject.Nonce } -} -// Purges the current trie. -func (s *State) Purge() int { - return s.trie.NewIterator().Purge() + return 0 } -func (s *State) EachStorage(cb ethtrie.EachCallback) { - it := s.trie.NewIterator() - it.Each(cb) -} - -func (self *State) ResetStateObject(stateObject *StateObject) { - delete(self.stateObjects, string(stateObject.Address())) - - stateObject.state.Reset() -} +// +// Setting, updating & deleting state object methods +// +// Update the given state object and apply it to state trie func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() @@ -109,12 +66,14 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { self.manifest.AddObjectChange(stateObject) } +// Delete the given state object and delete it from the state trie func (self *State) DeleteStateObject(stateObject *StateObject) { self.trie.Delete(string(stateObject.Address())) delete(self.stateObjects, string(stateObject.Address())) } +// Retrieve a state object given my the address. Nil if not found func (self *State) GetStateObject(addr []byte) *StateObject { stateObject := self.stateObjects[string(addr)] if stateObject != nil { @@ -132,6 +91,7 @@ func (self *State) GetStateObject(addr []byte) *StateObject { return stateObject } +// Retrieve a state object or create a new state object if nil func (self *State) GetOrNewStateObject(addr []byte) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil { @@ -141,6 +101,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { return stateObject } +// Create a state object whether it exist in the trie or not func (self *State) NewStateObject(addr []byte) *StateObject { statelogger.Infof("(+) %x\n", addr) @@ -150,10 +111,15 @@ func (self *State) NewStateObject(addr []byte) *StateObject { return stateObject } +// Deprecated func (self *State) GetAccount(addr []byte) *StateObject { return self.GetOrNewStateObject(addr) } +// +// Setting, copying of the state methods +// + func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } @@ -181,14 +147,67 @@ func (self *State) Set(state *State) { //*self = *state } -func (s *State) Put(key, object []byte) { - s.trie.Update(string(key), string(object)) -} - func (s *State) Root() interface{} { return s.trie.Root } +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + //stateObject.state.Reset() + stateObject.Reset() + } + + s.Empty() +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, stateObject := range s.stateObjects { + s.UpdateStateObject(stateObject) + + if stateObject.state == nil { + continue + } + + stateObject.state.Sync() + } + + s.trie.Sync() + + s.Empty() +} + +func (self *State) Empty() { + self.stateObjects = make(map[string]*StateObject) +} + +func (self *State) Update() { + for _, stateObject := range self.stateObjects { + if stateObject.remove { + self.DeleteStateObject(stateObject) + } else { + stateObject.Sync() + + self.UpdateStateObject(stateObject) + } + } + + // FIXME trie delete is broken + valid, t2 := ethtrie.ParanoiaCheck(self.trie) + if !valid { + self.trie = t2 + } +} + // Object manifest // // The object manifest is used to keep changes to the state so we can keep track of the changes diff --git a/ethchain/vm.go b/ethchain/vm.go index c63b5392f..f57d6a751 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -452,13 +452,26 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) stack.Push(ethutil.BigD(data)) + + vm.Printf(" => %x", data) // 0x30 range case ADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) + + vm.Printf(" => %x", closure.Object().Address()) case BALANCE: - stack.Push(closure.object.Amount) + require(1) + + addr := stack.Pop().Bytes() + balance := vm.state.GetBalance(addr) + + stack.Push(balance) + + vm.Printf(" => %v (%x)", balance, addr) case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) + + vm.Printf(" => %v", vm.vars.Origin) case CALLER: caller := closure.caller.Address() stack.Push(ethutil.BigD(caller)) @@ -712,7 +725,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(ethutil.BigFalse) } else { - //snapshot := vm.state.Copy() + snapshot := vm.state.Copy() stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) @@ -728,8 +741,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vmlogger.Debugf("Closure execution failed. %v\n", err) - //vm.state.Set(snapshot) - vm.state.ResetStateObject(stateObject) + vm.state.Set(snapshot) } else { stack.Push(ethutil.BigTrue) -- cgit v1.2.3 From ff151f9fbcfea2d21139ec778fc7c1ac32282d71 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Jul 2014 21:54:36 +0200 Subject: vm output --- ethchain/vm.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index f57d6a751..6a64d3ff3 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -479,6 +479,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vm.Printf(" => %x", caller) case CALLVALUE: stack.Push(vm.vars.Value) + + vm.Printf(" => %v", vm.vars.Value) case CALLDATALOAD: require(1) offset := stack.Pop().Int64() -- cgit v1.2.3 From 9010857677ac374e09bab62a89f2fb52c11ed6d3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 11 Jul 2014 16:04:09 +0200 Subject: Special diff output for execution --- ethchain/asm.go | 4 ++++ ethchain/state.go | 11 +++++++++++ ethchain/state_manager.go | 8 ++++++++ ethchain/vm.go | 37 ++++++++++++++++++++++++++++++------- 4 files changed, 53 insertions(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 09d6af56f..2697953fd 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -24,6 +24,10 @@ func Disassemble(script []byte) (asm []string) { case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: pc.Add(pc, ethutil.Big1) a := int64(op) - int64(PUSH1) + 1 + if int(pc.Int64()+a) > len(script) { + return nil + } + data := script[pc.Int64() : pc.Int64()+a] if len(data) == 0 { data = []byte{0} diff --git a/ethchain/state.go b/ethchain/state.go index 6d45c9e32..8df79dcef 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -208,6 +209,16 @@ func (self *State) Update() { } } +// Debug stuff +func (self *State) CreateOutputForDiff() { + for addr, stateObject := range self.stateObjects { + fmt.Printf("0x%x 0x%x 0x%x 0x%x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) + stateObject.state.EachStorage(func(addr string, value *ethutil.Value) { + fmt.Printf("0x%x 0x%x\n", addr, value.Bytes()) + }) + } +} + // Object manifest // // The object manifest is used to keep changes to the state so we can keep track of the changes diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a5afa5096..62fcda8a5 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -150,6 +150,10 @@ done: receipts = append(receipts, receipt) handled = append(handled, tx) + + if ethutil.Config.Diff { + state.CreateOutputForDiff() + } } parent.GasUsed = totalUsedGas @@ -183,6 +187,10 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // before that. defer state.Reset() + if ethutil.Config.Diff { + fmt.Printf("## 0x%x 0x%x ##\n", block.Hash(), block.Number) + } + receipts, err := sm.ApplyDiff(state, parent, block) defer func() { if err != nil { diff --git a/ethchain/vm.go b/ethchain/vm.go index 6a64d3ff3..3ad4472ca 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -31,6 +31,7 @@ type Debugger interface { BreakHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool StepHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool BreakPoints() []int64 + SetCode(byteCode []byte) } type Vm struct { @@ -90,7 +91,12 @@ func (self *Vm) Endl() *Vm { } func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { - return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: LogTyPretty} + lt := LogTyPretty + if ethutil.Config.Diff { + lt = LogTyDiff + } + + return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: lt} } var Pow256 = ethutil.BigPow(2, 256) @@ -107,12 +113,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } }() + // Debug hook + if vm.Dbg != nil { + vm.Dbg.SetCode(closure.Script) + } + // Don't bother with the execution if there's no code. if len(closure.Script) == 0 { return closure.Return(nil), nil } - vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.object.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.Address(), closure.Gas, closure.Args) var ( op OpCode @@ -149,7 +160,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { b = []byte{0} } - fmt.Printf("%x %x %x %x\n", closure.object.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) + fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) } gas := new(big.Int) @@ -456,9 +467,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vm.Printf(" => %x", data) // 0x30 range case ADDRESS: - stack.Push(ethutil.BigD(closure.Object().Address())) + stack.Push(ethutil.BigD(closure.Address())) - vm.Printf(" => %x", closure.Object().Address()) + vm.Printf(" => %x", closure.Address()) case BALANCE: require(1) @@ -664,9 +675,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { ) // Generate a new address - addr := ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce) + addr := ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()) for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ { - ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce+i) + ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()+i) } closure.object.Nonce++ @@ -706,6 +717,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vm.Printf("CREATE success") } vm.Endl() + + // Debug hook + if vm.Dbg != nil { + vm.Dbg.SetCode(closure.Script) + } case CALL: require(7) @@ -749,6 +765,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { mem.Set(retOffset.Int64(), retSize.Int64(), ret) } + + // Debug hook + if vm.Dbg != nil { + vm.Dbg.SetCode(closure.Script) + } } case RETURN: require(2) @@ -786,6 +807,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if vm.Dbg != nil { for _, instrNo := range vm.Dbg.BreakPoints() { if pc.Cmp(big.NewInt(instrNo)) == 0 { + vm.Stepping = true + if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) { return nil, nil } -- cgit v1.2.3 From 54715586ab147a62342a9462f3a73cc2f750d148 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 12 Jul 2014 11:10:47 +0200 Subject: Changed sha3 to official one --- ethchain/vm.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 3ad4472ca..f7ce8c2ce 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -690,14 +690,15 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { contract.AddAmount(value) // Set the init script - contract.initScript = mem.Get(offset.Int64(), size.Int64()) + initCode := mem.Get(offset.Int64(), size.Int64()) + //fmt.Printf("%x\n", initCode) // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) closure.UseGas(closure.Gas) // Create the closure - c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price) + c := NewClosure(closure, contract, initCode, vm.state, gas, closure.Price) // Call the closure and set the return value as // main script. contract.script, err = Call(vm, c, nil) -- cgit v1.2.3 From 6426f3635eddaa1477e643886fd3c0eaf1fa6158 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 13 Jul 2014 17:56:14 +0200 Subject: Forgot to return gas when CALL's value transfer fails --- ethchain/vm.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index f7ce8c2ce..f1794ff77 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -550,8 +550,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } code := closure.Script[cOff : cOff+l] + fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) mem.Set(mOff, l, code) + fmt.Println(Code(mem.Get(mOff, l))) case GASPRICE: stack.Push(closure.Price) @@ -741,6 +743,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if closure.object.Amount.Cmp(value) < 0 { vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + closure.ReturnGas(gas, nil, nil) stack.Push(ethutil.BigFalse) } else { -- cgit v1.2.3 From 5b2e5d180fa79865b6319f4251a440da44a81809 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 00:37:18 +0200 Subject: Changed diff output not to prefix hex with 0x --- ethchain/state.go | 4 ++-- ethchain/state_manager.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 8df79dcef..4faf691f2 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -212,9 +212,9 @@ func (self *State) Update() { // Debug stuff func (self *State) CreateOutputForDiff() { for addr, stateObject := range self.stateObjects { - fmt.Printf("0x%x 0x%x 0x%x 0x%x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) + fmt.Printf("%x %x %x %x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) stateObject.state.EachStorage(func(addr string, value *ethutil.Value) { - fmt.Printf("0x%x 0x%x\n", addr, value.Bytes()) + fmt.Printf("%x %x\n", addr, value.Bytes()) }) } } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 62fcda8a5..f2ecd4b9f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -151,7 +151,7 @@ done: receipts = append(receipts, receipt) handled = append(handled, tx) - if ethutil.Config.Diff { + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { state.CreateOutputForDiff() } } @@ -187,8 +187,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // before that. defer state.Reset() - if ethutil.Config.Diff { - fmt.Printf("## 0x%x 0x%x ##\n", block.Hash(), block.Number) + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { + fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) } receipts, err := sm.ApplyDiff(state, parent, block) -- cgit v1.2.3 From 5a0c4ce29509046e7de801e96bee893c82bfc1e8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 00:38:20 +0200 Subject: Fixed "Copy" to also copy over the pending storage changes --- ethchain/state_object.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index ebc050863..f4adc4c80 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -15,6 +15,18 @@ func (self Code) String() string { return strings.Join(Disassemble(self), " ") } +type Storage map[string]*ethutil.Value + +func (self Storage) Copy() Storage { + cpy := make(Storage) + for key, value := range self { + // XXX Do we need a 'value' copy or is this sufficient? + cpy[key] = value + } + + return cpy +} + type StateObject struct { // Address of the object address []byte @@ -27,7 +39,7 @@ type StateObject struct { script Code initScript Code - storage map[string]*ethutil.Value + storage Storage // Total gas pool is the total amount of gas currently // left if this object is the coinbase. Gas is directly @@ -41,7 +53,7 @@ type StateObject struct { } func (self *StateObject) Reset() { - self.storage = make(map[string]*ethutil.Value) + self.storage = make(Storage) } // Converts an transaction in to a state object @@ -95,7 +107,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { func (self *StateObject) MarkForDeletion() { self.remove = true - statelogger.Infof("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) + statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) } func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { @@ -154,13 +166,13 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - statelogger.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.DebugDetailf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - statelogger.Infof("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.DebugDetailf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -222,6 +234,7 @@ func (self *StateObject) Copy() *StateObject { } stateObject.script = ethutil.CopyBytes(self.script) stateObject.initScript = ethutil.CopyBytes(self.initScript) + stateObject.storage = self.storage.Copy() return stateObject } -- cgit v1.2.3 From 767d24ea5da8794dbc3b8bed19f6c204e775e406 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 22:52:30 +0200 Subject: Removed defer and added receipts checking in tx processing --- ethchain/state_manager.go | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f2ecd4b9f..d52e418ce 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -148,6 +148,11 @@ done: accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + original := block.Receipts()[i] + if !original.Cmp(receipt) { + return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) + } + receipts = append(receipts, receipt) handled = append(handled, tx) @@ -192,31 +197,6 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { } receipts, err := sm.ApplyDiff(state, parent, block) - defer func() { - if err != nil { - if len(receipts) == len(block.Receipts()) { - for i, receipt := range block.Receipts() { - statelogger.Infof("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) - } - } else { - statelogger.Warnln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) - } - } else { - /* - for i, receipt := range receipts { - gu := new(big.Int) - if i != 0 { - gu.Sub(receipt.CumulativeGasUsed, receipts[i-1].CumulativeGasUsed) - } else { - gu.Set(receipt.CumulativeGasUsed) - } - - statelogger.Infof("[r] %v ~ %x (%x)\n", gu, receipt.PostState[0:4], receipt.Tx.Hash()) - } - */ - } - }() - if err != nil { return err } -- cgit v1.2.3 From 98f21d8973398ccf58a762788a1972ef16213de5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 14 Jul 2014 22:52:44 +0200 Subject: Compare method for receipts --- ethchain/transaction.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index da3f9bcf2..0b4f8d1a4 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -227,6 +227,18 @@ func (self *Receipt) String() string { self.CumulativeGasUsed) } +func (self *Receipt) Cmp(other *Receipt) bool { + if bytes.Compare(self.PostState, other.PostState) != 0 { + return false + } + + if self.CumulativeGasUsed.Cmp(other.CumulativeGasUsed) != 0 { + return false + } + + return true +} + // Transaction slice type for basic sorting type Transactions []*Transaction -- cgit v1.2.3 From 69acda2c255b098a015e17432b9bffd9010d841d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 00:25:27 +0200 Subject: Paranoia check moved --- ethchain/state_transition.go | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 314d858f2..8cface9e8 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,8 +2,6 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethtrie" - "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -275,20 +273,5 @@ func (self *StateTransition) Eval(script []byte, context *StateObject, typ strin func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) { ret, _, err = closure.Call(vm, data) - if ethutil.Config.Paranoia { - var ( - context = closure.object - trie = context.state.trie - ) - - valid, t2 := ethtrie.ParanoiaCheck(trie) - if !valid { - // TODO FIXME ASAP - context.state.trie = t2 - - statelogger.Infoln("Warn: PARANOIA: Different state object roots during copy") - } - } - return } -- cgit v1.2.3 From 50bc838047709796596f447ef3e60d0e4ab47fde Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 00:25:38 +0200 Subject: Moved checks --- ethchain/state.go | 1 - ethchain/state_object.go | 29 +++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 4faf691f2..66c298b3c 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -145,7 +145,6 @@ func (self *State) Set(state *State) { self.trie = state.trie self.stateObjects = state.stateObjects - //*self = *state } func (s *State) Root() interface{} { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index f4adc4c80..5791c6ed1 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -54,6 +54,7 @@ type StateObject struct { func (self *StateObject) Reset() { self.storage = make(Storage) + self.state.Reset() } // Converts an transaction in to a state object @@ -78,7 +79,7 @@ func NewStateObject(addr []byte) *StateObject { object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) - object.storage = make(map[string]*ethutil.Value) + object.storage = make(Storage) return object } @@ -125,23 +126,24 @@ func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) { self.setStorage(key.Bytes(), value) } -func (self *StateObject) getStorage(key []byte) *ethutil.Value { - k := ethutil.LeftPadBytes(key, 32) +func (self *StateObject) getStorage(k []byte) *ethutil.Value { + key := ethutil.LeftPadBytes(k, 32) - value := self.storage[string(k)] + value := self.storage[string(key)] if value == nil { - value = self.GetAddr(k) + value = self.GetAddr(key) - self.storage[string(k)] = value + if !value.IsNil() { + self.storage[string(key)] = value + } } return value } -func (self *StateObject) setStorage(key []byte, value *ethutil.Value) { - k := ethutil.LeftPadBytes(key, 32) - - self.storage[string(k)] = value +func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { + key := ethutil.LeftPadBytes(k, 32) + self.storage[string(key)] = value.Copy() } func (self *StateObject) Sync() { @@ -152,9 +154,16 @@ func (self *StateObject) Sync() { } self.SetAddr([]byte(key), value) + } + valid, t2 := ethtrie.ParanoiaCheck(self.state.trie) + if !valid { + self.state.trie = t2 + + statelogger.Infoln("Warn: PARANOIA: Different state storage root during copy") } } + func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { if int64(len(c.script)-1) < pc.Int64() { return ethutil.NewValue(0) -- cgit v1.2.3 From 2784e256f1c5f8112486e9037c9b00e628e5aa10 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 00:25:49 +0200 Subject: Vm logging on diff --- ethchain/state_manager.go | 2 +- ethchain/transaction.go | 4 ---- ethchain/vm.go | 10 ++++++---- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index d52e418ce..129b30ba6 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -196,7 +196,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) } - receipts, err := sm.ApplyDiff(state, parent, block) + _, err = sm.ApplyDiff(state, parent, block) if err != nil { return err } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 0b4f8d1a4..5686a7edb 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -232,10 +232,6 @@ func (self *Receipt) Cmp(other *Receipt) bool { return false } - if self.CumulativeGasUsed.Cmp(other.CumulativeGasUsed) != 0 { - return false - } - return true } diff --git a/ethchain/vm.go b/ethchain/vm.go index f1794ff77..788bde886 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -184,7 +184,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { var mult *big.Int y, x := stack.Peekn() val := closure.GetStorage(x) - if val.IsEmpty() && len(y.Bytes()) > 0 { + //if val.IsEmpty() && len(y.Bytes()) > 0 { + if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { mult = ethutil.Big2 } else if !val.IsEmpty() && len(y.Bytes()) == 0 { mult = ethutil.Big0 @@ -482,7 +483,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) - vm.Printf(" => %v", vm.vars.Origin) + vm.Printf(" => %x", vm.vars.Origin) case CALLER: caller := closure.caller.Address() stack.Push(ethutil.BigD(caller)) @@ -550,10 +551,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } code := closure.Script[cOff : cOff+l] - fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) + //fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) mem.Set(mOff, l, code) - fmt.Println(Code(mem.Get(mOff, l))) + //fmt.Println(Code(mem.Get(mOff, l))) case GASPRICE: stack.Push(closure.Price) @@ -743,6 +744,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if closure.object.Amount.Cmp(value) < 0 { vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + closure.ReturnGas(gas, nil, nil) stack.Push(ethutil.BigFalse) -- cgit v1.2.3 From 1735ec0362e84455126d8c1bd380ecae436d1167 Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 15 Jul 2014 01:11:06 +0100 Subject: use ethreact.Event and ethreact.ReactorEngine --- ethchain/dagger.go | 5 +++-- ethchain/state_manager.go | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 4dda21ff5..adf1c2f05 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -3,6 +3,7 @@ package ethchain import ( "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" "hash" @@ -14,7 +15,7 @@ import ( var powlogger = ethlog.NewLogger("POW") type PoW interface { - Search(block *Block, reactChan chan ethutil.React) []byte + Search(block *Block, reactChan chan ethreact.Event) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -22,7 +23,7 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { +func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 62fcda8a5..3eafd2d6e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -36,7 +37,7 @@ type EthManager interface { BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) - Reactor() *ethutil.ReactorEngine + Reactor() *ethreact.ReactorEngine PeerCount() int IsMining() bool IsListening() bool -- cgit v1.2.3 From 34da3b4fa8133a2042919fe344b7bc656fcad4f2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 20:35:07 +0200 Subject: Moved --- ethchain/state_manager.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 129b30ba6..80362fa77 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethtrie" + _ "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "math/big" @@ -214,12 +214,14 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return err } - if ethutil.Config.Paranoia { - valid, _ := ethtrie.ParanoiaCheck(state.trie) - if !valid { - err = fmt.Errorf("PARANOIA: World state trie corruption") + /* + if ethutil.Config.Paranoia { + valid, _ := ethtrie.ParanoiaCheck(state.trie) + if !valid { + err = fmt.Errorf("PARANOIA: World state trie corruption") + } } - } + */ if !block.State().Cmp(state) { -- cgit v1.2.3 From 7a410643ac5dc7cc297cbdb094539761230440d0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Jul 2014 20:35:55 +0200 Subject: Added/changed logging --- ethchain/state_object.go | 5 +++-- ethchain/vm.go | 10 +++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5791c6ed1..889496e91 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -143,6 +143,7 @@ func (self *StateObject) getStorage(k []byte) *ethutil.Value { func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { key := ethutil.LeftPadBytes(k, 32) + //fmt.Printf("%x %v\n", key, value) self.storage[string(key)] = value.Copy() } @@ -158,9 +159,9 @@ func (self *StateObject) Sync() { valid, t2 := ethtrie.ParanoiaCheck(self.state.trie) if !valid { - self.state.trie = t2 + statelogger.Infof("Warn: PARANOIA: Different state storage root during copy %x vs %x\n", self.state.trie.Root, t2.Root) - statelogger.Infoln("Warn: PARANOIA: Different state storage root during copy") + self.state.trie = t2 } } diff --git a/ethchain/vm.go b/ethchain/vm.go index 788bde886..3a956ee83 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -155,6 +155,15 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // XXX Leave this Println intact. Don't change this to the log system. // Used for creating diffs between implementations if vm.logTy == LogTyDiff { + switch op { + case STOP, RETURN, SUICIDE: + closure.object.Sync() + closure.object.state.EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) + }) + } + b := pc.Bytes() if len(b) == 0 { b = []byte{0} @@ -184,7 +193,6 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { var mult *big.Int y, x := stack.Peekn() val := closure.GetStorage(x) - //if val.IsEmpty() && len(y.Bytes()) > 0 { if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { mult = ethutil.Big2 } else if !val.IsEmpty() && len(y.Bytes()) == 0 { -- cgit v1.2.3 From ed3424ff75b396360990725afc124326dea4ab45 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 11:21:18 +0200 Subject: Trie fixes --- ethchain/state.go | 4 ++++ ethchain/state_manager.go | 1 + ethchain/state_object.go | 41 +++++++++++++++++++++++++++++++---------- ethchain/vm.go | 2 +- 4 files changed, 37 insertions(+), 11 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 66c298b3c..6b849296a 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -76,6 +76,8 @@ func (self *State) DeleteStateObject(stateObject *StateObject) { // Retrieve a state object given my the address. Nil if not found func (self *State) GetStateObject(addr []byte) *StateObject { + addr = ethutil.Address(addr) + stateObject := self.stateObjects[string(addr)] if stateObject != nil { return stateObject @@ -204,6 +206,8 @@ func (self *State) Update() { // FIXME trie delete is broken valid, t2 := ethtrie.ParanoiaCheck(self.trie) if !valid { + statelogger.Infof("Warn: PARANOIA: Different state root during copy %x vs %x\n", self.trie.Root, t2.Root) + self.trie = t2 } } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 80362fa77..a0568c4cd 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -121,6 +121,7 @@ done: for i, tx := range txs { txGas := new(big.Int).Set(tx.Gas) st := NewStateTransition(coinbase, tx, state, block) + //fmt.Printf("#%d\n", i+1) err = st.TransitionState() if err != nil { switch { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 889496e91..cf37586fc 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -75,7 +75,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { func NewStateObject(addr []byte) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. - address := ethutil.LeftPadBytes(addr, 20) + address := ethutil.Address(addr) object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) @@ -92,13 +92,6 @@ func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { return contract } -// Returns a newly created account -func NewAccount(address []byte, amount *big.Int) *StateObject { - account := &StateObject{address: address, Amount: amount, Nonce: 0} - - return account -} - func NewStateObjectFromBytes(address, data []byte) *StateObject { object := &StateObject{address: address} object.RlpDecode(data) @@ -139,17 +132,37 @@ func (self *StateObject) getStorage(k []byte) *ethutil.Value { } return value + + //return self.GetAddr(key) } func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { key := ethutil.LeftPadBytes(k, 32) - //fmt.Printf("%x %v\n", key, value) self.storage[string(key)] = value.Copy() + + /* + if value.BigInt().Cmp(ethutil.Big0) == 0 { + self.state.trie.Delete(string(key)) + return + } + + self.SetAddr(key, value) + */ } func (self *StateObject) Sync() { + /* + fmt.Println("############# BEFORE ################") + self.state.EachStorage(func(key string, value *ethutil.Value) { + fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) + }) + fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) + fmt.Println("#####################################") + */ for key, value := range self.storage { - if value.BigInt().Cmp(ethutil.Big0) == 0 { + if value.Len() == 0 { // value.BigInt().Cmp(ethutil.Big0) == 0 { + //data := self.getStorage([]byte(key)) + //fmt.Printf("deleting %x %x 0x%x\n", self.Address(), []byte(key), data) self.state.trie.Delete(string(key)) continue } @@ -163,6 +176,14 @@ func (self *StateObject) Sync() { self.state.trie = t2 } + + /* + fmt.Println("############# AFTER ################") + self.state.EachStorage(func(key string, value *ethutil.Value) { + fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) + }) + */ + //fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { diff --git a/ethchain/vm.go b/ethchain/vm.go index 3a956ee83..58d1bee89 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -195,7 +195,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { val := closure.GetStorage(x) if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { mult = ethutil.Big2 - } else if !val.IsEmpty() && len(y.Bytes()) == 0 { + } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { mult = ethutil.Big0 } else { mult = ethutil.Big1 -- cgit v1.2.3 From 0415e4a637296539e7a5c09282b7aee19268e599 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 14:53:27 +0200 Subject: Fixed coinbase copy in state --- ethchain/state.go | 3 ++- ethchain/state_manager.go | 4 +++- ethchain/state_object.go | 9 ++++++--- ethchain/state_transition.go | 30 +++++++++++++++++------------- ethchain/vm.go | 2 +- 5 files changed, 29 insertions(+), 19 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 6b849296a..9748da1bc 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -61,6 +61,7 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) + fmt.Printf("balance %v %p\n", stateObject.Amount, stateObject) self.trie.Update(string(addr), string(stateObject.RlpEncode())) @@ -174,7 +175,7 @@ func (s *State) Reset() { func (s *State) Sync() { // Sync all nested states for _, stateObject := range s.stateObjects { - s.UpdateStateObject(stateObject) + //s.UpdateStateObject(stateObject) if stateObject.state == nil { continue diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a0568c4cd..0d4b8ac55 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -120,7 +120,9 @@ func (self *StateManager) ProcessTransactions(coinbase *StateObject, state *Stat done: for i, tx := range txs { txGas := new(big.Int).Set(tx.Gas) - st := NewStateTransition(coinbase, tx, state, block) + + cb := state.GetStateObject(coinbase.Address()) + st := NewStateTransition(cb, tx, state, block) //fmt.Printf("#%d\n", i+1) err = st.TransitionState() if err != nil { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index cf37586fc..a4225991a 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -80,6 +80,7 @@ func NewStateObject(addr []byte) *StateObject { object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) object.storage = make(Storage) + object.gasPool = new(big.Int) return object } @@ -183,7 +184,7 @@ func (self *StateObject) Sync() { fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) }) */ - //fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) + fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { @@ -197,13 +198,13 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - statelogger.DebugDetailf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - statelogger.DebugDetailf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -266,6 +267,7 @@ func (self *StateObject) Copy() *StateObject { stateObject.script = ethutil.CopyBytes(self.script) stateObject.initScript = ethutil.CopyBytes(self.initScript) stateObject.storage = self.storage.Copy() + stateObject.gasPool.Set(self.gasPool) return stateObject } @@ -324,6 +326,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*ethutil.Value) + c.gasPool = new(big.Int) c.ScriptHash = decoder.Get(3).Bytes() diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8cface9e8..8ed528c9f 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -42,7 +42,7 @@ func (self *StateTransition) Coinbase() *StateObject { return self.cb } - self.cb = self.state.GetAccount(self.coinbase) + self.cb = self.state.GetOrNewStateObject(self.coinbase) return self.cb } func (self *StateTransition) Sender() *StateObject { @@ -50,7 +50,7 @@ func (self *StateTransition) Sender() *StateObject { return self.sen } - self.sen = self.state.GetAccount(self.tx.Sender()) + self.sen = self.state.GetOrNewStateObject(self.tx.Sender()) return self.sen } @@ -63,7 +63,7 @@ func (self *StateTransition) Receiver() *StateObject { return self.rec } - self.rec = self.state.GetAccount(self.tx.Recipient) + self.rec = self.state.GetOrNewStateObject(self.tx.Recipient) return self.rec } @@ -174,13 +174,16 @@ func (self *StateTransition) TransitionState() (err error) { return } - /* FIXME - * If tx goes TO "0", goes OOG during init, reverse changes, but initial endowment should happen. The ether is lost forever - */ - var snapshot *State + if sender.Amount.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) + } + var snapshot *State // If the receiver is nil it's a contract (\0*32). if tx.CreatesContract() { + // Subtract the (irreversible) amount from the senders account + sender.SubAmount(self.value) + snapshot = self.state.Copy() // Create a new state object for the contract @@ -189,16 +192,17 @@ func (self *StateTransition) TransitionState() (err error) { if receiver == nil { return fmt.Errorf("Unable to create contract") } + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) } else { receiver = self.Receiver() - } - // Transfer value from sender to receiver - if err = self.transferValue(sender, receiver); err != nil { - return - } + // Subtract the amount from the senders account + sender.SubAmount(self.value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) - if snapshot == nil { snapshot = self.state.Copy() } diff --git a/ethchain/vm.go b/ethchain/vm.go index 58d1bee89..4fdf8b31a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -456,7 +456,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case BYTE: require(2) val, th := stack.Popn() - if th.Cmp(big.NewInt(32)) < 0 { + if th.Cmp(big.NewInt(32)) < 0 && th.Cmp(big.NewInt(int64(len(val.Bytes())))) < 0 { byt := big.NewInt(int64(val.Bytes()[th.Int64()])) stack.Push(byt) -- cgit v1.2.3 From 90f63657cbcbf6768cd146d17d176d2a0ee4b778 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 15:01:33 +0200 Subject: Removed debug log --- ethchain/state.go | 1 - 1 file changed, 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 9748da1bc..684b81102 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -61,7 +61,6 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) - fmt.Printf("balance %v %p\n", stateObject.Amount, stateObject) self.trie.Update(string(addr), string(stateObject.RlpEncode())) -- cgit v1.2.3 From 16f61005006751c38607da089a864350d997c52e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 17 Jul 2014 15:11:09 +0200 Subject: Removed debug log --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index a4225991a..8e7b5fece 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -184,7 +184,7 @@ func (self *StateObject) Sync() { fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) }) */ - fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) + //fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) } func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { -- cgit v1.2.3 From db8170def31e03ecb7086dd257d7c8fce084313f Mon Sep 17 00:00:00 2001 From: Maran Date: Fri, 18 Jul 2014 12:01:08 +0200 Subject: WIP to expose hashrate to gui --- ethchain/dagger.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 4dda21ff5..dccd2ff5b 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -16,10 +16,16 @@ var powlogger = ethlog.NewLogger("POW") type PoW interface { Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool + GetHashrate() int64 } type EasyPow struct { - hash *big.Int + hash *big.Int + HashRate int64 +} + +func (pow *EasyPow) GetHashrate() int64 { + return pow.HashRate } func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { @@ -39,7 +45,8 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - powlogger.Infoln("Hashing @", int64(hashes), "khash") + pow.HashRate = int64(hashes) + powlogger.Infoln("Hashing @", int64(pow.HashRate), "khash") } sha := ethcrypto.Sha3Bin(big.NewInt(r.Int63()).Bytes()) -- cgit v1.2.3 From cd9b344506ee2daeb7a6248b2cdb5e7e69db7e79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Jul 2014 13:21:40 +0200 Subject: Fixed range --- ethchain/state_manager.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 0d4b8ac55..a12ce53e5 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -151,9 +151,11 @@ done: accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} - original := block.Receipts()[i] - if !original.Cmp(receipt) { - return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) + if i < len(block.Receipts()) { + original := block.Receipts()[i] + if !original.Cmp(receipt) { + return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) + } } receipts = append(receipts, receipt) -- cgit v1.2.3 From 9f00aeae29d53fec358fcecdc9bcc162b8e3984c Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Jul 2014 16:13:21 +0200 Subject: Base time on previous parent, not last block --- ethchain/state_manager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a12ce53e5..f28f45eab 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -312,9 +312,9 @@ func (sm *StateManager) ValidateBlock(block *Block) error { } } - diff := block.Time - sm.bc.CurrentBlock.Time + diff := block.Time - previousBlock.Time if diff < 0 { - return ValidationError("Block timestamp less then prev block %v", diff) + return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time) } /* XXX -- cgit v1.2.3 From 93261b98c2bc664af30676129def291ff9e8a9ce Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 21 Jul 2014 11:56:04 +0200 Subject: Changed iterator --- ethchain/state.go | 14 ++------------ ethchain/state_object.go | 26 ++++++++++++++++++++++++++ ethchain/vm.go | 2 +- 3 files changed, 29 insertions(+), 13 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 684b81102..3a9929ecc 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,7 +1,6 @@ package ethchain import ( - "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -27,12 +26,6 @@ func NewState(trie *ethtrie.Trie) *State { return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } -// Iterate over each storage address and yield callback -func (s *State) EachStorage(cb ethtrie.EachCallback) { - it := s.trie.NewIterator() - it.Each(cb) -} - // Retrieve the balance from the given address or 0 if object not found func (self *State) GetBalance(addr []byte) *big.Int { stateObject := self.GetStateObject(addr) @@ -214,11 +207,8 @@ func (self *State) Update() { // Debug stuff func (self *State) CreateOutputForDiff() { - for addr, stateObject := range self.stateObjects { - fmt.Printf("%x %x %x %x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) - stateObject.state.EachStorage(func(addr string, value *ethutil.Value) { - fmt.Printf("%x %x\n", addr, value.Bytes()) - }) + for _, stateObject := range self.stateObjects { + stateObject.CreateOutputForDiff() } } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8e7b5fece..184609015 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -151,6 +151,24 @@ func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { */ } +// Iterate over each storage address and yield callback +func (self *StateObject) EachStorage(cb ethtrie.EachCallback) { + // First loop over the uncommit/cached values in storage + for key, value := range self.storage { + // XXX Most iterators Fns as it stands require encoded values + encoded := ethutil.NewValue(value.Encode()) + cb(key, encoded) + } + + it := self.state.trie.NewIterator() + it.Each(func(key string, value *ethutil.Value) { + // If it's cached don't call the callback. + if self.storage[key] == nil { + cb(key, value) + } + }) +} + func (self *StateObject) Sync() { /* fmt.Println("############# BEFORE ################") @@ -303,6 +321,14 @@ func (c *StateObject) Init() Code { return c.initScript } +// Debug stuff +func (self *StateObject) CreateOutputForDiff() { + fmt.Printf("%x %x %x %x\n", self.Address(), self.state.Root(), self.Amount.Bytes(), self.Nonce) + self.EachStorage(func(addr string, value *ethutil.Value) { + fmt.Printf("%x %x\n", addr, value.Bytes()) + }) +} + // // Encoding // diff --git a/ethchain/vm.go b/ethchain/vm.go index 4fdf8b31a..9d47f950d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -158,7 +158,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { switch op { case STOP, RETURN, SUICIDE: closure.object.Sync() - closure.object.state.EachStorage(func(key string, value *ethutil.Value) { + closure.object.EachStorage(func(key string, value *ethutil.Value) { value.Decode() fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) }) -- cgit v1.2.3 From 5d2669dbd35b9449cbbb249dcec89e2a64c90f30 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 21 Jul 2014 12:21:34 +0200 Subject: Fixed tx sha creation --- ethchain/block.go | 33 ++++++++++++++++++++++++++++----- ethchain/state_manager.go | 17 ++++++----------- 2 files changed, 34 insertions(+), 16 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index a0f9ecd86..447d55f99 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" - "strconv" + _ "strconv" "time" ) @@ -252,20 +252,43 @@ func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { func (block *Block) setTransactions(txs []*Transaction) { block.transactions = txs + /* + trie := ethtrie.NewTrie(ethutil.Config.Db, "") + for i, tx := range txs { + trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) + } + + switch trie.Root.(type) { + case string: + block.TxSha = []byte(trie.Root.(string)) + case []byte: + block.TxSha = trie.Root.([]byte) + default: + panic(fmt.Sprintf("invalid root type %T", trie.Root)) + } + */ +} + +func CreateTxSha(receipts Receipts) (sha []byte) { trie := ethtrie.NewTrie(ethutil.Config.Db, "") - for i, tx := range txs { - trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) + for i, receipt := range receipts { + trie.Update(string(ethutil.NewValue(i).Encode()), string(ethutil.NewValue(receipt.RlpData()).Encode())) } switch trie.Root.(type) { case string: - block.TxSha = []byte(trie.Root.(string)) + sha = []byte(trie.Root.(string)) case []byte: - block.TxSha = trie.Root.([]byte) + sha = trie.Root.([]byte) default: panic(fmt.Sprintf("invalid root type %T", trie.Root)) } + return sha +} + +func (self *Block) SetTxHash(receipts Receipts) { + self.TxSha = CreateTxSha(receipts) } func (block *Block) Value() *ethutil.Value { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f28f45eab..6a6c67492 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -201,11 +201,16 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) } - _, err = sm.ApplyDiff(state, parent, block) + receipts, err := sm.ApplyDiff(state, parent, block) if err != nil { return err } + txSha := CreateTxSha(receipts) + if bytes.Compare(txSha, block.TxSha) != 0 { + return fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha) + } + // Block validation if err = sm.ValidateBlock(block); err != nil { statelogger.Errorln("Error validating block:", err) @@ -219,17 +224,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return err } - /* - if ethutil.Config.Paranoia { - valid, _ := ethtrie.ParanoiaCheck(state.trie) - if !valid { - err = fmt.Errorf("PARANOIA: World state trie corruption") - } - } - */ - if !block.State().Cmp(state) { - err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return } -- cgit v1.2.3 From 6774ddaba29ae9e9db5065ce74055297b948adf9 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 21 Jul 2014 14:35:37 +0200 Subject: Fix regression on 32bit (windows) systems --- ethchain/vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 4fdf8b31a..528088a49 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -506,7 +506,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { offset := stack.Pop().Int64() data := make([]byte, 32) - if len(closure.Args) >= int(offset) { + if big.NewInt(int64(len(closure.Args))).Cmp(big.NewInt(offset)) >= 0 { l := int64(math.Min(float64(offset+32), float64(len(closure.Args)))) copy(data, closure.Args[offset:l]) -- cgit v1.2.3 From 20ee1ae65e57ef7d60404277162c84c572c6bb10 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 21 Jul 2014 20:38:43 +0200 Subject: Refactored CALLDATALOAD to use big int * Added BigMin --- ethchain/vm.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/vm.go b/ethchain/vm.go index 34ecd95b7..a9bed1eca 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -503,13 +503,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vm.Printf(" => %v", vm.vars.Value) case CALLDATALOAD: require(1) - offset := stack.Pop().Int64() + var ( + offset = stack.Pop() + data = make([]byte, 32) + lenData = big.NewInt(int64(len(closure.Args))) + ) - data := make([]byte, 32) - if big.NewInt(int64(len(closure.Args))).Cmp(big.NewInt(offset)) >= 0 { - l := int64(math.Min(float64(offset+32), float64(len(closure.Args)))) + if lenData.Cmp(offset) >= 0 { + length := new(big.Int).Add(offset, ethutil.Big32) + length = ethutil.BigMin(length, lenData) - copy(data, closure.Args[offset:l]) + copy(data, closure.Args[offset.Int64():length.Int64()]) } vm.Printf(" => 0x%x", data) -- cgit v1.2.3 From 1e8b54abfb7129fcdf4812ad01b6a7cd61e4f65d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 22 Jul 2014 11:54:48 +0200 Subject: Refactored state, state object and vm * The State and StateObject have been moved to their own package * The VM is moved to it's own package --- ethchain/state_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 6a6c67492..8dc88d7c3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -123,9 +123,9 @@ done: cb := state.GetStateObject(coinbase.Address()) st := NewStateTransition(cb, tx, state, block) - //fmt.Printf("#%d\n", i+1) err = st.TransitionState() if err != nil { + statelogger.Infoln(err) switch { case IsNonceErr(err): err = nil // ignore error -- cgit v1.2.3 From 490ca410c01a1b8076214d00c21d2edf09c24f86 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 22 Jul 2014 15:57:54 +0200 Subject: Minor improvements and fixes to the new vm structure --- ethchain/asm.go | 4 ++-- ethchain/vm.go | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 2697953fd..9f99b0c48 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -25,7 +25,7 @@ func Disassemble(script []byte) (asm []string) { pc.Add(pc, ethutil.Big1) a := int64(op) - int64(PUSH1) + 1 if int(pc.Int64()+a) > len(script) { - return nil + return } data := script[pc.Int64() : pc.Int64()+a] @@ -40,5 +40,5 @@ func Disassemble(script []byte) (asm []string) { pc.Add(pc, ethutil.Big1) } - return + return asm } diff --git a/ethchain/vm.go b/ethchain/vm.go index a9bed1eca..4cbb4e1c4 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -563,10 +563,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } code := closure.Script[cOff : cOff+l] - //fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) + fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) mem.Set(mOff, l, code) - //fmt.Println(Code(mem.Get(mOff, l))) case GASPRICE: stack.Push(closure.Price) @@ -673,6 +672,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(pc) case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) + + vm.Printf(" => %v", mem.Len()).Endl() case GAS: stack.Push(closure.Gas) // 0x60 range -- cgit v1.2.3 From 32d125131f602d63f66ee7eb09439074f0b94a91 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Jul 2014 12:04:15 +0200 Subject: Refactored to new state and vm --- ethchain/block.go | 27 +- ethchain/block_chain.go | 4 +- ethchain/closure.go | 121 ------ ethchain/stack.go | 150 -------- ethchain/state.go | 250 ------------- ethchain/state_manager.go | 35 +- ethchain/state_object.go | 368 ------------------ ethchain/state_object_test.go | 52 --- ethchain/state_test.go | 30 -- ethchain/state_transition.go | 95 +++-- ethchain/transaction_pool.go | 3 +- ethchain/vm.go | 843 ------------------------------------------ ethchain/vm_env.go | 28 ++ ethchain/vm_test.go | 68 ---- 14 files changed, 125 insertions(+), 1949 deletions(-) delete mode 100644 ethchain/closure.go delete mode 100644 ethchain/stack.go delete mode 100644 ethchain/state.go delete mode 100644 ethchain/state_object.go delete mode 100644 ethchain/state_object_test.go delete mode 100644 ethchain/state_test.go delete mode 100644 ethchain/vm.go create mode 100644 ethchain/vm_env.go delete mode 100644 ethchain/vm_test.go (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 447d55f99..437525e35 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -39,7 +40,7 @@ type Block struct { Coinbase []byte // Block Trie state //state *ethutil.Trie - state *State + state *ethstate.State // Difficulty for the current block Difficulty *big.Int // Creation time @@ -104,7 +105,7 @@ func CreateBlock(root interface{}, } block.SetUncles([]*Block{}) - block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, root)) + block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, root)) return block } @@ -116,12 +117,12 @@ func (block *Block) Hash() []byte { func (block *Block) HashNoNonce() []byte { return ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, - block.UncleSha, block.Coinbase, block.state.trie.Root, + block.UncleSha, block.Coinbase, block.state.Trie.Root, block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, block.GasLimit, block.GasUsed, block.Time, block.Extra})) } -func (block *Block) State() *State { +func (block *Block) State() *ethstate.State { return block.state } @@ -140,17 +141,17 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { base := new(big.Int) contract.Amount = base.Sub(contract.Amount, fee) - block.state.trie.Update(string(addr), string(contract.RlpEncode())) + block.state.Trie.Update(string(addr), string(contract.RlpEncode())) - data := block.state.trie.Get(string(block.Coinbase)) + data := block.state.Trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) - account := NewStateObjectFromBytes(block.Coinbase, []byte(data)) + account := ethstate.NewStateObjectFromBytes(block.Coinbase, []byte(data)) base = new(big.Int) account.Amount = base.Add(account.Amount, fee) - //block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) + //block.state.Trie.Update(string(block.Coinbase), string(ether.RlpEncode())) block.state.UpdateStateObject(account) return true @@ -312,7 +313,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() @@ -354,7 +355,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() @@ -369,7 +370,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { } func (block *Block) GetRoot() interface{} { - return block.state.trie.Root + return block.state.Trie.Root } func (self *Block) Receipts() []*Receipt { @@ -385,7 +386,7 @@ func (block *Block) header() []interface{} { // Coinbase address block.Coinbase, // root state - block.state.trie.Root, + block.state.Trie.Root, // Sha of tx block.TxSha, // Current block Difficulty @@ -429,7 +430,7 @@ func (block *Block) String() string { block.PrevHash, block.UncleSha, block.Coinbase, - block.state.trie.Root, + block.state.Trie.Root, block.TxSha, block.Difficulty, block.Number, diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index f72a77706..1a2662787 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -44,7 +44,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { hash := ZeroHash256 if bc.CurrentBlock != nil { - root = bc.CurrentBlock.state.trie.Root + root = bc.CurrentBlock.state.Trie.Root hash = bc.LastBlockHash lastBlockTime = bc.CurrentBlock.Time } @@ -297,7 +297,7 @@ func (bc *BlockChain) setLastBlock() { } else { AddTestNetFunds(bc.genesisBlock) - bc.genesisBlock.state.trie.Sync() + bc.genesisBlock.state.Trie.Sync() // Prepare the genesis block bc.Add(bc.genesisBlock) diff --git a/ethchain/closure.go b/ethchain/closure.go deleted file mode 100644 index 1f7f8d703..000000000 --- a/ethchain/closure.go +++ /dev/null @@ -1,121 +0,0 @@ -package ethchain - -// TODO Re write VM to use values instead of big integers? - -import ( - "github.com/ethereum/eth-go/ethutil" - "math/big" -) - -type ClosureRef interface { - ReturnGas(*big.Int, *big.Int, *State) - Address() []byte - GetStorage(*big.Int) *ethutil.Value - SetStorage(*big.Int, *ethutil.Value) - N() *big.Int -} - -// Basic inline closure object which implement the 'closure' interface -type Closure struct { - caller ClosureRef - object *StateObject - Script []byte - State *State - - Gas, UsedGas, Price *big.Int - - Args []byte -} - -// Create a new closure for the given data items -func NewClosure(caller ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { - c := &Closure{caller: caller, object: object, Script: script, State: state, Args: nil} - - // Gas should be a pointer so it can safely be reduced through the run - // This pointer will be off the state transition - c.Gas = gas //new(big.Int).Set(gas) - // In most cases price and value are pointers to transaction objects - // and we don't want the transaction's values to change. - c.Price = new(big.Int).Set(price) - c.UsedGas = new(big.Int) - - return c -} - -// Retuns the x element in data slice -func (c *Closure) GetStorage(x *big.Int) *ethutil.Value { - m := c.object.GetStorage(x) - if m == nil { - return ethutil.EmptyValue() - } - - return m -} - -func (c *Closure) Get(x *big.Int) *ethutil.Value { - return c.Gets(x, big.NewInt(1)) -} - -func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { - if x.Int64() >= int64(len(c.Script)) || y.Int64() >= int64(len(c.Script)) { - return ethutil.NewValue(0) - } - - partial := c.Script[x.Int64() : x.Int64()+y.Int64()] - - return ethutil.NewValue(partial) -} - -func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) { - c.object.SetStorage(x, val) -} - -func (c *Closure) Address() []byte { - return c.object.Address() -} - -func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) { - c.Args = args - - ret, err := vm.RunClosure(c) - - return ret, c.UsedGas, err -} - -func (c *Closure) Return(ret []byte) []byte { - // Return the remaining gas to the caller - c.caller.ReturnGas(c.Gas, c.Price, c.State) - - return ret -} - -func (c *Closure) UseGas(gas *big.Int) bool { - if c.Gas.Cmp(gas) < 0 { - return false - } - - // Sub the amount of gas from the remaining - c.Gas.Sub(c.Gas, gas) - c.UsedGas.Add(c.UsedGas, gas) - - return true -} - -// Implement the caller interface -func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { - // Return the gas to the closure - c.Gas.Add(c.Gas, gas) - c.UsedGas.Sub(c.UsedGas, gas) -} - -func (c *Closure) Object() *StateObject { - return c.object -} - -func (c *Closure) Caller() ClosureRef { - return c.caller -} - -func (c *Closure) N() *big.Int { - return c.object.N() -} diff --git a/ethchain/stack.go b/ethchain/stack.go deleted file mode 100644 index a9fa2e522..000000000 --- a/ethchain/stack.go +++ /dev/null @@ -1,150 +0,0 @@ -package ethchain - -import ( - "fmt" - "math" - "math/big" -) - -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) Data() []*big.Int { - return st.data -} - -func (st *Stack) Len() int { - return len(st.data) -} - -func (st *Stack) Pop() *big.Int { - str := st.data[len(st.data)-1] - - copy(st.data[:len(st.data)-1], st.data[:len(st.data)-1]) - st.data = st.data[:len(st.data)-1] - - return str -} - -func (st *Stack) Popn() (*big.Int, *big.Int) { - ints := st.data[len(st.data)-2:] - - copy(st.data[:len(st.data)-2], st.data[:len(st.data)-2]) - st.data = st.data[:len(st.data)-2] - - return ints[0], ints[1] -} - -func (st *Stack) Peek() *big.Int { - str := st.data[len(st.data)-1] - - return str -} - -func (st *Stack) Peekn() (*big.Int, *big.Int) { - ints := st.data[:2] - - return ints[0], ints[1] -} - -func (st *Stack) Push(d *big.Int) { - st.data = append(st.data, new(big.Int).Set(d)) -} - -func (st *Stack) Get(amount *big.Int) []*big.Int { - // offset + size <= len(data) - length := big.NewInt(int64(len(st.data))) - if amount.Cmp(length) <= 0 { - start := new(big.Int).Sub(length, amount) - return st.data[start.Int64():length.Int64()] - } - - return nil -} - -func (st *Stack) Print() { - fmt.Println("### stack ###") - if len(st.data) > 0 { - for i, val := range st.data { - fmt.Printf("%-3d %v\n", i, val) - } - } else { - fmt.Println("-- empty --") - } - fmt.Println("#############") -} - -type Memory struct { - store []byte -} - -func (m *Memory) Set(offset, size int64, value []byte) { - totSize := offset + size - lenSize := int64(len(m.store) - 1) - if totSize > lenSize { - // Calculate the diff between the sizes - diff := totSize - lenSize - if diff > 0 { - // Create a new empty slice and append it - newSlice := make([]byte, diff-1) - // Resize slice - m.store = append(m.store, newSlice...) - } - } - copy(m.store[offset:offset+size], value) -} - -func (m *Memory) Resize(size uint64) { - if uint64(m.Len()) < size { - m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) - } -} - -func (m *Memory) Get(offset, size int64) []byte { - if len(m.store) > int(offset) { - end := int(math.Min(float64(len(m.store)), float64(offset+size))) - - return m.store[offset:end] - } - - return nil -} - -func (m *Memory) Len() int { - return len(m.store) -} - -func (m *Memory) Data() []byte { - return m.store -} - -func (m *Memory) Print() { - fmt.Printf("### mem %d bytes ###\n", len(m.store)) - if len(m.store) > 0 { - addr := 0 - for i := 0; i+32 <= len(m.store); i += 32 { - fmt.Printf("%03d: % x\n", addr, m.store[i:i+32]) - addr++ - } - } else { - fmt.Println("-- empty --") - } - fmt.Println("####################") -} diff --git a/ethchain/state.go b/ethchain/state.go deleted file mode 100644 index 3a9929ecc..000000000 --- a/ethchain/state.go +++ /dev/null @@ -1,250 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethtrie" - "github.com/ethereum/eth-go/ethutil" - "math/big" -) - -// States within the ethereum protocol are used to store anything -// within the merkle trie. States take care of caching and storing -// nested states. It's the general query interface to retrieve: -// * Contracts -// * Accounts -type State struct { - // The trie for this structure - trie *ethtrie.Trie - - stateObjects map[string]*StateObject - - manifest *Manifest -} - -// Create a new state from a given trie -func NewState(trie *ethtrie.Trie) *State { - return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} -} - -// Retrieve the balance from the given address or 0 if object not found -func (self *State) GetBalance(addr []byte) *big.Int { - stateObject := self.GetStateObject(addr) - if stateObject != nil { - return stateObject.Amount - } - - return ethutil.Big0 -} - -func (self *State) GetNonce(addr []byte) uint64 { - stateObject := self.GetStateObject(addr) - if stateObject != nil { - return stateObject.Nonce - } - - return 0 -} - -// -// Setting, updating & deleting state object methods -// - -// Update the given state object and apply it to state trie -func (self *State) UpdateStateObject(stateObject *StateObject) { - addr := stateObject.Address() - - ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) - - self.trie.Update(string(addr), string(stateObject.RlpEncode())) - - self.manifest.AddObjectChange(stateObject) -} - -// Delete the given state object and delete it from the state trie -func (self *State) DeleteStateObject(stateObject *StateObject) { - self.trie.Delete(string(stateObject.Address())) - - delete(self.stateObjects, string(stateObject.Address())) -} - -// Retrieve a state object given my the address. Nil if not found -func (self *State) GetStateObject(addr []byte) *StateObject { - addr = ethutil.Address(addr) - - stateObject := self.stateObjects[string(addr)] - if stateObject != nil { - return stateObject - } - - data := self.trie.Get(string(addr)) - if len(data) == 0 { - return nil - } - - stateObject = NewStateObjectFromBytes(addr, []byte(data)) - self.stateObjects[string(addr)] = stateObject - - return stateObject -} - -// Retrieve a state object or create a new state object if nil -func (self *State) GetOrNewStateObject(addr []byte) *StateObject { - stateObject := self.GetStateObject(addr) - if stateObject == nil { - stateObject = self.NewStateObject(addr) - } - - return stateObject -} - -// Create a state object whether it exist in the trie or not -func (self *State) NewStateObject(addr []byte) *StateObject { - statelogger.Infof("(+) %x\n", addr) - - stateObject := NewStateObject(addr) - self.stateObjects[string(addr)] = stateObject - - return stateObject -} - -// Deprecated -func (self *State) GetAccount(addr []byte) *StateObject { - return self.GetOrNewStateObject(addr) -} - -// -// Setting, copying of the state methods -// - -func (s *State) Cmp(other *State) bool { - return s.trie.Cmp(other.trie) -} - -func (self *State) Copy() *State { - if self.trie != nil { - state := NewState(self.trie.Copy()) - for k, stateObject := range self.stateObjects { - state.stateObjects[k] = stateObject.Copy() - } - - return state - } - - return nil -} - -func (self *State) Set(state *State) { - if state == nil { - panic("Tried setting 'state' to nil through 'Set'") - } - - self.trie = state.trie - self.stateObjects = state.stateObjects -} - -func (s *State) Root() interface{} { - return s.trie.Root -} - -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, stateObject := range s.stateObjects { - if stateObject.state == nil { - continue - } - - //stateObject.state.Reset() - stateObject.Reset() - } - - s.Empty() -} - -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, stateObject := range s.stateObjects { - //s.UpdateStateObject(stateObject) - - if stateObject.state == nil { - continue - } - - stateObject.state.Sync() - } - - s.trie.Sync() - - s.Empty() -} - -func (self *State) Empty() { - self.stateObjects = make(map[string]*StateObject) -} - -func (self *State) Update() { - for _, stateObject := range self.stateObjects { - if stateObject.remove { - self.DeleteStateObject(stateObject) - } else { - stateObject.Sync() - - self.UpdateStateObject(stateObject) - } - } - - // FIXME trie delete is broken - valid, t2 := ethtrie.ParanoiaCheck(self.trie) - if !valid { - statelogger.Infof("Warn: PARANOIA: Different state root during copy %x vs %x\n", self.trie.Root, t2.Root) - - self.trie = t2 - } -} - -// Debug stuff -func (self *State) CreateOutputForDiff() { - for _, stateObject := range self.stateObjects { - stateObject.CreateOutputForDiff() - } -} - -// Object manifest -// -// The object manifest is used to keep changes to the state so we can keep track of the changes -// that occurred during a state transitioning phase. -type Manifest struct { - // XXX These will be handy in the future. Not important for now. - objectAddresses map[string]bool - storageAddresses map[string]map[string]bool - - objectChanges map[string]*StateObject - storageChanges map[string]map[string]*big.Int -} - -func NewManifest() *Manifest { - m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} - m.Reset() - - return m -} - -func (m *Manifest) Reset() { - m.objectChanges = make(map[string]*StateObject) - m.storageChanges = make(map[string]map[string]*big.Int) -} - -func (m *Manifest) AddObjectChange(stateObject *StateObject) { - m.objectChanges[string(stateObject.Address())] = stateObject -} - -func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { - if m.storageChanges[string(stateObject.Address())] == nil { - m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) - } - - m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage -} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8dc88d7c3..9408cf331 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - _ "github.com/ethereum/eth-go/ethtrie" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "math/big" @@ -50,8 +50,6 @@ type StateManager struct { mutex sync.Mutex // Canonical block chain bc *BlockChain - // Stack for processing contracts - stack *Stack // non-persistent key/value memory storage mem map[string]*big.Int // Proof of work used for validating @@ -62,10 +60,10 @@ type StateManager struct { // Transiently state. The trans state isn't ever saved, validated and // it could be used for setting account nonces without effecting // the main states. - transState *State + transState *ethstate.State // Mining state. The mining state is used purely and solely by the mining // operation. - miningState *State + miningState *ethstate.State // The last attempted block is mainly used for debugging purposes // This does not have to be a valid block and will be set during @@ -75,7 +73,6 @@ type StateManager struct { func NewStateManager(ethereum EthManager) *StateManager { sm := &StateManager{ - stack: NewStack(), mem: make(map[string]*big.Int), Pow: &EasyPow{}, Ethereum: ethereum, @@ -87,19 +84,19 @@ func NewStateManager(ethereum EthManager) *StateManager { return sm } -func (sm *StateManager) CurrentState() *State { +func (sm *StateManager) CurrentState() *ethstate.State { return sm.Ethereum.BlockChain().CurrentBlock.State() } -func (sm *StateManager) TransState() *State { +func (sm *StateManager) TransState() *ethstate.State { return sm.transState } -func (sm *StateManager) MiningState() *State { +func (sm *StateManager) MiningState() *ethstate.State { return sm.miningState } -func (sm *StateManager) NewMiningState() *State { +func (sm *StateManager) NewMiningState() *ethstate.State { sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy() return sm.miningState @@ -109,7 +106,7 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (self *StateManager) ProcessTransactions(coinbase *StateObject, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { +func (self *StateManager) ProcessTransactions(coinbase *ethstate.StateObject, state *ethstate.State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { var ( receipts Receipts handled, unhandled Transactions @@ -225,7 +222,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { } if !block.State().Cmp(state) { - err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) return } @@ -242,7 +239,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) - state.manifest.Reset() + state.Manifest().Reset() } sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) @@ -255,7 +252,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return nil } -func (sm *StateManager) ApplyDiff(state *State, parent, block *Block) (receipts Receipts, err error) { +func (sm *StateManager) ApplyDiff(state *ethstate.State, parent, block *Block) (receipts Receipts, err error) { coinbase := state.GetOrNewStateObject(block.Coinbase) coinbase.SetGasPool(block.CalcGasLimit(parent)) @@ -340,7 +337,7 @@ func CalculateUncleReward(block *Block) *big.Int { return UncleReward } -func (sm *StateManager) AccumelateRewards(state *State, block *Block) error { +func (sm *StateManager) AccumelateRewards(state *ethstate.State, block *Block) error { // Get the account associated with the coinbase account := state.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address @@ -364,14 +361,14 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) notifyChanges(state *State) { - for addr, stateObject := range state.manifest.objectChanges { +func (sm *StateManager) notifyChanges(state *ethstate.State) { + for addr, stateObject := range state.Manifest().ObjectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range state.manifest.storageChanges { + for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { for addr, value := range mappedObjects { - sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } } } diff --git a/ethchain/state_object.go b/ethchain/state_object.go deleted file mode 100644 index 184609015..000000000 --- a/ethchain/state_object.go +++ /dev/null @@ -1,368 +0,0 @@ -package ethchain - -import ( - "fmt" - "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethtrie" - "github.com/ethereum/eth-go/ethutil" - "math/big" - "strings" -) - -type Code []byte - -func (self Code) String() string { - return strings.Join(Disassemble(self), " ") -} - -type Storage map[string]*ethutil.Value - -func (self Storage) Copy() Storage { - cpy := make(Storage) - for key, value := range self { - // XXX Do we need a 'value' copy or is this sufficient? - cpy[key] = value - } - - return cpy -} - -type StateObject struct { - // Address of the object - address []byte - // Shared attributes - Amount *big.Int - ScriptHash []byte - Nonce uint64 - // Contract related attributes - state *State - script Code - initScript Code - - storage Storage - - // Total gas pool is the total amount of gas currently - // left if this object is the coinbase. Gas is directly - // purchased of the coinbase. - gasPool *big.Int - - // Mark for deletion - // When an object is marked for deletion it will be delete from the trie - // during the "update" phase of the state transition - remove bool -} - -func (self *StateObject) Reset() { - self.storage = make(Storage) - self.state.Reset() -} - -// Converts an transaction in to a state object -func MakeContract(tx *Transaction, state *State) *StateObject { - // Create contract if there's no recipient - if tx.IsContract() { - addr := tx.CreationAddress() - - contract := state.NewStateObject(addr) - contract.initScript = tx.Data - contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) - - return contract - } - - return nil -} - -func NewStateObject(addr []byte) *StateObject { - // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. - address := ethutil.Address(addr) - - object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} - object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) - object.storage = make(Storage) - object.gasPool = new(big.Int) - - return object -} - -func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { - contract := NewStateObject(address) - contract.Amount = Amount - contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) - - return contract -} - -func NewStateObjectFromBytes(address, data []byte) *StateObject { - object := &StateObject{address: address} - object.RlpDecode(data) - - return object -} - -func (self *StateObject) MarkForDeletion() { - self.remove = true - statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) -} - -func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { - return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) -} - -func (c *StateObject) SetAddr(addr []byte, value interface{}) { - c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) -} - -func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value { - return self.getStorage(key.Bytes()) -} -func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) { - self.setStorage(key.Bytes(), value) -} - -func (self *StateObject) getStorage(k []byte) *ethutil.Value { - key := ethutil.LeftPadBytes(k, 32) - - value := self.storage[string(key)] - if value == nil { - value = self.GetAddr(key) - - if !value.IsNil() { - self.storage[string(key)] = value - } - } - - return value - - //return self.GetAddr(key) -} - -func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { - key := ethutil.LeftPadBytes(k, 32) - self.storage[string(key)] = value.Copy() - - /* - if value.BigInt().Cmp(ethutil.Big0) == 0 { - self.state.trie.Delete(string(key)) - return - } - - self.SetAddr(key, value) - */ -} - -// Iterate over each storage address and yield callback -func (self *StateObject) EachStorage(cb ethtrie.EachCallback) { - // First loop over the uncommit/cached values in storage - for key, value := range self.storage { - // XXX Most iterators Fns as it stands require encoded values - encoded := ethutil.NewValue(value.Encode()) - cb(key, encoded) - } - - it := self.state.trie.NewIterator() - it.Each(func(key string, value *ethutil.Value) { - // If it's cached don't call the callback. - if self.storage[key] == nil { - cb(key, value) - } - }) -} - -func (self *StateObject) Sync() { - /* - fmt.Println("############# BEFORE ################") - self.state.EachStorage(func(key string, value *ethutil.Value) { - fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) - }) - fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) - fmt.Println("#####################################") - */ - for key, value := range self.storage { - if value.Len() == 0 { // value.BigInt().Cmp(ethutil.Big0) == 0 { - //data := self.getStorage([]byte(key)) - //fmt.Printf("deleting %x %x 0x%x\n", self.Address(), []byte(key), data) - self.state.trie.Delete(string(key)) - continue - } - - self.SetAddr([]byte(key), value) - } - - valid, t2 := ethtrie.ParanoiaCheck(self.state.trie) - if !valid { - statelogger.Infof("Warn: PARANOIA: Different state storage root during copy %x vs %x\n", self.state.trie.Root, t2.Root) - - self.state.trie = t2 - } - - /* - fmt.Println("############# AFTER ################") - self.state.EachStorage(func(key string, value *ethutil.Value) { - fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) - }) - */ - //fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) -} - -func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { - if int64(len(c.script)-1) < pc.Int64() { - return ethutil.NewValue(0) - } - - return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) -} - -func (c *StateObject) AddAmount(amount *big.Int) { - c.SetAmount(new(big.Int).Add(c.Amount, amount)) - - statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) -} - -func (c *StateObject) SubAmount(amount *big.Int) { - c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - - statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) -} - -func (c *StateObject) SetAmount(amount *big.Int) { - c.Amount = amount -} - -// -// Gas setters and getters -// - -// Return the gas back to the origin. Used by the Virtual machine or Closures -func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) {} -func (c *StateObject) ConvertGas(gas, price *big.Int) error { - total := new(big.Int).Mul(gas, price) - if total.Cmp(c.Amount) > 0 { - return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total) - } - - c.SubAmount(total) - - return nil -} - -func (self *StateObject) SetGasPool(gasLimit *big.Int) { - self.gasPool = new(big.Int).Set(gasLimit) - - statelogger.DebugDetailf("%x: fuel (+ %v)", self.Address(), self.gasPool) -} - -func (self *StateObject) BuyGas(gas, price *big.Int) error { - if self.gasPool.Cmp(gas) < 0 { - return GasLimitError(self.gasPool, gas) - } - - rGas := new(big.Int).Set(gas) - rGas.Mul(rGas, price) - - self.AddAmount(rGas) - - return nil -} - -func (self *StateObject) RefundGas(gas, price *big.Int) { - self.gasPool.Add(self.gasPool, gas) - - rGas := new(big.Int).Set(gas) - rGas.Mul(rGas, price) - - self.Amount.Sub(self.Amount, rGas) -} - -func (self *StateObject) Copy() *StateObject { - stateObject := NewStateObject(self.Address()) - stateObject.Amount.Set(self.Amount) - stateObject.ScriptHash = ethutil.CopyBytes(self.ScriptHash) - stateObject.Nonce = self.Nonce - if self.state != nil { - stateObject.state = self.state.Copy() - } - stateObject.script = ethutil.CopyBytes(self.script) - stateObject.initScript = ethutil.CopyBytes(self.initScript) - stateObject.storage = self.storage.Copy() - stateObject.gasPool.Set(self.gasPool) - - return stateObject -} - -func (self *StateObject) Set(stateObject *StateObject) { - *self = *stateObject -} - -// -// Attribute accessors -// - -func (c *StateObject) State() *State { - return c.state -} - -func (c *StateObject) N() *big.Int { - return big.NewInt(int64(c.Nonce)) -} - -// Returns the address of the contract/account -func (c *StateObject) Address() []byte { - return c.address -} - -// Returns the main script body -func (c *StateObject) Script() Code { - return c.script -} - -// Returns the initialization script -func (c *StateObject) Init() Code { - return c.initScript -} - -// Debug stuff -func (self *StateObject) CreateOutputForDiff() { - fmt.Printf("%x %x %x %x\n", self.Address(), self.state.Root(), self.Amount.Bytes(), self.Nonce) - self.EachStorage(func(addr string, value *ethutil.Value) { - fmt.Printf("%x %x\n", addr, value.Bytes()) - }) -} - -// -// Encoding -// - -// State object encoding methods -func (c *StateObject) RlpEncode() []byte { - var root interface{} - if c.state != nil { - root = c.state.trie.Root - } else { - root = "" - } - - return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethcrypto.Sha3Bin(c.script)}) -} - -func (c *StateObject) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - c.Nonce = decoder.Get(0).Uint() - c.Amount = decoder.Get(1).BigInt() - c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) - c.storage = make(map[string]*ethutil.Value) - c.gasPool = new(big.Int) - - c.ScriptHash = decoder.Get(3).Bytes() - - c.script, _ = ethutil.Config.Db.Get(c.ScriptHash) -} - -// Storage change object. Used by the manifest for notifying changes to -// the sub channels. -type StorageState struct { - StateAddress []byte - Address []byte - Value *big.Int -} diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go deleted file mode 100644 index 2588100d0..000000000 --- a/ethchain/state_object_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package ethchain - -import ( - "fmt" - "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/ethutil" - "math/big" - "testing" -) - -func TestSync(t *testing.T) { - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) - - contract.script = []byte{42} - - state.UpdateStateObject(contract) - state.Sync() - - object := state.GetStateObject([]byte("aa")) - if len(object.Script()) == 0 { - t.Fail() - } -} - -func TestObjectGet(t *testing.T) { - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") - - db, _ := ethdb.NewMemDatabase() - ethutil.Config.Db = db - - state := NewState(ethutil.NewTrie(db, "")) - - contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) - state.UpdateStateObject(contract) - - contract = state.GetStateObject([]byte("aa")) - contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello")) - o := contract.GetMem(big.NewInt(0)) - fmt.Println(o) - - state.UpdateStateObject(contract) - contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello00")) - - contract = state.GetStateObject([]byte("aa")) - o = contract.GetMem(big.NewInt(0)) - fmt.Println("after", o) -} diff --git a/ethchain/state_test.go b/ethchain/state_test.go deleted file mode 100644 index 95be0f373..000000000 --- a/ethchain/state_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/ethutil" - "testing" -) - -func TestSnapshot(t *testing.T) { - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - stateObject := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) - state.UpdateStateObject(stateObject) - stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42)) - - snapshot := state.Copy() - - stateObject = state.GetStateObject([]byte("aa")) - stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(43)) - - state.Set(snapshot) - - stateObject = state.GetStateObject([]byte("aa")) - if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) { - t.Error("Expected storage 0 to be 42") - } -} diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8ed528c9f..a03a3a94a 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,6 +2,10 @@ package ethchain import ( "fmt" + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethtrie" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethvm" "math/big" ) @@ -27,17 +31,17 @@ type StateTransition struct { gas, gasPrice *big.Int value *big.Int data []byte - state *State + state *ethstate.State block *Block - cb, rec, sen *StateObject + cb, rec, sen *ethstate.StateObject } -func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { +func NewStateTransition(coinbase *ethstate.StateObject, tx *Transaction, state *ethstate.State, block *Block) *StateTransition { return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} } -func (self *StateTransition) Coinbase() *StateObject { +func (self *StateTransition) Coinbase() *ethstate.StateObject { if self.cb != nil { return self.cb } @@ -45,7 +49,7 @@ func (self *StateTransition) Coinbase() *StateObject { self.cb = self.state.GetOrNewStateObject(self.coinbase) return self.cb } -func (self *StateTransition) Sender() *StateObject { +func (self *StateTransition) Sender() *ethstate.StateObject { if self.sen != nil { return self.sen } @@ -54,7 +58,7 @@ func (self *StateTransition) Sender() *StateObject { return self.sen } -func (self *StateTransition) Receiver() *StateObject { +func (self *StateTransition) Receiver() *ethstate.StateObject { if self.tx != nil && self.tx.CreatesContract() { return nil } @@ -67,7 +71,7 @@ func (self *StateTransition) Receiver() *StateObject { return self.rec } -func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject { +func (self *StateTransition) MakeStateObject(state *ethstate.State, tx *Transaction) *ethstate.StateObject { contract := MakeContract(tx, state) return contract @@ -154,7 +158,7 @@ func (self *StateTransition) TransitionState() (err error) { var ( tx = self.tx sender = self.Sender() - receiver *StateObject + receiver *ethstate.StateObject ) defer self.RefundGas() @@ -163,13 +167,13 @@ func (self *StateTransition) TransitionState() (err error) { sender.Nonce += 1 // Transaction gas - if err = self.UseGas(GasTx); err != nil { + if err = self.UseGas(ethvm.GasTx); err != nil { return } // Pay data gas dataPrice := big.NewInt(int64(len(self.data))) - dataPrice.Mul(dataPrice, GasData) + dataPrice.Mul(dataPrice, ethvm.GasData) if err = self.UseGas(dataPrice); err != nil { return } @@ -178,7 +182,7 @@ func (self *StateTransition) TransitionState() (err error) { return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) } - var snapshot *State + var snapshot *ethstate.State // If the receiver is nil it's a contract (\0*32). if tx.CreatesContract() { // Subtract the (irreversible) amount from the senders account @@ -220,10 +224,10 @@ func (self *StateTransition) TransitionState() (err error) { return fmt.Errorf("Error during init execution %v", err) } - receiver.script = code + receiver.Code = code } else { - if len(receiver.Script()) > 0 { - _, err = self.Eval(receiver.Script(), receiver, "code") + if len(receiver.Code) > 0 { + _, err = self.Eval(receiver.Code, receiver, "code") if err != nil { self.state.Set(snapshot) @@ -235,7 +239,7 @@ func (self *StateTransition) TransitionState() (err error) { return } -func (self *StateTransition) transferValue(sender, receiver *StateObject) error { +func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObject) error { if sender.Amount.Cmp(self.value) < 0 { return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) } @@ -248,34 +252,61 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return nil } -func (self *StateTransition) Eval(script []byte, context *StateObject, typ string) (ret []byte, err error) { +func (self *StateTransition) Eval(script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) { var ( - block = self.block - initiator = self.Sender() - state = self.state + transactor = self.Sender() + state = self.state + env = NewEnv(state, self.tx, self.block) + callerClosure = ethvm.NewClosure(transactor, context, script, self.gas, self.gasPrice) ) - closure := NewClosure(initiator, context, script, state, self.gas, self.gasPrice) - vm := NewVm(state, nil, RuntimeVars{ - Origin: initiator.Address(), - Block: block, - BlockNumber: block.Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: self.value, - }) + vm := ethvm.New(env) vm.Verbose = true vm.Fn = typ - ret, err = Call(vm, closure, self.data) + ret, _, err = callerClosure.Call(vm, self.tx.Data) + + /* + closure := NewClosure(initiator, context, script, state, self.gas, self.gasPrice) + vm := NewVm(state, nil, RuntimeVars{ + Origin: initiator.Address(), + Block: block, + BlockNumber: block.Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: self.value, + }) + vm.Verbose = true + vm.Fn = typ + + ret, err = Call(vm, closure, self.data) + */ return } -func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) { +/* +func Call(vm *eth.Vm, closure *Closure, data []byte) (ret []byte, err error) { ret, _, err = closure.Call(vm, data) return } +*/ + +// Converts an transaction in to a state object +func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject { + // Create contract if there's no recipient + if tx.IsContract() { + addr := tx.CreationAddress() + + contract := state.NewStateObject(addr) + contract.InitCode = tx.Data + contract.State = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) + + return contract + } + + return nil +} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 6ab8d83d9..21c6ea3de 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -5,6 +5,7 @@ import ( "container/list" "fmt" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethwire" "math/big" "sync" @@ -252,7 +253,7 @@ func (pool *TxPool) CurrentTransactions() []*Transaction { return txList } -func (pool *TxPool) RemoveInvalid(state *State) { +func (pool *TxPool) RemoveInvalid(state *ethstate.State) { for e := pool.pool.Front(); e != nil; e = e.Next() { tx := e.Value.(*Transaction) sender := state.GetAccount(tx.Sender()) diff --git a/ethchain/vm.go b/ethchain/vm.go deleted file mode 100644 index 4cbb4e1c4..000000000 --- a/ethchain/vm.go +++ /dev/null @@ -1,843 +0,0 @@ -package ethchain - -import ( - "fmt" - "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethutil" - "math" - "math/big" -) - -var vmlogger = ethlog.NewLogger("VM") - -var ( - GasStep = big.NewInt(1) - GasSha = big.NewInt(20) - GasSLoad = big.NewInt(20) - GasSStore = big.NewInt(100) - GasBalance = big.NewInt(20) - GasCreate = big.NewInt(100) - GasCall = big.NewInt(20) - GasMemory = big.NewInt(1) - GasData = big.NewInt(5) - GasTx = big.NewInt(500) - - LogTyPretty byte = 0x1 - LogTyDiff byte = 0x2 -) - -type Debugger interface { - BreakHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool - StepHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool - BreakPoints() []int64 - SetCode(byteCode []byte) -} - -type Vm struct { - // Stack for processing contracts - stack *Stack - // non-persistent key/value memory storage - mem map[string]*big.Int - - vars RuntimeVars - - state *State - - stateManager *StateManager - - Verbose bool - - logTy byte - logStr string - - err error - - // Debugging - Dbg Debugger - - BreakPoints []int64 - Stepping bool - Fn string -} - -type RuntimeVars struct { - Origin []byte - Block *Block - BlockNumber *big.Int - PrevHash []byte - Coinbase []byte - Time int64 - Diff *big.Int - TxData []string - Value *big.Int -} - -func (self *Vm) Printf(format string, v ...interface{}) *Vm { - if self.Verbose && self.logTy == LogTyPretty { - self.logStr += fmt.Sprintf(format, v...) - } - - return self -} - -func (self *Vm) Endl() *Vm { - if self.Verbose && self.logTy == LogTyPretty { - vmlogger.Debugln(self.logStr) - self.logStr = "" - } - - return self -} - -func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { - lt := LogTyPretty - if ethutil.Config.Diff { - lt = LogTyDiff - } - - return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: lt} -} - -var Pow256 = ethutil.BigPow(2, 256) - -var isRequireError = false - -func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { - // Recover from any require exception - defer func() { - if r := recover(); r != nil { - ret = closure.Return(nil) - err = fmt.Errorf("%v", r) - vmlogger.Errorln("vm err", err) - } - }() - - // Debug hook - if vm.Dbg != nil { - vm.Dbg.SetCode(closure.Script) - } - - // Don't bother with the execution if there's no code. - if len(closure.Script) == 0 { - return closure.Return(nil), nil - } - - vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.Address(), closure.Gas, closure.Args) - - var ( - op OpCode - - mem = &Memory{} - stack = NewStack() - pc = big.NewInt(0) - step = 0 - prevStep = 0 - require = func(m int) { - if stack.Len() < m { - isRequireError = true - panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) - } - } - ) - - for { - prevStep = step - // The base for all big integer arithmetic - base := new(big.Int) - - step++ - // Get the memory location of pc - val := closure.Get(pc) - // Get the opcode (it must be an opcode!) - op = OpCode(val.Uint()) - - // XXX Leave this Println intact. Don't change this to the log system. - // Used for creating diffs between implementations - if vm.logTy == LogTyDiff { - switch op { - case STOP, RETURN, SUICIDE: - closure.object.Sync() - closure.object.EachStorage(func(key string, value *ethutil.Value) { - value.Decode() - fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) - }) - } - - b := pc.Bytes() - if len(b) == 0 { - b = []byte{0} - } - - fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) - } - - gas := new(big.Int) - addStepGasUsage := func(amount *big.Int) { - if amount.Cmp(ethutil.Big0) >= 0 { - gas.Add(gas, amount) - } - } - - addStepGasUsage(GasStep) - - var newMemSize uint64 = 0 - switch op { - case STOP: - gas.Set(ethutil.Big0) - case SUICIDE: - gas.Set(ethutil.Big0) - case SLOAD: - gas.Set(GasSLoad) - case SSTORE: - var mult *big.Int - y, x := stack.Peekn() - val := closure.GetStorage(x) - if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { - mult = ethutil.Big2 - } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - mult = ethutil.Big0 - } else { - mult = ethutil.Big1 - } - gas = new(big.Int).Mul(mult, GasSStore) - case BALANCE: - gas.Set(GasBalance) - case MSTORE: - require(2) - newMemSize = stack.Peek().Uint64() + 32 - case MLOAD: - require(1) - - newMemSize = stack.Peek().Uint64() + 32 - case MSTORE8: - require(2) - newMemSize = stack.Peek().Uint64() + 1 - case RETURN: - require(2) - - newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() - case SHA3: - require(2) - - gas.Set(GasSha) - - newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() - case CALLDATACOPY: - require(3) - - newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() - case CODECOPY: - require(3) - - newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() - case CALL: - require(7) - gas.Set(GasCall) - addStepGasUsage(stack.data[stack.Len()-1]) - - x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() - y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() - - newMemSize = uint64(math.Max(float64(x), float64(y))) - case CREATE: - require(3) - gas.Set(GasCreate) - - newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() - } - - newMemSize = (newMemSize + 31) / 32 * 32 - if newMemSize > uint64(mem.Len()) { - m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 - addStepGasUsage(big.NewInt(int64(m))) - } - - if !closure.UseGas(gas) { - err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas) - - closure.UseGas(closure.Gas) - - return closure.Return(nil), err - } - - vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - vm.Printf(" (g) %-3v (%v)", gas, closure.Gas) - - mem.Resize(newMemSize) - - switch op { - case LOG: - stack.Print() - mem.Print() - // 0x20 range - case ADD: - require(2) - x, y := stack.Popn() - vm.Printf(" %v + %v", y, x) - - base.Add(y, x) - - vm.Printf(" = %v", base) - // Pop result back on the stack - stack.Push(base) - case SUB: - require(2) - x, y := stack.Popn() - vm.Printf(" %v - %v", y, x) - - base.Sub(y, x) - - vm.Printf(" = %v", base) - // Pop result back on the stack - stack.Push(base) - case MUL: - require(2) - x, y := stack.Popn() - vm.Printf(" %v * %v", y, x) - - base.Mul(y, x) - - vm.Printf(" = %v", base) - // Pop result back on the stack - stack.Push(base) - case DIV: - require(2) - x, y := stack.Popn() - vm.Printf(" %v / %v", y, x) - - base.Div(y, x) - - vm.Printf(" = %v", base) - // Pop result back on the stack - stack.Push(base) - case SDIV: - require(2) - x, y := 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 - stack.Push(z) - case MOD: - require(2) - x, y := stack.Popn() - - vm.Printf(" %v %% %v", y, x) - - base.Mod(y, x) - - vm.Printf(" = %v", base) - stack.Push(base) - case SMOD: - require(2) - x, y := 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 - stack.Push(z) - case EXP: - require(2) - x, y := stack.Popn() - - vm.Printf(" %v ** %v", y, x) - - base.Exp(y, x, Pow256) - - vm.Printf(" = %v", base) - - stack.Push(base) - case NEG: - require(1) - base.Sub(Pow256, stack.Pop()) - stack.Push(base) - case LT: - require(2) - x, y := stack.Popn() - vm.Printf(" %v < %v", y, x) - // x < y - if y.Cmp(x) < 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - case GT: - require(2) - x, y := stack.Popn() - vm.Printf(" %v > %v", y, x) - - // x > y - if y.Cmp(x) > 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - - case SLT: - require(2) - x, y := stack.Popn() - vm.Printf(" %v < %v", y, x) - // x < y - if y.Cmp(x) < 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - case SGT: - require(2) - x, y := stack.Popn() - vm.Printf(" %v > %v", y, x) - - // x > y - if y.Cmp(x) > 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - - case EQ: - require(2) - x, y := stack.Popn() - vm.Printf(" %v == %v", y, x) - - // x == y - if x.Cmp(y) == 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - case NOT: - require(1) - x := stack.Pop() - if x.Cmp(ethutil.BigFalse) > 0 { - stack.Push(ethutil.BigFalse) - } else { - stack.Push(ethutil.BigTrue) - } - - // 0x10 range - case AND: - require(2) - x, y := stack.Popn() - vm.Printf(" %v & %v", y, x) - - stack.Push(base.And(y, x)) - case OR: - require(2) - x, y := stack.Popn() - vm.Printf(" %v | %v", y, x) - - stack.Push(base.Or(y, x)) - case XOR: - require(2) - x, y := stack.Popn() - vm.Printf(" %v ^ %v", y, x) - - stack.Push(base.Xor(y, x)) - case BYTE: - require(2) - val, th := stack.Popn() - if th.Cmp(big.NewInt(32)) < 0 && th.Cmp(big.NewInt(int64(len(val.Bytes())))) < 0 { - byt := big.NewInt(int64(val.Bytes()[th.Int64()])) - stack.Push(byt) - - vm.Printf(" => 0x%x", byt.Bytes()) - } else { - stack.Push(ethutil.BigFalse) - } - - // 0x20 range - case SHA3: - require(2) - size, offset := stack.Popn() - data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) - - stack.Push(ethutil.BigD(data)) - - vm.Printf(" => %x", data) - // 0x30 range - case ADDRESS: - stack.Push(ethutil.BigD(closure.Address())) - - vm.Printf(" => %x", closure.Address()) - case BALANCE: - require(1) - - addr := stack.Pop().Bytes() - balance := vm.state.GetBalance(addr) - - stack.Push(balance) - - vm.Printf(" => %v (%x)", balance, addr) - case ORIGIN: - stack.Push(ethutil.BigD(vm.vars.Origin)) - - vm.Printf(" => %x", vm.vars.Origin) - case CALLER: - caller := closure.caller.Address() - stack.Push(ethutil.BigD(caller)) - - vm.Printf(" => %x", caller) - case CALLVALUE: - stack.Push(vm.vars.Value) - - vm.Printf(" => %v", vm.vars.Value) - case CALLDATALOAD: - require(1) - var ( - offset = stack.Pop() - data = make([]byte, 32) - lenData = big.NewInt(int64(len(closure.Args))) - ) - - if lenData.Cmp(offset) >= 0 { - length := new(big.Int).Add(offset, ethutil.Big32) - length = ethutil.BigMin(length, lenData) - - copy(data, closure.Args[offset.Int64():length.Int64()]) - } - - vm.Printf(" => 0x%x", data) - - stack.Push(ethutil.BigD(data)) - case CALLDATASIZE: - l := int64(len(closure.Args)) - stack.Push(big.NewInt(l)) - - vm.Printf(" => %d", l) - case CALLDATACOPY: - var ( - size = int64(len(closure.Args)) - mOff = stack.Pop().Int64() - cOff = stack.Pop().Int64() - l = stack.Pop().Int64() - ) - - if cOff > size { - cOff = 0 - l = 0 - } else if cOff+l > size { - l = 0 - } - - code := closure.Args[cOff : cOff+l] - - mem.Set(mOff, l, code) - case CODESIZE: - l := big.NewInt(int64(len(closure.Script))) - stack.Push(l) - - vm.Printf(" => %d", l) - case CODECOPY: - var ( - size = int64(len(closure.Script)) - mOff = stack.Pop().Int64() - cOff = stack.Pop().Int64() - l = stack.Pop().Int64() - ) - - if cOff > size { - cOff = 0 - l = 0 - } else if cOff+l > size { - l = 0 - } - - code := closure.Script[cOff : cOff+l] - fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) - - mem.Set(mOff, l, code) - case GASPRICE: - stack.Push(closure.Price) - - // 0x40 range - case PREVHASH: - stack.Push(ethutil.BigD(vm.vars.PrevHash)) - case COINBASE: - stack.Push(ethutil.BigD(vm.vars.Coinbase)) - case TIMESTAMP: - stack.Push(big.NewInt(vm.vars.Time)) - case NUMBER: - stack.Push(vm.vars.BlockNumber) - case DIFFICULTY: - stack.Push(vm.vars.Diff) - case GASLIMIT: - // TODO - stack.Push(big.NewInt(0)) - - // 0x50 range - case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: - a := big.NewInt(int64(op) - int64(PUSH1) + 1) - pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, a) - val := ethutil.BigD(data.Bytes()) - // Push value to stack - stack.Push(val) - pc.Add(pc, a.Sub(a, big.NewInt(1))) - - step += int(op) - int(PUSH1) + 1 - - vm.Printf(" => 0x%x", data.Bytes()) - case POP: - require(1) - stack.Pop() - case DUP: - require(1) - stack.Push(stack.Peek()) - - vm.Printf(" => 0x%x", stack.Peek().Bytes()) - case SWAP: - require(2) - x, y := stack.Popn() - stack.Push(y) - stack.Push(x) - case MLOAD: - require(1) - offset := stack.Pop() - val := ethutil.BigD(mem.Get(offset.Int64(), 32)) - stack.Push(val) - - vm.Printf(" => 0x%x", val.Bytes()) - case MSTORE: // Store the value at stack top-1 in to memory at location stack top - require(2) - // Pop value of the stack - val, mStart := stack.Popn() - mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) - - vm.Printf(" => 0x%x", val) - case MSTORE8: - require(2) - val, mStart := stack.Popn() - //base.And(val, new(big.Int).SetInt64(0xff)) - //mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) - mem.store[mStart.Int64()] = byte(val.Int64() & 0xff) - - vm.Printf(" => 0x%x", val) - case SLOAD: - require(1) - loc := stack.Pop() - val := closure.GetStorage(loc) - - stack.Push(val.BigInt()) - - vm.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) - case SSTORE: - require(2) - val, loc := stack.Popn() - closure.SetStorage(loc, ethutil.NewValue(val)) - - // Add the change to manifest - vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) - - vm.Printf(" {0x%x : 0x%x}", loc, val) - case JUMP: - require(1) - pc = stack.Pop() - // Reduce pc by one because of the increment that's at the end of this for loop - vm.Printf(" ~> %v", pc).Endl() - - continue - case JUMPI: - require(2) - cond, pos := stack.Popn() - if cond.Cmp(ethutil.BigTrue) >= 0 { - pc = pos - - vm.Printf(" ~> %v (t)", pc).Endl() - - continue - } else { - vm.Printf(" (f)") - } - case PC: - stack.Push(pc) - case MSIZE: - stack.Push(big.NewInt(int64(mem.Len()))) - - vm.Printf(" => %v", mem.Len()).Endl() - case GAS: - stack.Push(closure.Gas) - // 0x60 range - case CREATE: - require(3) - - var ( - err error - value = stack.Pop() - size, offset = stack.Popn() - - // Snapshot the current stack so we are able to - // revert back to it later. - snapshot = vm.state.Copy() - ) - - // Generate a new address - addr := ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()) - for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ { - ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()+i) - } - closure.object.Nonce++ - - vm.Printf(" (*) %x", addr).Endl() - - // Create a new contract - contract := vm.state.NewStateObject(addr) - if contract.Amount.Cmp(value) >= 0 { - closure.object.SubAmount(value) - contract.AddAmount(value) - - // Set the init script - initCode := mem.Get(offset.Int64(), size.Int64()) - //fmt.Printf("%x\n", initCode) - // Transfer all remaining gas to the new - // contract so it may run the init script - gas := new(big.Int).Set(closure.Gas) - closure.UseGas(closure.Gas) - - // Create the closure - c := NewClosure(closure, contract, initCode, vm.state, gas, closure.Price) - // Call the closure and set the return value as - // main script. - contract.script, err = Call(vm, c, nil) - } else { - err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) - } - - if err != nil { - stack.Push(ethutil.BigFalse) - - // Revert the state as it was before. - vm.state.Set(snapshot) - - vm.Printf("CREATE err %v", err) - } else { - stack.Push(ethutil.BigD(addr)) - vm.Printf("CREATE success") - } - vm.Endl() - - // Debug hook - if vm.Dbg != nil { - vm.Dbg.SetCode(closure.Script) - } - case CALL: - require(7) - - vm.Endl() - - gas := stack.Pop() - // Pop gas and value of the stack. - value, addr := stack.Popn() - // Pop input size and offset - inSize, inOffset := stack.Popn() - // Pop return size and offset - retSize, retOffset := stack.Popn() - - // Get the arguments from the memory - args := mem.Get(inOffset.Int64(), inSize.Int64()) - - if closure.object.Amount.Cmp(value) < 0 { - vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) - - closure.ReturnGas(gas, nil, nil) - - stack.Push(ethutil.BigFalse) - } else { - snapshot := vm.state.Copy() - - stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) - - closure.object.SubAmount(value) - stateObject.AddAmount(value) - - // Create a new callable closure - c := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, err := Call(vm, c, args) - if err != nil { - stack.Push(ethutil.BigFalse) - - vmlogger.Debugf("Closure execution failed. %v\n", err) - - vm.state.Set(snapshot) - } else { - stack.Push(ethutil.BigTrue) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) - } - - // Debug hook - if vm.Dbg != nil { - vm.Dbg.SetCode(closure.Script) - } - } - case RETURN: - require(2) - size, offset := stack.Popn() - ret := mem.Get(offset.Int64(), size.Int64()) - - vm.Printf(" => (%d) 0x%x", len(ret), ret).Endl() - - return closure.Return(ret), nil - case SUICIDE: - require(1) - - receiver := vm.state.GetOrNewStateObject(stack.Pop().Bytes()) - - receiver.AddAmount(closure.object.Amount) - - closure.object.MarkForDeletion() - - fallthrough - case STOP: // Stop the closure - vm.Endl() - - return closure.Return(nil), nil - default: - vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) - fmt.Println(Code(closure.Script)) - - return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) - } - - pc.Add(pc, ethutil.Big1) - - vm.Endl() - - if vm.Dbg != nil { - for _, instrNo := range vm.Dbg.BreakPoints() { - if pc.Cmp(big.NewInt(instrNo)) == 0 { - vm.Stepping = true - - if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) { - return nil, nil - } - } else if vm.Stepping { - if !vm.Dbg.StepHook(prevStep, op, mem, stack, closure.Object()) { - return nil, nil - } - } - } - } - - } -} diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go new file mode 100644 index 000000000..711cfbe9f --- /dev/null +++ b/ethchain/vm_env.go @@ -0,0 +1,28 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethstate" + "math/big" +) + +type VMEnv struct { + state *ethstate.State + block *Block + tx *Transaction +} + +func NewEnv(state *ethstate.State, tx *Transaction, block *Block) *VMEnv { + return &VMEnv{ + state: state, + block: block, + } +} + +func (self *VMEnv) Origin() []byte { return self.tx.Sender() } +func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number } +func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } +func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } +func (self *VMEnv) Time() int64 { return self.block.Time } +func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } +func (self *VMEnv) Value() *big.Int { return self.tx.Value } +func (self *VMEnv) State() *ethstate.State { return self.state } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go deleted file mode 100644 index c8023cd79..000000000 --- a/ethchain/vm_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package ethchain - -import ( - _ "bytes" - "fmt" - "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/ethutil" - "math/big" - "testing" -) - -func TestRun4(t *testing.T) { - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - callerScript, err := ethutil.Compile(` - this.store[this.origin()] = 10**20 - hello := "world" - - return lambda { - big to = this.data[0] - big from = this.origin() - big value = this.data[1] - - if this.store[from] >= value { - this.store[from] = this.store[from] - value - this.store[to] = this.store[to] + value - } - } - `) - if err != nil { - fmt.Println(err) - } - fmt.Println(Disassemble(callerScript)) - - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript) - callerTx.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) - - // Contract addr as test address - gas := big.NewInt(1000) - gasPrice := big.NewInt(10) - account := NewAccount(ContractAddr, big.NewInt(10000000)) - fmt.Println("account.Amount =", account.Amount) - c := MakeContract(callerTx, state) - e := account.ConvertGas(gas, gasPrice) - if e != nil { - fmt.Println(err) - } - fmt.Println("account.Amount =", account.Amount) - callerClosure := NewClosure(account, c, callerScript, state, gas, gasPrice) - - vm := NewVm(state, nil, RuntimeVars{ - Origin: account.Address(), - BlockNumber: big.NewInt(1), - PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - Time: 1, - Diff: big.NewInt(256), - }) - var ret []byte - ret, _, e = callerClosure.Call(vm, nil, nil) - if e != nil { - fmt.Println("error", e) - } - fmt.Println(ret) -} -- cgit v1.2.3 From cbd71ef8f590bf7e97beaa81256d188c21587ef9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Jul 2014 12:10:18 +0200 Subject: Add Tx --- ethchain/vm_env.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go index 711cfbe9f..ddead77fd 100644 --- a/ethchain/vm_env.go +++ b/ethchain/vm_env.go @@ -15,6 +15,7 @@ func NewEnv(state *ethstate.State, tx *Transaction, block *Block) *VMEnv { return &VMEnv{ state: state, block: block, + tx: tx, } } -- cgit v1.2.3 From a45c08f9fe320d79d2abc7c29e5f3b986130c5bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Jul 2014 12:19:55 +0200 Subject: Removed old code --- ethchain/state_transition.go | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index a03a3a94a..266328ce8 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -266,34 +266,8 @@ func (self *StateTransition) Eval(script []byte, context *ethstate.StateObject, ret, _, err = callerClosure.Call(vm, self.tx.Data) - /* - closure := NewClosure(initiator, context, script, state, self.gas, self.gasPrice) - vm := NewVm(state, nil, RuntimeVars{ - Origin: initiator.Address(), - Block: block, - BlockNumber: block.Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: self.value, - }) - vm.Verbose = true - vm.Fn = typ - - ret, err = Call(vm, closure, self.data) - */ - - return -} - -/* -func Call(vm *eth.Vm, closure *Closure, data []byte) (ret []byte, err error) { - ret, _, err = closure.Call(vm, data) - return } -*/ // Converts an transaction in to a state object func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject { -- cgit v1.2.3 From 41bd38147c2e5968283facf641b2444c09f53d14 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Jul 2014 11:24:44 +0200 Subject: Clean up and util methods --- ethchain/block.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 437525e35..e00bcb24f 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -3,13 +3,14 @@ package ethchain import ( "bytes" "fmt" + "math/big" + _ "strconv" + "time" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "math/big" - _ "strconv" - "time" ) type BlockInfo struct { @@ -63,12 +64,6 @@ type Block struct { 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) -- cgit v1.2.3 From 1f9894c0845a5259adbfd30fe3a86631e6403b8d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Jul 2014 00:31:15 +0200 Subject: Old code removed and renamed amount to balance --- ethchain/block.go | 27 --------------- ethchain/block_chain.go | 7 ++-- ethchain/state_transition.go | 15 +++++---- ethchain/transaction_pool.go | 79 +++----------------------------------------- 4 files changed, 16 insertions(+), 112 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index e00bcb24f..ac56f58c3 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -125,33 +125,6 @@ func (block *Block) Transactions() []*Transaction { return block.transactions } -func (block *Block) PayFee(addr []byte, fee *big.Int) bool { - contract := block.state.GetStateObject(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.Trie.Update(string(addr), string(contract.RlpEncode())) - - data := block.state.Trie.Get(string(block.Coinbase)) - - // Get the ether (Coinbase) and add the fee (gief fee to miner) - account := ethstate.NewStateObjectFromBytes(block.Coinbase, []byte(data)) - - base = new(big.Int) - account.Amount = base.Add(account.Amount, fee) - - //block.state.Trie.Update(string(block.Coinbase), string(ether.RlpEncode())) - block.state.UpdateStateObject(account) - - return true -} - func (block *Block) CalcGasLimit(parent *Block) *big.Int { if block.Number.Cmp(big.NewInt(0)) == 0 { return ethutil.BigPow(10, 6) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 1a2662787..250903798 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,11 +2,12 @@ package ethchain import ( "bytes" + "math" + "math/big" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "math" - "math/big" ) var chainlogger = ethlog.NewLogger("CHAIN") @@ -280,7 +281,7 @@ func AddTestNetFunds(block *Block) { } { codedAddr := ethutil.Hex2Bytes(addr) account := block.state.GetAccount(codedAddr) - account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) + account.Balance = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 266328ce8..02a8e0e82 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,11 +2,12 @@ package ethchain import ( "fmt" + "math/big" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethvm" - "math/big" ) /* @@ -94,8 +95,8 @@ func (self *StateTransition) BuyGas() error { var err error sender := self.Sender() - if sender.Amount.Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Amount) + if sender.Balance.Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance) } coinbase := self.Coinbase() @@ -178,8 +179,8 @@ func (self *StateTransition) TransitionState() (err error) { return } - if sender.Amount.Cmp(self.value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) + if sender.Balance.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) } var snapshot *ethstate.State @@ -240,8 +241,8 @@ func (self *StateTransition) TransitionState() (err error) { } func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObject) error { - if sender.Amount.Cmp(self.value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) + if sender.Balance.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) } // Subtract the amount from the senders account diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 21c6ea3de..b0d62fd91 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -4,11 +4,12 @@ import ( "bytes" "container/list" "fmt" + "math/big" + "sync" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethwire" - "math/big" - "sync" ) var txplogger = ethlog.NewLogger("TXP") @@ -91,78 +92,6 @@ func (pool *TxPool) addTransaction(tx *Transaction) { pool.Ethereum.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, state *State, toContract bool) (gas *big.Int, err error) { - fmt.Printf("state root before update %x\n", state.Root()) - defer func() { - if r := recover(); r != nil { - txplogger.Infoln(r) - err = fmt.Errorf("%v", r) - } - }() - - gas = new(big.Int) - addGas := func(g *big.Int) { gas.Add(gas, g) } - addGas(GasTx) - - // Get the sender - sender := state.GetAccount(tx.Sender()) - - if sender.Nonce != tx.Nonce { - err = NonceError(tx.Nonce, sender.Nonce) - return - } - - sender.Nonce += 1 - defer func() { - //state.UpdateStateObject(sender) - // Notify all subscribers - pool.Ethereum.Reactor().Post("newTx:post", tx) - }() - - txTotalBytes := big.NewInt(int64(len(tx.Data))) - txTotalBytes.Div(txTotalBytes, ethutil.Big32) - addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) - - rGas := new(big.Int).Set(gas) - rGas.Mul(gas, tx.GasPrice) - - // 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, rGas) - if sender.Amount.Cmp(totAmount) < 0 { - err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) - return - } - state.UpdateStateObject(sender) - fmt.Printf("state root after sender update %x\n", state.Root()) - - // Get the receiver - receiver := state.GetAccount(tx.Recipient) - - // Send Tx to self - if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - // Subtract the fee - sender.SubAmount(rGas) - } else { - // Subtract the amount from the senders account - sender.SubAmount(totAmount) - - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(tx.Value) - - state.UpdateStateObject(receiver) - fmt.Printf("state root after receiver update %x\n", state.Root()) - } - - txplogger.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) - - return -} -*/ - func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Get the last block so we can retrieve the sender and receiver from // the merkle trie @@ -183,7 +112,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { totAmount := new(big.Int).Set(tx.Value) // 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 { + if sender.Balance.Cmp(totAmount) < 0 { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } -- cgit v1.2.3 From 3debeb7236d2c8474fa9049cc91dc26bf1040b3f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 4 Aug 2014 10:38:18 +0200 Subject: ethtrie.NewTrie => ethtrie.New --- ethchain/block.go | 24 ++++-------------------- ethchain/block_chain.go | 10 +++++----- ethchain/state_transition.go | 2 +- 3 files changed, 10 insertions(+), 26 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index ac56f58c3..e4486f8e4 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -100,7 +100,7 @@ func CreateBlock(root interface{}, } block.SetUncles([]*Block{}) - block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, root)) + block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, root)) return block } @@ -220,26 +220,10 @@ func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { func (block *Block) setTransactions(txs []*Transaction) { block.transactions = txs - - /* - trie := ethtrie.NewTrie(ethutil.Config.Db, "") - for i, tx := range txs { - trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) - } - - switch trie.Root.(type) { - case string: - block.TxSha = []byte(trie.Root.(string)) - case []byte: - block.TxSha = trie.Root.([]byte) - default: - panic(fmt.Sprintf("invalid root type %T", trie.Root)) - } - */ } func CreateTxSha(receipts Receipts) (sha []byte) { - trie := ethtrie.NewTrie(ethutil.Config.Db, "") + trie := ethtrie.New(ethutil.Config.Db, "") for i, receipt := range receipts { trie.Update(string(ethutil.NewValue(i).Encode()), string(ethutil.NewValue(receipt.RlpData()).Encode())) } @@ -281,7 +265,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() @@ -323,7 +307,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 250903798..736fe52c7 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -132,7 +132,7 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte // Start with the newest block we got, all the way back to the common block we both know for _, block := range blocks { if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - chainlogger.Infoln("[CHAIN] We have found the common parent block, breaking") + chainlogger.Infoln("We have found the common parent block, breaking") break } chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) @@ -145,13 +145,13 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { i++ if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - chainlogger.Infoln("We have found the common parent block, breaking") + chainlogger.Infoln("Found the common parent block") break } anOtherBlock := bc.GetBlock(block.PrevHash) if anOtherBlock == nil { // We do not want to count the genesis block for difficulty since that's not being sent - chainlogger.Infoln("At genesis block, breaking") + chainlogger.Infoln("Found genesis block. Stop") break } curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) @@ -159,11 +159,11 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte chainlogger.Infoln("Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - chainlogger.Infof("The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) + chainlogger.Infof("Resetting to block %x. Changing chain.") bc.ResetTillBlockHash(commonBlockHash) return false } else { - chainlogger.Infoln("Our chain showed the incoming chain who is boss. Ignoring.") + chainlogger.Infoln("Current chain is longest chain. Ignoring incoming chain.") return true } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 02a8e0e82..8f1561c00 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -278,7 +278,7 @@ func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject contract := state.NewStateObject(addr) contract.InitCode = tx.Data - contract.State = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) + contract.State = ethstate.NewState(ethtrie.New(ethutil.Config.Db, "")) return contract } -- cgit v1.2.3 From 03ce15df4c7ef51d4373233ab5c3766282b31771 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 4 Aug 2014 10:42:40 +0200 Subject: ethstate.NewState => ethstate.New --- ethchain/block.go | 6 +++--- ethchain/state_transition.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index e4486f8e4..321af6183 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -100,7 +100,7 @@ func CreateBlock(root interface{}, } block.SetUncles([]*Block{}) - block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, root)) + block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, root)) return block } @@ -265,7 +265,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() @@ -307,7 +307,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethstate.NewState(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) + block.state = ethstate.New(ethtrie.New(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8f1561c00..dfcbfcc04 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -278,7 +278,7 @@ func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject contract := state.NewStateObject(addr) contract.InitCode = tx.Data - contract.State = ethstate.NewState(ethtrie.New(ethutil.Config.Db, "")) + contract.State = ethstate.New(ethtrie.New(ethutil.Config.Db, "")) return contract } -- cgit v1.2.3 From da50c751480da32036f41ccbeb1f292694ca0286 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 6 Aug 2014 09:53:00 +0200 Subject: Added state dump method --- ethchain/block_chain.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 736fe52c7..3eba90fca 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -290,7 +290,6 @@ 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 = block.Number.Uint64() @@ -301,9 +300,6 @@ func (bc *BlockChain) setLastBlock() { bc.genesisBlock.state.Trie.Sync() // Prepare the genesis block bc.Add(bc.genesisBlock) - - //chainlogger.Infof("root %x\n", bm.bc.genesisBlock.State().Root) - //bm.bc.genesisBlock.PrintHash() } // Set the last know difficulty (might be 0x0 as initial value, Genesis) @@ -339,6 +335,18 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block { return NewBlockFromBytes(data) } +func (self *BlockChain) GetBlockByNumber(num uint64) *Block { + block := self.CurrentBlock + for ; block.Number.Uint64() != num; block = self.GetBlock(block.PrevHash) { + } + + if block.Number.Uint64() == 0 && num != 0 { + return nil + } + + return block +} + func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { bi := BlockInfo{} data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) -- cgit v1.2.3 From c51db4c940a5ea679aee580a673a4ccdd2421b9a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 8 Aug 2014 14:36:59 +0100 Subject: Fixed stack issue --- ethchain/state_manager.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 226b2fe73..f06622fcb 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -4,15 +4,16 @@ import ( "bytes" "container/list" "fmt" + "math/big" + "sync" + "time" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "math/big" - "sync" - "time" ) var statelogger = ethlog.NewLogger("STATE") -- cgit v1.2.3 From 27290e12772f4a354cfdc6383222597f66cefa21 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 9 Aug 2014 18:06:16 +0100 Subject: Fixed gas limit calculation --- ethchain/block.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 321af6183..5b06fd58d 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -130,8 +130,10 @@ func (block *Block) CalcGasLimit(parent *Block) *big.Int { return ethutil.BigPow(10, 6) } - previous := new(big.Int).Mul(big.NewInt(1023), parent.GasLimit) - current := new(big.Rat).Mul(new(big.Rat).SetInt(block.GasUsed), big.NewRat(6, 5)) + // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 + + previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit) + current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed), big.NewRat(6, 5)) curInt := new(big.Int).Div(current.Num(), current.Denom()) result := new(big.Int).Add(previous, curInt) -- cgit v1.2.3 From 024be32f0667c17b9240dda23a90612d17278b23 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 9 Aug 2014 18:09:55 +0100 Subject: Make sure all left padded zero's aren't included --- ethchain/transaction.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 5686a7edb..e1b48a3d3 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -3,10 +3,11 @@ package ethchain import ( "bytes" "fmt" + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "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} @@ -130,7 +131,7 @@ func (tx *Transaction) RlpData() interface{} { // TODO Remove prefixing zero's - return append(data, tx.v, tx.r, tx.s) + return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes()) } func (tx *Transaction) RlpValue() *ethutil.Value { -- cgit v1.2.3 From 2e5d28c73f1d97865def3ffe8c7ad0a4819f15f3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 11 Aug 2014 16:23:17 +0200 Subject: Added bloom filter & block filter methods --- ethchain/bloom.go | 47 ++++++++++++++++ ethchain/bloom_test.go | 20 +++++++ ethchain/filter.go | 146 ++++++++++++++++++++++++++++++++++++++++++++++++ ethchain/filter_test.go | 7 +++ 4 files changed, 220 insertions(+) create mode 100644 ethchain/bloom.go create mode 100644 ethchain/bloom_test.go create mode 100644 ethchain/filter.go create mode 100644 ethchain/filter_test.go (limited to 'ethchain') diff --git a/ethchain/bloom.go b/ethchain/bloom.go new file mode 100644 index 000000000..320ce73fc --- /dev/null +++ b/ethchain/bloom.go @@ -0,0 +1,47 @@ +package ethchain + +type BloomFilter struct { + bin []byte +} + +func NewBloomFilter(bin []byte) *BloomFilter { + if bin == nil { + bin = make([]byte, 255) + } + + return &BloomFilter{ + bin: bin, + } +} + +func (self *BloomFilter) Set(addr []byte) { + if len(addr) < 8 { + chainlogger.Warnf("err: bloom set to small: %x\n", addr) + + return + } + + for _, i := range addr[len(addr)-8:] { + self.bin[i] = 1 + } +} + +func (self *BloomFilter) Search(addr []byte) bool { + if len(addr) < 8 { + chainlogger.Warnf("err: bloom search to small: %x\n", addr) + + return false + } + + for _, i := range addr[len(addr)-8:] { + if self.bin[i] == 0 { + return false + } + } + + return true +} + +func (self *BloomFilter) Bin() []byte { + return self.bin +} diff --git a/ethchain/bloom_test.go b/ethchain/bloom_test.go new file mode 100644 index 000000000..ea53d539c --- /dev/null +++ b/ethchain/bloom_test.go @@ -0,0 +1,20 @@ +package ethchain + +import "testing" + +func TestBloomFilter(t *testing.T) { + bf := NewBloomFilter(nil) + + a := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} + bf.Set(a) + + b := []byte{10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + + if bf.Search(a) == false { + t.Error("Expected 'a' to yield true using a bloom filter") + } + + if bf.Search(b) { + t.Error("Expected 'b' not to field trie using a bloom filter") + } +} diff --git a/ethchain/filter.go b/ethchain/filter.go new file mode 100644 index 000000000..c3b0a7f94 --- /dev/null +++ b/ethchain/filter.go @@ -0,0 +1,146 @@ +package ethchain + +import ( + "bytes" + "fmt" + + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" +) + +// Filtering interface +type Filter struct { + eth EthManager + earliest []byte + latest []byte + skip int + from, to []byte + max int +} + +// Create a new filter which uses a bloom filter on blocks to figure out whether a particular block +// is interesting or not. +func NewFilter(eth EthManager) *Filter { + return &Filter{eth: eth} +} + +// Set the earliest and latest block for filtering. +// -1 = latest block (i.e., the current block) +// hash = particular hash from-to +func (self *Filter) SetEarliestBlock(earliest interface{}) { + e := ethutil.NewValue(earliest) + + // Check for -1 (latest) otherwise assume bytes + if e.Int() == -1 { + self.earliest = self.eth.BlockChain().CurrentBlock.Hash() + } else if e.Len() > 0 { + self.earliest = e.Bytes() + } else { + panic(fmt.Sprintf("earliest has to be either -1 or a valid hash: %v (%T)", e, e.Val)) + } +} + +func (self *Filter) SetLatestBlock(latest interface{}) { + l := ethutil.NewValue(latest) + + // Check for -1 (latest) otherwise assume bytes + if l.Int() == -1 { + self.latest = self.eth.BlockChain().CurrentBlock.Hash() + } else if l.Len() > 0 { + self.latest = l.Bytes() + } else { + panic(fmt.Sprintf("latest has to be either -1 or a valid hash: %v", l)) + } +} + +func (self *Filter) SetFrom(addr []byte) { + self.from = addr +} + +func (self *Filter) SetTo(addr []byte) { + self.to = addr +} + +func (self *Filter) SetMax(max int) { + self.max = max +} + +func (self *Filter) SetSkip(skip int) { + self.skip = skip +} + +// Run filters messages with the current parameters set +func (self *Filter) Find() []*ethstate.Message { + var messages []*ethstate.Message + + block := self.eth.BlockChain().GetBlock(self.latest) + + // skip N blocks (useful for pagination) + if self.skip > 0 { + for i := 0; i < i; i++ { + block = self.eth.BlockChain().GetBlock(block.PrevHash) + } + } + + // Start block filtering + quit := false + for i := 1; !quit && block != nil; i++ { + // Mark last check + if self.max == i || (len(self.earliest) > 0 && bytes.Compare(block.Hash(), self.earliest) == 0) { + quit = true + } + + // Use bloom filtering to see if this block is interesting given the + // current parameters + if self.bloomFilter(block) { + // Get the messages of the block + msgs, err := self.eth.StateManager().GetMessages(block) + if err != nil { + chainlogger.Warnln("err: filter get messages ", err) + + break + } + + // Filter the messages for interesting stuff + for _, message := range msgs { + if len(self.to) > 0 && bytes.Compare(message.To, self.to) != 0 { + continue + } + + if len(self.from) > 0 && bytes.Compare(message.From, self.from) != 0 { + continue + } + + messages = append(messages, message) + } + } + + block = self.eth.BlockChain().GetBlock(block.PrevHash) + } + + return messages +} + +func (self *Filter) bloomFilter(block *Block) bool { + fk := append([]byte("bloom"), block.Hash()...) + bin, err := self.eth.Db().Get(fk) + if err != nil { + panic(err) + } + + bloom := NewBloomFilter(bin) + + if len(self.from) > 0 { + if !bloom.Search(self.from) { + return false + } + } + + if len(self.to) > 0 { + if !bloom.Search(self.to) { + return false + } + } + + return true +} diff --git a/ethchain/filter_test.go b/ethchain/filter_test.go new file mode 100644 index 000000000..6dce51b3b --- /dev/null +++ b/ethchain/filter_test.go @@ -0,0 +1,7 @@ +package ethchain + +import "testing" + +func TestFilter(t *testing.T) { + filter := NewFilter() +} -- cgit v1.2.3 From a760ce05b948e89bc564af20599dcf95698ac0eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 11 Aug 2014 16:23:38 +0200 Subject: Updated chain for filtering --- ethchain/block.go | 13 -------- ethchain/block_chain.go | 2 ++ ethchain/block_chain_test.go | 23 +++++++++++---- ethchain/state_manager.go | 70 ++++++++++++++++++++++++++++++++++++++++++-- ethchain/state_transition.go | 12 +++++++- ethchain/vm_env.go | 4 ++- 6 files changed, 101 insertions(+), 23 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 5b06fd58d..5765abd51 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -142,19 +142,6 @@ func (block *Block) CalcGasLimit(parent *Block) *big.Int { min := big.NewInt(125000) return ethutil.BigMax(min, result) - /* - base := new(big.Int) - base2 := new(big.Int) - parentGL := bc.CurrentBlock.GasLimit - parentUsed := bc.CurrentBlock.GasUsed - - base.Mul(parentGL, big.NewInt(1024-1)) - base2.Mul(parentUsed, big.NewInt(6)) - base2.Div(base2, big.NewInt(5)) - base.Add(base, base2) - base.Div(base, big.NewInt(1024)) - */ - } func (block *Block) BlockInfo() BlockInfo { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 3eba90fca..611735707 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -300,6 +300,8 @@ func (bc *BlockChain) setLastBlock() { bc.genesisBlock.state.Trie.Sync() // Prepare the genesis block bc.Add(bc.genesisBlock) + fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) + bc.Ethereum.Db().Put(fk, make([]byte, 255)) } // Set the last know difficulty (might be 0x0 as initial value, Genesis) diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index bbc96c823..1edcf9c7b 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -3,16 +3,19 @@ package ethchain import ( "container/list" "fmt" + "testing" + + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "testing" ) // Implement our EthTest Manager type TestManager struct { stateManager *StateManager - reactor *ethutil.ReactorEngine + reactor *ethreact.ReactorEngine txPool *TxPool blockChain *BlockChain @@ -47,16 +50,24 @@ func (tm *TestManager) StateManager() *StateManager { return tm.stateManager } -func (tm *TestManager) Reactor() *ethutil.ReactorEngine { +func (tm *TestManager) Reactor() *ethreact.ReactorEngine { return tm.reactor } func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { fmt.Println("Broadcast not implemented") } -func NewTestManager() *TestManager { +func (tm *TestManager) ClientIdentity() ethwire.ClientIdentity { + return nil +} +func (tm *TestManager) KeyManager() *ethcrypto.KeyManager { + return nil +} - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") +func (tm *TestManager) Db() ethutil.Database { return nil } + +func NewTestManager() *TestManager { + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH") db, err := ethdb.NewMemDatabase() if err != nil { @@ -66,7 +77,7 @@ func NewTestManager() *TestManager { ethutil.Config.Db = db testManager := &TestManager{} - testManager.reactor = ethutil.NewReactorEngine() + testManager.reactor = ethreact.New() testManager.txPool = NewTxPool(testManager) testManager.blockChain = NewBlockChain(testManager) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f06622fcb..a60b28b3f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -45,6 +45,7 @@ type EthManager interface { Peers() *list.List KeyManager() *ethcrypto.KeyManager ClientIdentity() ethwire.ClientIdentity + Db() ethutil.Database } type StateManager struct { @@ -235,7 +236,12 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Add the block to the chain sm.bc.Add(block) - sm.notifyChanges(state) + + // Create a bloom bin for this block + filter := sm.createBloomFilter(state) + // Persist the data + fk := append([]byte("bloom"), block.Hash()...) + sm.Ethereum.Db().Put(fk, filter.Bin()) statelogger.Infof("Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { @@ -363,14 +369,74 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) notifyChanges(state *ethstate.State) { +// Manifest will handle both creating notifications and generating bloom bin data +func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { + bloomf := NewBloomFilter(nil) + for addr, stateObject := range state.Manifest().ObjectChanges { + // Set the bloom filter's bin + bloomf.Set([]byte(addr)) + sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { for addr, value := range mappedObjects { + // Set the bloom filter's bin + bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr))) + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } } + + return bloomf +} + +func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, err error) { + if !sm.bc.HasBlock(block.PrevHash) { + return nil, ParentError(block.PrevHash) + } + + sm.lastAttemptedBlock = block + + var ( + parent = sm.bc.GetBlock(block.PrevHash) + state = parent.State().Copy() + ) + + defer state.Reset() + + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { + fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) + } + + receipts, err := sm.ApplyDiff(state, parent, block) + if err != nil { + return nil, err + } + + txSha := CreateTxSha(receipts) + if bytes.Compare(txSha, block.TxSha) != 0 { + return nil, fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha) + } + + // Block validation + if err = sm.ValidateBlock(block); err != nil { + statelogger.Errorln("Error validating block:", err) + return nil, err + } + + // I'm not sure, but I don't know if there should be thrown + // any errors at this time. + if err = sm.AccumelateRewards(state, block); err != nil { + statelogger.Errorln("Error accumulating reward", err) + return nil, err + } + + if !block.State().Cmp(state) { + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) + return nil, err + } + + return state.Manifest().Messages, nil } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index dfcbfcc04..489ff2b6a 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -211,6 +211,13 @@ func (self *StateTransition) TransitionState() (err error) { snapshot = self.state.Copy() } + msg := self.state.Manifest().AddMessage(ðstate.Message{ + To: receiver.Address(), From: sender.Address(), + Input: self.tx.Data, + Origin: sender.Address(), + Block: self.block.Hash(), Timestamp: self.block.Time, Coinbase: self.block.Coinbase, Number: self.block.Number, + }) + // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { // Evaluate the initialization script @@ -226,14 +233,17 @@ func (self *StateTransition) TransitionState() (err error) { } receiver.Code = code + msg.Output = code } else { if len(receiver.Code) > 0 { - _, err = self.Eval(receiver.Code, receiver, "code") + ret, err := self.Eval(receiver.Code, receiver, "code") if err != nil { self.state.Set(snapshot) return fmt.Errorf("Error during code execution %v", err) } + + msg.Output = ret } } diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go index ddead77fd..30f9497fa 100644 --- a/ethchain/vm_env.go +++ b/ethchain/vm_env.go @@ -1,8 +1,9 @@ package ethchain import ( - "github.com/ethereum/eth-go/ethstate" "math/big" + + "github.com/ethereum/eth-go/ethstate" ) type VMEnv struct { @@ -25,5 +26,6 @@ func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } func (self *VMEnv) Time() int64 { return self.block.Time } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } +func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.tx.Value } func (self *VMEnv) State() *ethstate.State { return self.state } -- cgit v1.2.3 From fa881220aedb638f9ee35337b2ca1817c2a8482f Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 13 Aug 2014 10:52:50 +0200 Subject: Updated lookup method to include CNAME's as well as A records --- ethchain/bloom.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/bloom.go b/ethchain/bloom.go index 320ce73fc..5317ca0b1 100644 --- a/ethchain/bloom.go +++ b/ethchain/bloom.go @@ -6,7 +6,7 @@ type BloomFilter struct { func NewBloomFilter(bin []byte) *BloomFilter { if bin == nil { - bin = make([]byte, 255) + bin = make([]byte, 256) } return &BloomFilter{ -- cgit v1.2.3 From 0d733aa07197c8adbbaa92a12a4ad32e86676cc7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 14 Aug 2014 17:02:21 +0200 Subject: Removed validation check from GetMessages --- ethchain/state_manager.go | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a60b28b3f..d7860b2a2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -406,37 +406,9 @@ func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, defer state.Reset() - if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { - fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) - } - - receipts, err := sm.ApplyDiff(state, parent, block) - if err != nil { - return nil, err - } + sm.ApplyDiff(state, parent, block) - txSha := CreateTxSha(receipts) - if bytes.Compare(txSha, block.TxSha) != 0 { - return nil, fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha) - } - - // Block validation - if err = sm.ValidateBlock(block); err != nil { - statelogger.Errorln("Error validating block:", err) - return nil, err - } - - // I'm not sure, but I don't know if there should be thrown - // any errors at this time. - if err = sm.AccumelateRewards(state, block); err != nil { - statelogger.Errorln("Error accumulating reward", err) - return nil, err - } - - if !block.State().Cmp(state) { - err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) - return nil, err - } + sm.AccumelateRewards(state, block) return state.Manifest().Messages, nil } -- cgit v1.2.3 From 07cfb7b64ac7932a4ff8c2480452114b84b421a6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 14 Aug 2014 17:02:39 +0200 Subject: updated filter so it accepts multiple from and to --- ethchain/filter.go | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'ethchain') diff --git a/ethchain/filter.go b/ethchain/filter.go index c3b0a7f94..65c41c42d 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -14,7 +14,7 @@ type Filter struct { earliest []byte latest []byte skip int - from, to []byte + from, to [][]byte max int } @@ -53,14 +53,22 @@ func (self *Filter) SetLatestBlock(latest interface{}) { } } -func (self *Filter) SetFrom(addr []byte) { +func (self *Filter) SetFrom(addr [][]byte) { self.from = addr } -func (self *Filter) SetTo(addr []byte) { +func (self *Filter) AddFrom(addr []byte) { + self.from = append(self.from, addr) +} + +func (self *Filter) SetTo(addr [][]byte) { self.to = addr } +func (self *Filter) AddTo(addr []byte) { + self.from = append(self.to, addr) +} + func (self *Filter) SetMax(max int) { self.max = max } @@ -101,13 +109,22 @@ func (self *Filter) Find() []*ethstate.Message { break } + includes := func(addresses [][]byte, a []byte) (found bool) { + for _, addr := range addresses { + if bytes.Compare(addr, a) == 0 { + return true + } + } + + return + } // Filter the messages for interesting stuff for _, message := range msgs { - if len(self.to) > 0 && bytes.Compare(message.To, self.to) != 0 { + if len(self.to) > 0 && !includes(self.to, message.To) { continue } - if len(self.from) > 0 && bytes.Compare(message.From, self.from) != 0 { + if len(self.from) > 0 && !includes(self.from, message.From) { continue } @@ -130,17 +147,28 @@ func (self *Filter) bloomFilter(block *Block) bool { bloom := NewBloomFilter(bin) + var fromIncluded, toIncluded bool if len(self.from) > 0 { - if !bloom.Search(self.from) { - return false + for _, from := range self.from { + if bloom.Search(from) { + fromIncluded = true + break + } } + } else { + fromIncluded = true } if len(self.to) > 0 { - if !bloom.Search(self.to) { - return false + for _, to := range self.to { + if bloom.Search(to) { + toIncluded = true + break + } } + } else { + toIncluded = true } - return true + return fromIncluded && toIncluded } -- cgit v1.2.3 From 0fcc6065692f2692072cdf0d61fe1ada547fc235 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 00:24:37 +0200 Subject: Added new filter from map --- ethchain/filter.go | 83 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 18 deletions(-) (limited to 'ethchain') diff --git a/ethchain/filter.go b/ethchain/filter.go index 65c41c42d..4f3160b90 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -24,6 +24,46 @@ func NewFilter(eth EthManager) *Filter { return &Filter{eth: eth} } +func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { + filter := NewFilter(eth) + + if object["earliest"] != nil { + earliest := object["earliest"] + if e, ok := earliest.(string); ok { + filter.SetEarliestBlock(ethutil.Hex2Bytes(e)) + } else { + filter.SetEarliestBlock(earliest) + } + } + + if object["latest"] != nil { + latest := object["latest"] + if l, ok := latest.(string); ok { + filter.SetLatestBlock(ethutil.Hex2Bytes(l)) + } else { + filter.SetLatestBlock(latest) + } + } + + if object["to"] != nil { + filter.AddTo(ethutil.Hex2Bytes(object["to"].(string))) + } + + if object["from"] != nil { + filter.AddFrom(ethutil.Hex2Bytes(object["from"].(string))) + } + + if object["max"] != nil { + filter.SetMax(object["max"].(int)) + } + + if object["skip"] != nil { + filter.SetSkip(object["skip"].(int)) + } + + return filter +} + // Set the earliest and latest block for filtering. // -1 = latest block (i.e., the current block) // hash = particular hash from-to @@ -109,30 +149,37 @@ func (self *Filter) Find() []*ethstate.Message { break } - includes := func(addresses [][]byte, a []byte) (found bool) { - for _, addr := range addresses { - if bytes.Compare(addr, a) == 0 { - return true - } - } + messages = append(messages, self.FilterMessages(msgs)...) + } - return - } - // Filter the messages for interesting stuff - for _, message := range msgs { - if len(self.to) > 0 && !includes(self.to, message.To) { - continue - } + block = self.eth.BlockChain().GetBlock(block.PrevHash) + } - if len(self.from) > 0 && !includes(self.from, message.From) { - continue - } + return messages +} - messages = append(messages, message) +func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message { + var messages []*ethstate.Message + includes := func(addresses [][]byte, a []byte) (found bool) { + for _, addr := range addresses { + if bytes.Compare(addr, a) == 0 { + return true } } - block = self.eth.BlockChain().GetBlock(block.PrevHash) + return + } + // Filter the messages for interesting stuff + for _, message := range msgs { + if len(self.to) > 0 && !includes(self.to, message.To) { + continue + } + + if len(self.from) > 0 && !includes(self.from, message.From) { + continue + } + + messages = append(messages, message) } return messages -- cgit v1.2.3 From c7ee9844bd6f8ed2bb466f8adf21f437ecc83564 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 00:25:16 +0200 Subject: Removed old code --- ethchain/state_manager.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index d7860b2a2..1f47a2e0b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -380,14 +380,18 @@ func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { - for addr, value := range mappedObjects { - // Set the bloom filter's bin - bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr))) + sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages) - sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) + /* + for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { + for addr, value := range mappedObjects { + // Set the bloom filter's bin + bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr))) + + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) + } } - } + */ return bloomf } -- cgit v1.2.3 From 7d95e8624a3bdca4a68b2a7ff6ed133264088cc1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 16:19:10 +0200 Subject: Added message to closure && added change addresses --- ethchain/filter.go | 101 +++++++++++++++++++++++++++++++++++++++---- ethchain/state_manager.go | 14 ++++-- ethchain/state_transition.go | 8 ++-- 3 files changed, 107 insertions(+), 16 deletions(-) (limited to 'ethchain') diff --git a/ethchain/filter.go b/ethchain/filter.go index 4f3160b90..c4c403cf7 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -6,8 +6,13 @@ import ( "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" + "gopkg.in/qml.v1" ) +type data struct { + id, address []byte +} + // Filtering interface type Filter struct { eth EthManager @@ -16,6 +21,8 @@ type Filter struct { skip int from, to [][]byte max int + + altered []data } // Create a new filter which uses a bloom filter on blocks to figure out whether a particular block @@ -61,9 +68,19 @@ func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { filter.SetSkip(object["skip"].(int)) } + if object["altered"] != nil { + filter.altered = makeAltered(object["altered"]) + } + + fmt.Println("ALTERED", filter.altered) + return filter } +func (self *Filter) AddAltered(id, address []byte) { + self.altered = append(self.altered, data{id, address}) +} + // Set the earliest and latest block for filtering. // -1 = latest block (i.e., the current block) // hash = particular hash from-to @@ -158,17 +175,19 @@ func (self *Filter) Find() []*ethstate.Message { return messages } +func includes(addresses [][]byte, a []byte) (found bool) { + for _, addr := range addresses { + if bytes.Compare(addr, a) == 0 { + return true + } + } + + return +} + func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message { var messages []*ethstate.Message - includes := func(addresses [][]byte, a []byte) (found bool) { - for _, addr := range addresses { - if bytes.Compare(addr, a) == 0 { - return true - } - } - return - } // Filter the messages for interesting stuff for _, message := range msgs { if len(self.to) > 0 && !includes(self.to, message.To) { @@ -179,6 +198,28 @@ func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message continue } + var match bool + if len(self.altered) == 0 { + match = true + } + + for _, item := range self.altered { + if len(item.id) > 0 && bytes.Compare(message.To, item.id) != 0 { + continue + } + + if len(item.address) > 0 && !includes(message.ChangedAddresses, item.address) { + continue + } + + match = true + break + } + + if !match { + continue + } + messages = append(messages, message) } @@ -219,3 +260,47 @@ func (self *Filter) bloomFilter(block *Block) bool { return fromIncluded && toIncluded } + +// Conversion methodn +func mapToData(m map[string]interface{}) (d data) { + if str, ok := m["id"].(string); ok { + d.id = ethutil.Hex2Bytes(str) + } + + if str, ok := m["at"].(string); ok { + d.address = ethutil.Hex2Bytes(str) + } + + return +} + +// data can come in in the following formats: +// ["aabbccdd", {id: "ccddee", at: "11223344"}], "aabbcc", {id: "ccddee", at: "1122"} +func makeAltered(v interface{}) (d []data) { + if str, ok := v.(string); ok { + d = append(d, data{ethutil.Hex2Bytes(str), nil}) + } else if obj, ok := v.(map[string]interface{}); ok { + d = append(d, mapToData(obj)) + } else if slice, ok := v.([]interface{}); ok { + for _, item := range slice { + d = append(d, makeAltered(item)...) + } + } else if qList, ok := v.(*qml.List); ok { + var s []interface{} + qList.Convert(&s) + + fmt.Println(s) + + d = makeAltered(s) + } else if qMap, ok := v.(*qml.Map); ok { + var m map[string]interface{} + qMap.Convert(&m) + fmt.Println(m) + + d = makeAltered(m) + } else { + panic(fmt.Sprintf("makeAltered err (unknown conversion): %T\n", v)) + } + + return +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1f47a2e0b..08bd22d29 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -373,11 +373,17 @@ func (sm *StateManager) Stop() { func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { bloomf := NewBloomFilter(nil) - for addr, stateObject := range state.Manifest().ObjectChanges { - // Set the bloom filter's bin - bloomf.Set([]byte(addr)) + /* + for addr, stateObject := range state.Manifest().ObjectChanges { + // Set the bloom filter's bin + bloomf.Set([]byte(addr)) - sm.Ethereum.Reactor().Post("object:"+addr, stateObject) + sm.Ethereum.Reactor().Post("object:"+addr, stateObject) + } + */ + for _, msg := range state.Manifest().Messages { + bloomf.Set(msg.To) + bloomf.Set(msg.From) } sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 489ff2b6a..f8452cdb3 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -225,7 +225,7 @@ func (self *StateTransition) TransitionState() (err error) { // script section for the state object. self.data = nil - code, err := self.Eval(receiver.Init(), receiver, "init") + code, err := self.Eval(msg, receiver.Init(), receiver, "init") if err != nil { self.state.Set(snapshot) @@ -236,7 +236,7 @@ func (self *StateTransition) TransitionState() (err error) { msg.Output = code } else { if len(receiver.Code) > 0 { - ret, err := self.Eval(receiver.Code, receiver, "code") + ret, err := self.Eval(msg, receiver.Code, receiver, "code") if err != nil { self.state.Set(snapshot) @@ -263,12 +263,12 @@ func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObjec return nil } -func (self *StateTransition) Eval(script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) { +func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) { var ( transactor = self.Sender() state = self.state env = NewEnv(state, self.tx, self.block) - callerClosure = ethvm.NewClosure(transactor, context, script, self.gas, self.gasPrice) + callerClosure = ethvm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) ) vm := ethvm.New(env) -- cgit v1.2.3 From b0ae61c6521003d7861d89944e1d426e939535bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 18 Aug 2014 10:17:45 +0200 Subject: Removed the "Get" part --- ethchain/state_transition.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index f8452cdb3..9fbc160a5 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -216,6 +216,7 @@ func (self *StateTransition) TransitionState() (err error) { Input: self.tx.Data, Origin: sender.Address(), Block: self.block.Hash(), Timestamp: self.block.Time, Coinbase: self.block.Coinbase, Number: self.block.Number, + Value: self.value, }) // Process the init code and create 'valid' contract -- cgit v1.2.3 From 55a2f35a648ef70cdcc88bd751265e30831b54e5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 20 Aug 2014 13:05:26 +0200 Subject: JS Filter --- ethchain/filter.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/filter.go b/ethchain/filter.go index c4c403cf7..5ed9af977 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -72,8 +72,6 @@ func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { filter.altered = makeAltered(object["altered"]) } - fmt.Println("ALTERED", filter.altered) - return filter } @@ -123,7 +121,7 @@ func (self *Filter) SetTo(addr [][]byte) { } func (self *Filter) AddTo(addr []byte) { - self.from = append(self.to, addr) + self.to = append(self.to, addr) } func (self *Filter) SetMax(max int) { -- cgit v1.2.3 From eaa2e8900d1036e09b002c4e20fc6e4f9cd031bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 14:47:58 +0200 Subject: PoC 6 networking code. * Added block pool for gathering blocks from the network (chunks) * Re wrote syncing --- ethchain/block_chain.go | 20 ++++++++++++++++++++ ethchain/genesis.go | 6 ++++-- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 611735707..3445bbb87 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -208,6 +208,26 @@ func (bc *BlockChain) GenesisBlock() *Block { return bc.genesisBlock } +func (self *BlockChain) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) { + block := self.GetBlock(hash) + if block == nil { + return + } + + // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list) + for i := uint64(0); i < max; i++ { + chain = append(chain, block.Hash()) + + if block.Number.Cmp(ethutil.Big0) <= 0 { + break + } + + block = self.GetBlock(block.PrevHash) + } + + return +} + // Get chain return blocks from hash up to max in RLP format func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { var chain []interface{} diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 54a3bc766..0ce53a6ee 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -1,9 +1,10 @@ package ethchain import ( + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" - "math/big" ) /* @@ -26,7 +27,8 @@ var GenesisHeader = []interface{}{ // tx sha "", // Difficulty - ethutil.BigPow(2, 22), + //ethutil.BigPow(2, 22), + big.NewInt(4096), // Number ethutil.Big0, // Block minimum gas price -- cgit v1.2.3 From 0eb08693e90ce2f7cdabb142852a4173cc91e387 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 18:14:41 +0200 Subject: Turbo mode --- ethchain/dagger.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 917b3d722..065d2c843 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -1,15 +1,16 @@ package ethchain import ( + "hash" + "math/big" + "math/rand" + "time" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" - "hash" - "math/big" - "math/rand" - "time" ) var powlogger = ethlog.NewLogger("POW") @@ -18,17 +19,23 @@ type PoW interface { Search(block *Block, reactChan chan ethreact.Event) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool GetHashrate() int64 + Turbo(bool) } type EasyPow struct { hash *big.Int HashRate int64 + turbo bool } func (pow *EasyPow) GetHashrate() int64 { return pow.HashRate } +func (pow *EasyPow) Turbo(on bool) { + pow.turbo = on +} + func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() @@ -55,6 +62,10 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { return sha } } + + if !pow.turbo { + time.Sleep(500 * time.Millisecond) + } } return nil -- cgit v1.2.3 From 732573ba512aa215e88aed3f20393c3c42c1aeb0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 21 Aug 2014 20:13:26 +0200 Subject: Turbo mining --- ethchain/dagger.go | 8 ++++++-- ethchain/genesis.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 065d2c843..478b7e877 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -42,6 +42,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { diff := block.Difficulty i := int64(0) start := time.Now().UnixNano() + t := time.Now() for { select { @@ -50,11 +51,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { return nil default: i++ - if i%1234567 == 0 { + + if time.Since(t) > (1 * time.Second) { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 pow.HashRate = int64(hashes) powlogger.Infoln("Hashing @", int64(pow.HashRate), "khash") + + t = time.Now() } sha := ethcrypto.Sha3Bin(big.NewInt(r.Int63()).Bytes()) @@ -64,7 +68,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { } if !pow.turbo { - time.Sleep(500 * time.Millisecond) + time.Sleep(20 * time.Microsecond) } } diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 0ce53a6ee..8a1219acb 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -28,7 +28,7 @@ var GenesisHeader = []interface{}{ "", // Difficulty //ethutil.BigPow(2, 22), - big.NewInt(4096), + big.NewInt(131072), // Number ethutil.Big0, // Block minimum gas price -- cgit v1.2.3 From 93008e279d947e872099c8029b54f7431178bb29 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 22 Aug 2014 10:58:14 +0200 Subject: Removed old chain code --- ethchain/block_chain.go | 155 ------------------------------------------- ethchain/state_transition.go | 2 +- 2 files changed, 1 insertion(+), 156 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 3445bbb87..3b2914a37 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,12 +2,10 @@ package ethchain import ( "bytes" - "math" "math/big" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" ) var chainlogger = ethlog.NewLogger("CHAIN") @@ -110,99 +108,6 @@ func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { return blockDiff } -func (bc *BlockChain) FindCanonicalChainFromMsg(msg *ethwire.Msg, commonBlockHash []byte) bool { - var blocks []*Block - for i := 0; i < (msg.Data.Len() - 1); i++ { - block := NewBlockFromRlpValue(msg.Data.Get(i)) - blocks = append(blocks, block) - } - return bc.FindCanonicalChain(blocks, commonBlockHash) -} - -// Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one -// Return true if we are the using the canonical chain false if not -func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte) bool { - // 1. Calculate TD of the current chain - // 2. Calculate TD of the new chain - // Reset state to the correct one - - chainDifficulty := new(big.Int) - - // Calculate the entire chain until the block we both have - // Start with the newest block we got, all the way back to the common block we both know - for _, block := range blocks { - if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - chainlogger.Infoln("We have found the common parent block, breaking") - break - } - chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) - } - - chainlogger.Infoln("Incoming chain difficulty:", chainDifficulty) - - curChainDifficulty := new(big.Int) - block := bc.CurrentBlock - for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { - i++ - if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - chainlogger.Infoln("Found the common parent block") - break - } - anOtherBlock := bc.GetBlock(block.PrevHash) - if anOtherBlock == nil { - // We do not want to count the genesis block for difficulty since that's not being sent - chainlogger.Infoln("Found genesis block. Stop") - break - } - curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) - } - - chainlogger.Infoln("Current chain difficulty:", curChainDifficulty) - if chainDifficulty.Cmp(curChainDifficulty) == 1 { - chainlogger.Infof("Resetting to block %x. Changing chain.") - bc.ResetTillBlockHash(commonBlockHash) - return false - } else { - chainlogger.Infoln("Current chain is longest chain. Ignoring incoming chain.") - return true - } -} -func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { - lastBlock := bc.CurrentBlock - var returnTo *Block - // Reset to Genesis if that's all the origin there is. - if bytes.Compare(hash, bc.genesisBlock.Hash()) == 0 { - returnTo = bc.genesisBlock - bc.CurrentBlock = bc.genesisBlock - bc.LastBlockHash = bc.genesisBlock.Hash() - bc.LastBlockNumber = 1 - } else { - returnTo = bc.GetBlock(hash) - bc.CurrentBlock = returnTo - bc.LastBlockHash = returnTo.Hash() - bc.LastBlockNumber = returnTo.Number.Uint64() - } - - // Manually reset the last sync block - err := ethutil.Config.Db.Delete(lastBlock.Hash()) - if err != nil { - return err - } - - var block *Block - for ; block != nil; block = bc.GetBlock(block.PrevHash) { - if bytes.Compare(block.Hash(), hash) == 0 { - chainlogger.Infoln("We have arrived at the the common parent block, breaking") - break - } - err = ethutil.Config.Db.Delete(block.Hash()) - if err != nil { - return err - } - } - chainlogger.Infoln("Split chain deleted and reverted to common parent block.") - return nil -} func (bc *BlockChain) GenesisBlock() *Block { return bc.genesisBlock @@ -228,66 +133,6 @@ func (self *BlockChain) GetChainHashesFromHash(hash []byte, max uint64) (chain [ return } -// 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.CurrentBlock.Number.Uint64() - // Get the parents number - parentNumber := bc.GetBlock(hash).Number.Uint64() - // 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 { - num-- - - block := bc.GetBlock(currentHash) - if block == nil { - break - } - currentHash = block.PrevHash - } - - for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { - // Get the block of the chain - block := bc.GetBlock(currentHash) - if block == nil { - chainlogger.Debugf("Unexpected error during GetChainFromHash: Unable to find %x\n", currentHash) - break - } - - currentHash = block.PrevHash - - chain = append(chain, block.Value().Val) - - num-- - } - - 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) { - blocks = append([]*Block{block}, blocks...) - - if bytes.Compare(genHash, block.Hash()) == 0 { - break - } - i++ - } - - return blocks -} - func AddTestNetFunds(block *Block) { for _, addr := range []string{ "51ba59315b3a95761d0863b05ccc7a7f54703d99", diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 9fbc160a5..80f9fda5e 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -140,7 +140,7 @@ func (self *StateTransition) preCheck() (err error) { } func (self *StateTransition) TransitionState() (err error) { - statelogger.Infof("(~) %x\n", self.tx.Hash()) + statelogger.Debugf("(~) %x\n", self.tx.Hash()) /* defer func() { -- cgit v1.2.3 From 962255b373a0c8d7c2459cb25aaaa0dc4e492ecf Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 23 Aug 2014 11:00:33 +0200 Subject: Removed old code --- ethchain/block_chain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 3b2914a37..74f47aa90 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -176,7 +176,7 @@ func (bc *BlockChain) setLastBlock() { } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { - ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes()) + ethutil.Config.Db.Put([]byte("LTD"), td.Bytes()) bc.TD = td } -- cgit v1.2.3 From 3f904bf3acb5779f68834ebca95825ea1990f85b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 25 Aug 2014 11:29:42 +0200 Subject: Implemented POST --- ethchain/state_transition.go | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 80f9fda5e..1c7eae675 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -278,6 +278,15 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context ret, _, err = callerClosure.Call(vm, self.tx.Data) + if err == nil { + // Execute POSTs + for e := vm.Queue().Front(); e != nil; e = e.Next() { + msg := e.Value.(*ethvm.Message) + + msg.Exec(transactor) + } + } + return } -- cgit v1.2.3 From 6afc16399f9624663579ad72950b4ea3b887db57 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 25 Aug 2014 12:53:06 +0200 Subject: Block size --- ethchain/block.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 5765abd51..d2d012e55 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -351,7 +351,7 @@ func (block *Block) header() []interface{} { func (block *Block) String() string { return fmt.Sprintf(` - BLOCK(%x): + BLOCK(%x): Size: %v PrevHash: %x UncleSha: %x Coinbase: %x @@ -368,6 +368,7 @@ func (block *Block) String() string { NumTx: %v `, block.Hash(), + block.Size(), block.PrevHash, block.UncleSha, block.Coinbase, @@ -384,3 +385,7 @@ func (block *Block) String() string { len(block.transactions), ) } + +func (self *Block) Size() ethutil.StorageSize { + return ethutil.StorageSize(len(self.RlpEncode())) +} -- cgit v1.2.3 From 250d40bca01ae92ef5db6258b519e5903929f764 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 8 Sep 2014 00:48:39 +0200 Subject: Reset the transient state when a new block's been found --- ethchain/state_manager.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 08bd22d29..33af259cf 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -237,6 +237,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Add the block to the chain sm.bc.Add(block) + sm.transState = state.Copy() + // Create a bloom bin for this block filter := sm.createBloomFilter(state) // Persist the data -- cgit v1.2.3 From 0b6b6b52fe1518efef4bcfe9e224cf9209dd8e56 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 8 Sep 2014 00:48:59 +0200 Subject: Contract creation address are empty again --- ethchain/transaction.go | 5 +++-- ethchain/transaction_pool.go | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index e1b48a3d3..e7e8f3a9f 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -13,7 +13,8 @@ import ( var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} func IsContractAddr(addr []byte) bool { - return bytes.Compare(addr, ContractAddr) == 0 + return len(addr) == 0 + //return bytes.Compare(addr, ContractAddr) == 0 } type Transaction struct { @@ -31,7 +32,7 @@ type Transaction struct { } func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Recipient: ContractAddr, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} + return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index b0d62fd91..bd8b27a6d 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -72,8 +72,6 @@ type TxPool struct { func NewTxPool(ethereum EthManager) *TxPool { return &TxPool{ - //server: s, - mutex: sync.Mutex{}, pool: list.New(), queueChan: make(chan *Transaction, txPoolQueueSize), quit: make(chan bool), -- cgit v1.2.3 From 29499900160cc2ee88968b74035f0a5c2d4c5af6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 10 Sep 2014 00:19:20 +0200 Subject: Added CALLSTATELESS --- ethchain/state_transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1c7eae675..c1180a641 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -283,7 +283,7 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context for e := vm.Queue().Front(); e != nil; e = e.Next() { msg := e.Value.(*ethvm.Message) - msg.Exec(transactor) + msg.Exec(msg.Addr(), transactor) } } -- cgit v1.2.3 From 2fb57b2ea7b7f697ddc4811c471d87116eae07cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 00:13:23 +0200 Subject: Reworked filters --- ethchain/filter.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ethchain') diff --git a/ethchain/filter.go b/ethchain/filter.go index 5ed9af977..d9f1796f4 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -23,6 +23,9 @@ type Filter struct { max int altered []data + + BlockCallback func(*Block) + MessageCallback func(ethstate.Messages) } // Create a new filter which uses a bloom filter on blocks to figure out whether a particular block -- cgit v1.2.3 From 954ba211bf8ee63872b5e4d20b6aafb4400507c6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 14 Sep 2014 12:02:35 +0200 Subject: Fixed contract validation address in tx pool --- ethchain/transaction_pool.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index bd8b27a6d..9a6322432 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -99,7 +99,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return fmt.Errorf("[TXPL] No last block on the block chain") } - if len(tx.Recipient) != 20 { + if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 { return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) } @@ -148,7 +148,10 @@ out: // Call blocking version. pool.addTransaction(tx) - txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + tmp := make([]byte, 4) + copy(tmp, tx.Recipient) + + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) -- cgit v1.2.3 From 2f614900e82036e3e8f6f6a714efc43e09aca830 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 01:11:01 +0200 Subject: Updated GHOST --- ethchain/block.go | 13 ++++++++- ethchain/block_chain.go | 2 +- ethchain/error.go | 18 ++++++++++++ ethchain/state_manager.go | 73 ++++++++++++++++++++--------------------------- 4 files changed, 62 insertions(+), 44 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index d2d012e55..fde6ff04a 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -31,11 +31,22 @@ func (bi *BlockInfo) RlpEncode() []byte { return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent}) } +type Blocks []*Block + +func (self Blocks) AsSet() ethutil.UniqueSet { + set := make(ethutil.UniqueSet) + for _, block := range self { + set.Insert(block.Hash()) + } + + return set +} + type Block struct { // Hash to the previous block PrevHash []byte // Uncles of this block - Uncles []*Block + Uncles Blocks UncleSha []byte // The coin base address Coinbase []byte diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 74f47aa90..2d88a0f53 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -60,7 +60,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { if bc.CurrentBlock != nil { var mul *big.Int - if block.Time < lastBlockTime+42 { + if block.Time < lastBlockTime+5 { mul = big.NewInt(1) } else { mul = big.NewInt(-1) diff --git a/ethchain/error.go b/ethchain/error.go index 2cf09a1ec..82949141a 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -25,6 +25,24 @@ func IsParentErr(err error) bool { return ok } +type UncleErr struct { + Message string +} + +func (err *UncleErr) Error() string { + return err.Message +} + +func UncleError(str string) error { + return &UncleErr{Message: str} +} + +func IsUncleErr(err error) bool { + _, ok := err.(*UncleErr) + + return ok +} + // Block validation error. If any validation fails, this error will be thrown type ValidationErr struct { Message string diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 33af259cf..a165ed79d 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -219,7 +219,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err = sm.AccumelateRewards(state, block); err != nil { + if err = sm.AccumelateRewards(state, block, parent); err != nil { statelogger.Errorln("Error accumulating reward", err) return err } @@ -334,36 +334,44 @@ func (sm *StateManager) 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) - } +func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error { + reward := new(big.Int) - return base.Add(base, BlockReward) -} + knownUncles := ethutil.Set(parent.Uncles) + nonces := ethutil.NewSet(block.Nonce) + for _, uncle := range block.Uncles { + if nonces.Include(uncle.Nonce) { + // Error not unique + return UncleError("Uncle not unique") + } -func CalculateUncleReward(block *Block) *big.Int { - return UncleReward -} + uncleParent := sm.bc.GetBlock(uncle.PrevHash) + if uncleParent == nil { + return UncleError("Uncle's parent unknown") + } -func (sm *StateManager) AccumelateRewards(state *ethstate.State, block *Block) error { - // Get the account associated with the coinbase - account := state.GetAccount(block.Coinbase) - // Reward amount of ether to the coinbase address - account.AddAmount(CalculateBlockReward(block, len(block.Uncles))) + if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 { + return UncleError("Uncle too old") + } - addr := make([]byte, len(block.Coinbase)) - copy(addr, block.Coinbase) - state.UpdateStateObject(account) + if knownUncles.Include(uncle.Hash()) { + return UncleError("Uncle in chain") + } + + r := new(big.Int) + r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) - for _, uncle := range block.Uncles { uncleAccount := state.GetAccount(uncle.Coinbase) - uncleAccount.AddAmount(CalculateUncleReward(uncle)) + uncleAccount.AddAmount(r) - state.UpdateStateObject(uncleAccount) + reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) } + // Get the account associated with the coinbase + account := state.GetAccount(block.Coinbase) + // Reward amount of ether to the coinbase address + account.AddAmount(reward) + return nil } @@ -375,14 +383,6 @@ func (sm *StateManager) Stop() { func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { bloomf := NewBloomFilter(nil) - /* - for addr, stateObject := range state.Manifest().ObjectChanges { - // Set the bloom filter's bin - bloomf.Set([]byte(addr)) - - sm.Ethereum.Reactor().Post("object:"+addr, stateObject) - } - */ for _, msg := range state.Manifest().Messages { bloomf.Set(msg.To) bloomf.Set(msg.From) @@ -390,17 +390,6 @@ func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages) - /* - for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges { - for addr, value := range mappedObjects { - // Set the bloom filter's bin - bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr))) - - sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, ðstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value}) - } - } - */ - return bloomf } @@ -420,7 +409,7 @@ func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, sm.ApplyDiff(state, parent, block) - sm.AccumelateRewards(state, block) + sm.AccumelateRewards(state, block, parent) return state.Manifest().Messages, nil } -- cgit v1.2.3 From 33a0dec8a157b9687ca6038f4deb011f3f1f7bdc Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 15:42:12 +0200 Subject: Improved catching up and refactored --- ethchain/block.go | 33 +++++++++++++++++++++++++++++---- ethchain/block_chain.go | 25 ++++++++++++------------- ethchain/state_manager.go | 8 +++++--- 3 files changed, 46 insertions(+), 20 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index fde6ff04a..157be2a52 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "math/big" + "sort" _ "strconv" "time" @@ -42,9 +43,32 @@ func (self Blocks) AsSet() ethutil.UniqueSet { return set } +type BlockBy func(b1, b2 *Block) bool + +func (self BlockBy) Sort(blocks Blocks) { + bs := blockSorter{ + blocks: blocks, + by: self, + } + sort.Sort(bs) +} + +type blockSorter struct { + blocks Blocks + by func(b1, b2 *Block) bool +} + +func (self blockSorter) Len() int { return len(self.blocks) } +func (self blockSorter) Swap(i, j int) { + self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] +} +func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } + +func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 } + type Block struct { // Hash to the previous block - PrevHash []byte + PrevHash ethutil.Bytes // Uncles of this block Uncles Blocks UncleSha []byte @@ -68,7 +92,7 @@ type Block struct { // Extra data Extra string // Block Nonce for verification - Nonce []byte + Nonce ethutil.Bytes // List of transactions and/or contracts transactions []*Transaction receipts []*Receipt @@ -117,8 +141,9 @@ func CreateBlock(root interface{}, } // Returns a hash of the block -func (block *Block) Hash() []byte { - return ethcrypto.Sha3Bin(block.Value().Encode()) +func (block *Block) Hash() ethutil.Bytes { + return ethcrypto.Sha3Bin(ethutil.NewValue(block.header()).Encode()) + //return ethcrypto.Sha3Bin(block.Value().Encode()) } func (block *Block) HashNoNonce() []byte { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2d88a0f53..5d0d652df 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -58,24 +58,20 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { block.MinGasPrice = big.NewInt(10000000000000) - if bc.CurrentBlock != nil { - var mul *big.Int - if block.Time < lastBlockTime+5 { - mul = big.NewInt(1) + parent := bc.CurrentBlock + if parent != nil { + diff := new(big.Int) + + adjust := new(big.Int).Rsh(parent.Difficulty, 10) + if block.Time >= lastBlockTime+5 { + diff.Sub(parent.Difficulty, adjust) } else { - mul = big.NewInt(-1) + diff.Add(parent.Difficulty, adjust) } - - 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 - block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) + } return block @@ -159,6 +155,9 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() + if bc.LastBlockNumber == 0 { + bc.genesisBlock = block + } } else { AddTestNetFunds(bc.genesisBlock) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a165ed79d..1ccaa560f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -217,13 +217,13 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return err } - // I'm not sure, but I don't know if there should be thrown - // any errors at this time. if err = sm.AccumelateRewards(state, block, parent); err != nil { statelogger.Errorln("Error accumulating reward", err) return err } + state.Update() + if !block.State().Cmp(state) { err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root) return @@ -335,7 +335,7 @@ func (sm *StateManager) ValidateBlock(block *Block) error { } func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error { - reward := new(big.Int) + reward := new(big.Int).Set(BlockReward) knownUncles := ethutil.Set(parent.Uncles) nonces := ethutil.NewSet(block.Nonce) @@ -358,6 +358,8 @@ func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent * return UncleError("Uncle in chain") } + nonces.Insert(uncle.Nonce) + r := new(big.Int) r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) -- cgit v1.2.3 From 399256b38403f2e95312250d49fca3cada8956b8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 15 Sep 2014 22:11:05 +0200 Subject: VM execution fixes Refactoring caused executing issues --- ethchain/block_chain.go | 8 +++----- ethchain/state_manager.go | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 5d0d652df..1e29f1188 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -148,6 +148,9 @@ func AddTestNetFunds(block *Block) { } func (bc *BlockChain) setLastBlock() { + // Prep genesis + AddTestNetFunds(bc.genesisBlock) + data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { block := NewBlockFromBytes(data) @@ -155,12 +158,7 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() - if bc.LastBlockNumber == 0 { - bc.genesisBlock = block - } } else { - AddTestNetFunds(bc.genesisBlock) - bc.genesisBlock.state.Trie.Sync() // Prepare the genesis block bc.Add(bc.genesisBlock) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1ccaa560f..b0ea754f4 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -5,6 +5,7 @@ import ( "container/list" "fmt" "math/big" + "os" "sync" "time" @@ -154,6 +155,10 @@ done: if i < len(block.Receipts()) { original := block.Receipts()[i] if !original.Cmp(receipt) { + if ethutil.Config.Diff { + os.Exit(1) + } + return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) } } @@ -307,14 +312,16 @@ func (sm *StateManager) ValidateBlock(block *Block) error { // 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 := sm.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) + parent := sm.bc.GetBlock(block.PrevHash) + /* + for _, uncle := range block.Uncles { + if bytes.Compare(uncle.PrevHash,parent.PrevHash) != 0 { + return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x",parent.PrevHash, uncle.PrevHash) + } } - } + */ - diff := block.Time - previousBlock.Time + diff := block.Time - parent.Time if diff < 0 { return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time) } -- cgit v1.2.3 From f3a93b046e45a293b673a955959666ec5389c4eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 18 Sep 2014 01:02:15 +0200 Subject: Upped protocol version for VM change --- ethchain/fees.go | 2 -- 1 file changed, 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/fees.go b/ethchain/fees.go index 743be86a2..901357439 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -5,5 +5,3 @@ import ( ) var BlockReward *big.Int = big.NewInt(1.5e+18) -var UncleReward *big.Int = big.NewInt(1.125e+18) -var UncleInclusionReward *big.Int = big.NewInt(1.875e+17) -- cgit v1.2.3 From 863785a52046bcfbbcaa57c83b4b43c215368760 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 18 Sep 2014 16:48:42 +0200 Subject: Updated opcodes --- ethchain/types.go | 244 ++++++++++++++++++++++++------------------------------ 1 file changed, 106 insertions(+), 138 deletions(-) (limited to 'ethchain') diff --git a/ethchain/types.go b/ethchain/types.go index 9e7269f74..45486b06c 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -27,10 +27,12 @@ const ( NOT = 0x0f // 0x10 range - bit ops - AND = 0x10 - OR = 0x11 - XOR = 0x12 - BYTE = 0x13 + AND = 0x10 + OR = 0x11 + XOR = 0x12 + BYTE = 0x13 + ADDMOD = 0x14 + MULMOD = 0x15 // 0x20 range - crypto SHA3 = 0x20 @@ -47,6 +49,8 @@ const ( CODESIZE = 0x38 CODECOPY = 0x39 GASPRICE = 0x3a + EXTCODECOPY = 0x3b + EXTCODESIZE = 0x3c // 0x40 range - block operations PREVHASH = 0x40 @@ -57,9 +61,9 @@ const ( GASLIMIT = 0x45 // 0x50 range - 'storage' and execution - POP = 0x50 - DUP = 0x51 - SWAP = 0x52 + POP = 0x50 + //DUP = 0x51 + //SWAP = 0x52 MLOAD = 0x53 MSTORE = 0x54 MSTORE8 = 0x55 @@ -105,10 +109,46 @@ const ( PUSH31 = 0x7e PUSH32 = 0x7f + DUP1 = 0x80 + DUP2 = 0x81 + DUP3 = 0x82 + DUP4 = 0x83 + DUP5 = 0x84 + DUP6 = 0x85 + DUP7 = 0x86 + DUP8 = 0x87 + DUP9 = 0x88 + DUP10 = 0x89 + DUP11 = 0x8a + DUP12 = 0x8b + DUP13 = 0x8c + DUP14 = 0x8d + DUP15 = 0x8e + DUP16 = 0x8f + + SWAP1 = 0x90 + SWAP2 = 0x91 + SWAP3 = 0x92 + SWAP4 = 0x93 + SWAP5 = 0x94 + SWAP6 = 0x95 + SWAP7 = 0x96 + SWAP8 = 0x97 + SWAP9 = 0x98 + SWAP10 = 0x99 + SWAP11 = 0x9a + SWAP12 = 0x9b + SWAP13 = 0x9c + SWAP14 = 0x9d + SWAP15 = 0x9e + SWAP16 = 0x9f + // 0xf0 range - closures - CREATE = 0xf0 - CALL = 0xf1 - RETURN = 0xf2 + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 + POST = 0xf3 + CALLSTATELESS = 0xf4 // 0x70 range - other LOG = 0xfe // XXX Unofficial @@ -136,10 +176,12 @@ var opCodeToString = map[OpCode]string{ NOT: "NOT", // 0x10 range - bit ops - AND: "AND", - OR: "OR", - XOR: "XOR", - BYTE: "BYTE", + AND: "AND", + OR: "OR", + XOR: "XOR", + BYTE: "BYTE", + ADDMOD: "ADDMOD", + MULMOD: "MULMOD", // 0x20 range - crypto SHA3: "SHA3", @@ -158,17 +200,19 @@ var opCodeToString = map[OpCode]string{ GASPRICE: "TXGASPRICE", // 0x40 range - block operations - PREVHASH: "PREVHASH", - COINBASE: "COINBASE", - TIMESTAMP: "TIMESTAMP", - NUMBER: "NUMBER", - DIFFICULTY: "DIFFICULTY", - GASLIMIT: "GASLIMIT", + PREVHASH: "PREVHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", // 0x50 range - 'storage' and execution - POP: "POP", - DUP: "DUP", - SWAP: "SWAP", + POP: "POP", + //DUP: "DUP", + //SWAP: "SWAP", MLOAD: "MLOAD", MSTORE: "MSTORE", MSTORE8: "MSTORE8", @@ -214,10 +258,46 @@ var opCodeToString = map[OpCode]string{ PUSH31: "PUSH31", PUSH32: "PUSH32", + DUP1: "DUP1", + DUP2: "DUP2", + DUP3: "DUP3", + DUP4: "DUP4", + DUP5: "DUP5", + DUP6: "DUP6", + DUP7: "DUP7", + DUP8: "DUP8", + DUP9: "DUP9", + DUP10: "DUP10", + DUP11: "DUP11", + DUP12: "DUP12", + DUP13: "DUP13", + DUP14: "DUP14", + DUP15: "DUP15", + DUP16: "DUP16", + + SWAP1: "SWAP1", + SWAP2: "SWAP2", + SWAP3: "SWAP3", + SWAP4: "SWAP4", + SWAP5: "SWAP5", + SWAP6: "SWAP6", + SWAP7: "SWAP7", + SWAP8: "SWAP8", + SWAP9: "SWAP9", + SWAP10: "SWAP10", + SWAP11: "SWAP11", + SWAP12: "SWAP12", + SWAP13: "SWAP13", + SWAP14: "SWAP14", + SWAP15: "SWAP15", + SWAP16: "SWAP16", + // 0xf0 range - CREATE: "CREATE", - CALL: "CALL", - RETURN: "RETURN", + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", + POST: "POST", + CALLSTATELESS: "CALLSTATELESS", // 0x70 range - other LOG: "LOG", @@ -232,115 +312,3 @@ func (o OpCode) String() string { return str } - -// Op codes for assembling -var OpCodes = map[string]byte{ - // 0x0 range - arithmetic ops - "STOP": 0x00, - "ADD": 0x01, - "MUL": 0x02, - "SUB": 0x03, - "DIV": 0x04, - "SDIV": 0x05, - "MOD": 0x06, - "SMOD": 0x07, - "EXP": 0x08, - "NEG": 0x09, - "LT": 0x0a, - "GT": 0x0b, - "EQ": 0x0c, - "NOT": 0x0d, - - // 0x10 range - bit ops - "AND": 0x10, - "OR": 0x11, - "XOR": 0x12, - "BYTE": 0x13, - - // 0x20 range - crypto - "SHA3": 0x20, - - // 0x30 range - closure state - "ADDRESS": 0x30, - "BALANCE": 0x31, - "ORIGIN": 0x32, - "CALLER": 0x33, - "CALLVALUE": 0x34, - "CALLDATALOAD": 0x35, - "CALLDATASIZE": 0x36, - "GASPRICE": 0x38, - - // 0x40 range - block operations - "PREVHASH": 0x40, - "COINBASE": 0x41, - "TIMESTAMP": 0x42, - "NUMBER": 0x43, - "DIFFICULTY": 0x44, - "GASLIMIT": 0x45, - - // 0x50 range - 'storage' and execution - "POP": 0x51, - "DUP": 0x52, - "SWAP": 0x53, - "MLOAD": 0x54, - "MSTORE": 0x55, - "MSTORE8": 0x56, - "SLOAD": 0x57, - "SSTORE": 0x58, - "JUMP": 0x59, - "JUMPI": 0x5a, - "PC": 0x5b, - "MSIZE": 0x5c, - - // 0x70 range - 'push' - "PUSH1": 0x60, - "PUSH2": 0x61, - "PUSH3": 0x62, - "PUSH4": 0x63, - "PUSH5": 0x64, - "PUSH6": 0x65, - "PUSH7": 0x66, - "PUSH8": 0x67, - "PUSH9": 0x68, - "PUSH10": 0x69, - "PUSH11": 0x6a, - "PUSH12": 0x6b, - "PUSH13": 0x6c, - "PUSH14": 0x6d, - "PUSH15": 0x6e, - "PUSH16": 0x6f, - "PUSH17": 0x70, - "PUSH18": 0x71, - "PUSH19": 0x72, - "PUSH20": 0x73, - "PUSH21": 0x74, - "PUSH22": 0x75, - "PUSH23": 0x76, - "PUSH24": 0x77, - "PUSH25": 0x78, - "PUSH26": 0x70, - "PUSH27": 0x7a, - "PUSH28": 0x7b, - "PUSH29": 0x7c, - "PUSH30": 0x7d, - "PUSH31": 0x7e, - "PUSH32": 0x7f, - - // 0xf0 range - closures - "CREATE": 0xf0, - "CALL": 0xf1, - "RETURN": 0xf2, - - // 0x70 range - other - "LOG": 0xfe, - "SUICIDE": 0x7f, -} - -func IsOpCode(s string) bool { - for key, _ := range OpCodes { - if key == s { - return true - } - } - return false -} -- cgit v1.2.3 From 80261c803a82e51413608a3dc5273c982844d135 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 19 Sep 2014 13:19:19 +0200 Subject: Fixed deref ptr --- ethchain/block_chain.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 1e29f1188..7c9b60fc5 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -164,6 +164,7 @@ func (bc *BlockChain) setLastBlock() { bc.Add(bc.genesisBlock) fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) bc.Ethereum.Db().Put(fk, make([]byte, 255)) + bc.CurrentBlock = bc.genesisBlock } // Set the last know difficulty (might be 0x0 as initial value, Genesis) @@ -201,10 +202,13 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block { func (self *BlockChain) GetBlockByNumber(num uint64) *Block { block := self.CurrentBlock - for ; block.Number.Uint64() != num; block = self.GetBlock(block.PrevHash) { + for ; block != nil; block = self.GetBlock(block.PrevHash) { + if block.Number.Uint64() == num { + break + } } - if block.Number.Uint64() == 0 && num != 0 { + if block != nil && block.Number.Uint64() == 0 && num != 0 { return nil } -- cgit v1.2.3 From 6800c3665a50f7ac624f4ecbaa474b8a81336143 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 23 Sep 2014 17:55:34 +0200 Subject: Re-added min gas price check on tx pool --- ethchain/transaction_pool.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 9a6322432..0f7e85982 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -27,6 +27,8 @@ const ( minGasPrice = 1000000 ) +var MinGasPrice = big.NewInt(10000000000000) + type TxMsg struct { Tx *Transaction Type TxMsgTy @@ -103,6 +105,10 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) } + if tx.GasPrice.Cmp(MinGasPrice) >= 0 { + return fmt.Errorf("Gas price to low. Require %v > Got %v", MinGasPrice, tx.GasPrice) + } + // Get the sender //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) -- cgit v1.2.3 From 46a496428f2d2a3a0f9ddcb755c825dfc1f73436 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 23 Sep 2014 18:19:51 +0200 Subject: ugh --- ethchain/transaction_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 0f7e85982..da6c3d6ba 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -105,7 +105,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) } - if tx.GasPrice.Cmp(MinGasPrice) >= 0 { + if tx.GasPrice.Cmp(MinGasPrice) < 0 { return fmt.Errorf("Gas price to low. Require %v > Got %v", MinGasPrice, tx.GasPrice) } -- cgit v1.2.3 From 57dc435f9b928f5de2a49736a2c71a7bf611289a Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 24 Sep 2014 11:39:17 +0200 Subject: Added TD for each block --- ethchain/block.go | 4 +++- ethchain/block_chain.go | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 157be2a52..5e8aca33a 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -18,6 +18,7 @@ type BlockInfo struct { Number uint64 Hash []byte Parent []byte + TD *big.Int } func (bi *BlockInfo) RlpDecode(data []byte) { @@ -26,10 +27,11 @@ func (bi *BlockInfo) RlpDecode(data []byte) { bi.Number = decoder.Get(0).Uint() bi.Hash = decoder.Get(1).Bytes() bi.Parent = decoder.Get(2).Bytes() + bi.TD = decoder.Get(3).BigInt() } func (bi *BlockInfo) RlpEncode() []byte { - return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent}) + return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent, bi.TD}) } type Blocks []*Block diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 7c9b60fc5..c8e5c610e 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,6 +2,7 @@ package ethchain import ( "bytes" + "fmt" "math/big" "github.com/ethereum/eth-go/ethlog" @@ -191,6 +192,26 @@ func (bc *BlockChain) Add(block *Block) { ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) } +func (self *BlockChain) CalcTotalDiff(block *Block) (*big.Int, error) { + parent := self.GetBlock(block.PrevHash) + if parent == nil { + return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) + } + + parentTd := parent.BlockInfo().TD + + uncleDiff := new(big.Int) + for _, uncle := range block.Uncles { + uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) + } + + td := new(big.Int) + td = td.Add(parentTd, uncleDiff) + td = td.Add(td, block.Difficulty) + + return td, nil +} + func (bc *BlockChain) GetBlock(hash []byte) *Block { data, _ := ethutil.Config.Db.Get(hash) if len(data) == 0 { @@ -234,7 +255,7 @@ func (bc *BlockChain) BlockInfo(block *Block) BlockInfo { // 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} + bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD} // 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()) -- cgit v1.2.3 From d3a0bb4f3535dda89c3cb1d26ff3168faaaf7ca6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 24 Sep 2014 19:54:14 +0200 Subject: Info => Debug --- ethchain/state_manager.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index b0ea754f4..888c68bb9 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -250,15 +250,13 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { fk := append([]byte("bloom"), block.Hash()...) sm.Ethereum.Db().Put(fk, filter.Bin()) - statelogger.Infof("Added block #%d (%x)\n", block.Number, block.Hash()) + statelogger.Debugf("Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) state.Manifest().Reset() } - sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) - sm.Ethereum.TxPool().RemoveInvalid(state) } else { statelogger.Errorln("total diff failed") -- cgit v1.2.3 From 68119d0929adebdbd39dd40982264f86164bd6e6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 26 Sep 2014 13:32:54 +0200 Subject: Fixed messages to use proper numbers --- ethchain/block_chain.go | 10 ++++++ ethchain/filter.go | 95 +++++++++++++++++++++---------------------------- 2 files changed, 50 insertions(+), 55 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index c8e5c610e..467c54058 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -236,6 +236,16 @@ func (self *BlockChain) GetBlockByNumber(num uint64) *Block { return block } +func (self *BlockChain) GetBlockBack(num uint64) *Block { + block := self.CurrentBlock + + for ; num != 0 && block != nil; num-- { + block = self.GetBlock(block.PrevHash) + } + + return block +} + func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { bi := BlockInfo{} data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) diff --git a/ethchain/filter.go b/ethchain/filter.go index d9f1796f4..0a97b3f98 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "fmt" + "math" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" @@ -16,8 +17,8 @@ type data struct { // Filtering interface type Filter struct { eth EthManager - earliest []byte - latest []byte + earliest int64 + latest int64 skip int from, to [][]byte max int @@ -38,37 +39,33 @@ func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { filter := NewFilter(eth) if object["earliest"] != nil { - earliest := object["earliest"] - if e, ok := earliest.(string); ok { - filter.SetEarliestBlock(ethutil.Hex2Bytes(e)) - } else { - filter.SetEarliestBlock(earliest) - } + val := ethutil.NewValue(object["earliest"]) + filter.SetEarliestBlock(val.Int()) } if object["latest"] != nil { - latest := object["latest"] - if l, ok := latest.(string); ok { - filter.SetLatestBlock(ethutil.Hex2Bytes(l)) - } else { - filter.SetLatestBlock(latest) - } + val := ethutil.NewValue(object["latest"]) + filter.SetLatestBlock(val.Int()) } if object["to"] != nil { - filter.AddTo(ethutil.Hex2Bytes(object["to"].(string))) + val := ethutil.NewValue(object["to"]) + filter.AddTo(ethutil.Hex2Bytes(val.Str())) } if object["from"] != nil { - filter.AddFrom(ethutil.Hex2Bytes(object["from"].(string))) + val := ethutil.NewValue(object["from"]) + filter.AddFrom(ethutil.Hex2Bytes(val.Str())) } if object["max"] != nil { - filter.SetMax(object["max"].(int)) + val := ethutil.NewValue(object["max"]) + filter.SetMax(int(val.Uint())) } if object["skip"] != nil { - filter.SetSkip(object["skip"].(int)) + val := ethutil.NewValue(object["skip"]) + filter.SetSkip(int(val.Uint())) } if object["altered"] != nil { @@ -85,30 +82,12 @@ func (self *Filter) AddAltered(id, address []byte) { // Set the earliest and latest block for filtering. // -1 = latest block (i.e., the current block) // hash = particular hash from-to -func (self *Filter) SetEarliestBlock(earliest interface{}) { - e := ethutil.NewValue(earliest) - - // Check for -1 (latest) otherwise assume bytes - if e.Int() == -1 { - self.earliest = self.eth.BlockChain().CurrentBlock.Hash() - } else if e.Len() > 0 { - self.earliest = e.Bytes() - } else { - panic(fmt.Sprintf("earliest has to be either -1 or a valid hash: %v (%T)", e, e.Val)) - } +func (self *Filter) SetEarliestBlock(earliest int64) { + self.earliest = earliest } -func (self *Filter) SetLatestBlock(latest interface{}) { - l := ethutil.NewValue(latest) - - // Check for -1 (latest) otherwise assume bytes - if l.Int() == -1 { - self.latest = self.eth.BlockChain().CurrentBlock.Hash() - } else if l.Len() > 0 { - self.latest = l.Bytes() - } else { - panic(fmt.Sprintf("latest has to be either -1 or a valid hash: %v", l)) - } +func (self *Filter) SetLatestBlock(latest int64) { + self.latest = latest } func (self *Filter) SetFrom(addr [][]byte) { @@ -137,23 +116,27 @@ func (self *Filter) SetSkip(skip int) { // Run filters messages with the current parameters set func (self *Filter) Find() []*ethstate.Message { - var messages []*ethstate.Message - - block := self.eth.BlockChain().GetBlock(self.latest) - - // skip N blocks (useful for pagination) - if self.skip > 0 { - for i := 0; i < i; i++ { - block = self.eth.BlockChain().GetBlock(block.PrevHash) - } + var earliestBlockNo uint64 = uint64(self.earliest) + if self.earliest == -1 { + earliestBlockNo = self.eth.BlockChain().CurrentBlock.Number.Uint64() + } + var latestBlockNo uint64 = uint64(self.latest) + if self.latest == -1 { + latestBlockNo = self.eth.BlockChain().CurrentBlock.Number.Uint64() } - // Start block filtering - quit := false - for i := 1; !quit && block != nil; i++ { - // Mark last check - if self.max == i || (len(self.earliest) > 0 && bytes.Compare(block.Hash(), self.earliest) == 0) { + var ( + messages []*ethstate.Message + block = self.eth.BlockChain().GetBlockByNumber(latestBlockNo) + quit bool + ) + for i := 0; !quit && block != nil; i++ { + // Quit on latest + switch { + case block.Number.Uint64() == earliestBlockNo: quit = true + case self.max <= len(messages): + break } // Use bloom filtering to see if this block is interesting given the @@ -173,7 +156,9 @@ func (self *Filter) Find() []*ethstate.Message { block = self.eth.BlockChain().GetBlock(block.PrevHash) } - return messages + skip := int(math.Min(float64(len(messages)), float64(self.skip))) + + return messages[skip:] } func includes(addresses [][]byte, a []byte) (found bool) { -- cgit v1.2.3 From b8354124bebcd3988afd2f41c320f834a69b949e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 26 Sep 2014 13:45:26 +0200 Subject: Added protocol caps accessors --- ethchain/state_manager.go | 1 + 1 file changed, 1 insertion(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 888c68bb9..8088f6735 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -32,6 +32,7 @@ type Peer interface { Version() string PingTime() string Connected() *int32 + Caps() *ethutil.Value } type EthManager interface { -- cgit v1.2.3 From e20b11305366c8d05ea626eda0bb46fba5b373ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 26 Sep 2014 20:19:11 +0200 Subject: Logging messages --- ethchain/state_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8088f6735..6bcbe063e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -251,7 +251,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { fk := append([]byte("bloom"), block.Hash()...) sm.Ethereum.Db().Put(fk, filter.Bin()) - statelogger.Debugf("Added block #%d (%x)\n", block.Number, block.Hash()) + statelogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4]) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) -- cgit v1.2.3 From ea0357bf02b61db94bd0ad8806ba7337a55a4f79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 28 Sep 2014 14:52:58 +0200 Subject: Block pool is thread safe --- ethchain/state_manager.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 6bcbe063e..cd2d57af9 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -143,9 +143,6 @@ done: } } - // Notify all subscribers - self.Ethereum.Reactor().Post("newTx:post", tx) - // Update the state with pending changes state.Update() @@ -160,10 +157,15 @@ done: os.Exit(1) } - return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()) + err := fmt.Errorf("#%d receipt failed (r) %v ~ %x <=> (c) %v ~ %x (%x...)", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash()[0:4]) + + return nil, nil, nil, err } } + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + receipts = append(receipts, receipt) handled = append(handled, tx) -- cgit v1.2.3 From ab6ede51d7fedb9270cab08ee732a834be34dab2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 29 Sep 2014 12:57:51 +0200 Subject: Working on new (blocking) event machine. The new event machine will be used for loose coupling and handle the communications between the services: 1) Block pool finds blocks which "links" with our current canonical chain 2) Posts the blocks on to the event machine 3) State manager receives blocks & processes them 4) Broadcasts new post block event --- ethchain/block_chain_test.go | 144 ------------------------------------------- ethchain/helper_test.go | 88 ++++++++++++++++++++++++++ ethchain/state_manager.go | 71 +++++++++++++++------ 3 files changed, 139 insertions(+), 164 deletions(-) create mode 100644 ethchain/helper_test.go (limited to 'ethchain') diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 1edcf9c7b..3603fd8a7 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -1,145 +1 @@ package ethchain - -import ( - "container/list" - "fmt" - "testing" - - "github.com/ethereum/eth-go/ethcrypto" - "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/ethreact" - "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" -) - -// Implement our EthTest Manager -type TestManager struct { - stateManager *StateManager - reactor *ethreact.ReactorEngine - - txPool *TxPool - blockChain *BlockChain - Blocks []*Block -} - -func (s *TestManager) IsListening() bool { - return false -} - -func (s *TestManager) IsMining() bool { - return false -} - -func (s *TestManager) PeerCount() int { - return 0 -} - -func (s *TestManager) Peers() *list.List { - return list.New() -} - -func (s *TestManager) BlockChain() *BlockChain { - return s.blockChain -} - -func (tm *TestManager) TxPool() *TxPool { - return tm.txPool -} - -func (tm *TestManager) StateManager() *StateManager { - return tm.stateManager -} - -func (tm *TestManager) Reactor() *ethreact.ReactorEngine { - return tm.reactor -} -func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { - fmt.Println("Broadcast not implemented") -} - -func (tm *TestManager) ClientIdentity() ethwire.ClientIdentity { - return nil -} -func (tm *TestManager) KeyManager() *ethcrypto.KeyManager { - return nil -} - -func (tm *TestManager) Db() ethutil.Database { return nil } - -func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH") - - db, err := ethdb.NewMemDatabase() - if err != nil { - fmt.Println("Could not create mem-db, failing") - return nil - } - ethutil.Config.Db = db - - testManager := &TestManager{} - testManager.reactor = ethreact.New() - - testManager.txPool = NewTxPool(testManager) - testManager.blockChain = NewBlockChain(testManager) - testManager.stateManager = NewStateManager(testManager) - - // Start the tx pool - testManager.txPool.Start() - - return testManager -} - -func (tm *TestManager) AddFakeBlock(blk []byte) error { - block := NewBlockFromBytes(blk) - tm.Blocks = append(tm.Blocks, block) - err := tm.StateManager().Process(block, false) - return err -} - -func (tm *TestManager) CreateChain1() error { - err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 32, 251, 128, 160, 4, 10, 11, 225, 132, 86, 146, 227, 229, 137, 164, 245, 16, 139, 219, 12, 251, 178, 154, 168, 210, 18, 84, 40, 250, 41, 124, 92, 169, 242, 246, 180, 192, 192}) - err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 222, 229, 152, 228, 200, 163, 244, 144, 120, 18, 203, 253, 195, 185, 105, 131, 163, 226, 116, 40, 140, 68, 249, 198, 221, 152, 121, 0, 124, 11, 180, 125, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 224, 4, 132, 83, 48, 36, 250, 128, 160, 79, 58, 51, 246, 238, 249, 210, 253, 136, 83, 71, 134, 49, 114, 190, 189, 242, 78, 100, 238, 101, 84, 204, 176, 198, 25, 139, 151, 60, 84, 51, 126, 192, 192}) - err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 68, 52, 33, 210, 160, 189, 217, 255, 78, 37, 196, 217, 94, 247, 166, 169, 224, 199, 102, 110, 85, 213, 45, 13, 173, 106, 4, 103, 151, 195, 38, 86, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 208, 12, 132, 83, 48, 38, 206, 128, 160, 65, 147, 32, 128, 177, 198, 131, 57, 57, 68, 135, 65, 198, 178, 138, 43, 25, 135, 92, 174, 208, 119, 103, 225, 26, 207, 243, 31, 225, 29, 173, 119, 192, 192}) - return err -} -func (tm *TestManager) CreateChain2() error { - err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 40, 35, 128, 160, 162, 214, 119, 207, 212, 186, 64, 47, 14, 186, 98, 118, 203, 79, 172, 205, 33, 206, 225, 177, 225, 194, 98, 188, 63, 219, 13, 151, 47, 32, 204, 27, 192, 192}) - err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 0, 210, 76, 6, 13, 18, 219, 190, 18, 250, 23, 178, 198, 117, 254, 85, 14, 74, 104, 116, 56, 144, 116, 172, 14, 3, 236, 99, 248, 228, 142, 91, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 255, 252, 132, 83, 48, 40, 74, 128, 160, 185, 20, 138, 2, 210, 15, 71, 144, 89, 167, 94, 155, 148, 118, 170, 157, 122, 70, 70, 114, 50, 221, 231, 8, 132, 167, 115, 239, 44, 245, 41, 226, 192, 192}) - return err -} - -func TestNegativeBlockChainReorg(t *testing.T) { - // We are resetting the database between creation so we need to cache our information - testManager2 := NewTestManager() - testManager2.CreateChain2() - tm2Blocks := testManager2.Blocks - - testManager := NewTestManager() - testManager.CreateChain1() - oldState := testManager.BlockChain().CurrentBlock.State() - - if testManager.BlockChain().FindCanonicalChain(tm2Blocks, testManager.BlockChain().GenesisBlock().Hash()) != true { - t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.") - } - if testManager.BlockChain().CurrentBlock.State() != oldState { - t.Error("I expected the top state to be the same as it was as before the reorg") - } - -} - -func TestPositiveBlockChainReorg(t *testing.T) { - testManager := NewTestManager() - testManager.CreateChain1() - tm1Blocks := testManager.Blocks - - testManager2 := NewTestManager() - testManager2.CreateChain2() - oldState := testManager2.BlockChain().CurrentBlock.State() - - if testManager2.BlockChain().FindCanonicalChain(tm1Blocks, testManager.BlockChain().GenesisBlock().Hash()) == true { - t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.") - } - if testManager2.BlockChain().CurrentBlock.State() == oldState { - t.Error("I expected the top state to have been modified but it was not") - } -} diff --git a/ethchain/helper_test.go b/ethchain/helper_test.go new file mode 100644 index 000000000..75d7771fc --- /dev/null +++ b/ethchain/helper_test.go @@ -0,0 +1,88 @@ +package ethchain + +import ( + "container/list" + "fmt" + + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethreact" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" +) + +// Implement our EthTest Manager +type TestManager struct { + stateManager *StateManager + reactor *ethreact.ReactorEngine + + txPool *TxPool + blockChain *BlockChain + Blocks []*Block +} + +func (s *TestManager) IsListening() bool { + return false +} + +func (s *TestManager) IsMining() bool { + return false +} + +func (s *TestManager) PeerCount() int { + return 0 +} + +func (s *TestManager) Peers() *list.List { + return list.New() +} + +func (s *TestManager) BlockChain() *BlockChain { + return s.blockChain +} + +func (tm *TestManager) TxPool() *TxPool { + return tm.txPool +} + +func (tm *TestManager) StateManager() *StateManager { + return tm.stateManager +} + +func (tm *TestManager) Reactor() *ethreact.ReactorEngine { + return tm.reactor +} +func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { + fmt.Println("Broadcast not implemented") +} + +func (tm *TestManager) ClientIdentity() ethwire.ClientIdentity { + return nil +} +func (tm *TestManager) KeyManager() *ethcrypto.KeyManager { + return nil +} + +func (tm *TestManager) Db() ethutil.Database { return nil } +func NewTestManager() *TestManager { + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH") + + db, err := ethdb.NewMemDatabase() + if err != nil { + fmt.Println("Could not create mem-db, failing") + return nil + } + ethutil.Config.Db = db + + testManager := &TestManager{} + testManager.reactor = ethreact.New() + + testManager.txPool = NewTxPool(testManager) + testManager.blockChain = NewBlockChain(testManager) + testManager.stateManager = NewStateManager(testManager) + + // Start the tx pool + testManager.txPool.Start() + + return testManager +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index cd2d57af9..f38666572 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -15,14 +15,11 @@ import ( "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "github.com/ethereum/eth-go/eventer" ) var statelogger = ethlog.NewLogger("STATE") -type BlockProcessor interface { - ProcessBlock(block *Block) -} - type Peer interface { Inbound() bool LastSend() time.Time @@ -48,6 +45,7 @@ type EthManager interface { KeyManager() *ethcrypto.KeyManager ClientIdentity() ethwire.ClientIdentity Db() ethutil.Database + Eventer() *eventer.EventMachine } type StateManager struct { @@ -60,7 +58,7 @@ type StateManager struct { // Proof of work used for validating Pow PoW // The ethereum manager interface - Ethereum EthManager + eth EthManager // The managed states // Transiently state. The trans state isn't ever saved, validated and // it could be used for setting account nonces without effecting @@ -74,14 +72,18 @@ type StateManager struct { // This does not have to be a valid block and will be set during // 'Process' & canonical validation. lastAttemptedBlock *Block + + // Quit chan + quit chan bool } func NewStateManager(ethereum EthManager) *StateManager { sm := &StateManager{ - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Ethereum: ethereum, - bc: ethereum.BlockChain(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + eth: ethereum, + bc: ethereum.BlockChain(), + quit: make(chan bool), } sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy() sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy() @@ -89,8 +91,41 @@ func NewStateManager(ethereum EthManager) *StateManager { return sm } +func (self *StateManager) Start() { + statelogger.Debugln("Starting state manager") + + go self.updateThread() +} + +func (self *StateManager) Stop() { + statelogger.Debugln("Stopping state manager") + + close(self.quit) +} + +func (self *StateManager) updateThread() { + blockChan := self.eth.Eventer().Register("block") + +out: + for { + select { + case event := <-blockChan: + block := event.Data.(*Block) + err := self.Process(block, false) + if err != nil { + statelogger.Infoln(err) + statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) + statelogger.Debugln(block) + } + + case <-self.quit: + break out + } + } +} + func (sm *StateManager) CurrentState() *ethstate.State { - return sm.Ethereum.BlockChain().CurrentBlock.State() + return sm.eth.BlockChain().CurrentBlock.State() } func (sm *StateManager) TransState() *ethstate.State { @@ -102,7 +137,7 @@ func (sm *StateManager) MiningState() *ethstate.State { } func (sm *StateManager) NewMiningState() *ethstate.State { - sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy() + sm.miningState = sm.eth.BlockChain().CurrentBlock.State().Copy() return sm.miningState } @@ -164,7 +199,7 @@ done: } // Notify all subscribers - self.Ethereum.Reactor().Post("newTx:post", tx) + self.eth.Reactor().Post("newTx:post", tx) receipts = append(receipts, receipt) handled = append(handled, tx) @@ -251,16 +286,16 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { filter := sm.createBloomFilter(state) // Persist the data fk := append([]byte("bloom"), block.Hash()...) - sm.Ethereum.Db().Put(fk, filter.Bin()) + sm.eth.Db().Put(fk, filter.Bin()) statelogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4]) if dontReact == false { - sm.Ethereum.Reactor().Post("newBlock", block) + sm.eth.Reactor().Post("newBlock", block) state.Manifest().Reset() } - sm.Ethereum.TxPool().RemoveInvalid(state) + sm.eth.TxPool().RemoveInvalid(state) } else { statelogger.Errorln("total diff failed") } @@ -385,10 +420,6 @@ func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent * return nil } -func (sm *StateManager) Stop() { - sm.bc.Stop() -} - // Manifest will handle both creating notifications and generating bloom bin data func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { bloomf := NewBloomFilter(nil) @@ -398,7 +429,7 @@ func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { bloomf.Set(msg.From) } - sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages) + sm.eth.Reactor().Post("messages", state.Manifest().Messages) return bloomf } -- cgit v1.2.3 From 3af211dd65d6690afce9976a9f47ab1cdddb8d58 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 30 Sep 2014 23:26:52 +0200 Subject: Implemented WebSocket package --- ethchain/state_transition.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index c1180a641..096464963 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -142,14 +142,12 @@ func (self *StateTransition) preCheck() (err error) { func (self *StateTransition) TransitionState() (err error) { statelogger.Debugf("(~) %x\n", self.tx.Hash()) - /* - defer func() { - if r := recover(); r != nil { - logger.Infoln(r) - err = fmt.Errorf("state transition err %v", r) - } - }() - */ + defer func() { + if r := recover(); r != nil { + statelogger.Infoln(r) + err = fmt.Errorf("state transition err %v", r) + } + }() // XXX Transactions after this point are considered valid. if err = self.preCheck(); err != nil { -- cgit v1.2.3 From 82be3054961864dfd5bbeaec2ab961f593203dbf Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 2 Oct 2014 17:03:15 +0200 Subject: Fixed inconsistencies --- ethchain/state_manager.go | 17 ++++++++++------- ethchain/state_transition.go | 4 ++-- ethchain/transaction.go | 11 +++++++++-- 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f38666572..93fd1ec58 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -104,18 +104,21 @@ func (self *StateManager) Stop() { } func (self *StateManager) updateThread() { - blockChan := self.eth.Eventer().Register("block") + blockChan := self.eth.Eventer().Register("blocks") out: for { select { case event := <-blockChan: - block := event.Data.(*Block) - err := self.Process(block, false) - if err != nil { - statelogger.Infoln(err) - statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) - statelogger.Debugln(block) + blocks := event.Data.(Blocks) + for _, block := range blocks { + err := self.Process(block, false) + if err != nil { + statelogger.Infoln(err) + statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) + statelogger.Debugln(block) + break + } } case <-self.quit: diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 096464963..fbb729950 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -292,9 +292,9 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject { // Create contract if there's no recipient if tx.IsContract() { - addr := tx.CreationAddress() + addr := tx.CreationAddress(state) - contract := state.NewStateObject(addr) + contract := state.GetOrNewStateObject(addr) contract.InitCode = tx.Data contract.State = ethstate.New(ethtrie.New(ethutil.Config.Db, "")) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index e7e8f3a9f..ae77ee58d 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -6,6 +6,7 @@ import ( "math/big" "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" ) @@ -77,8 +78,14 @@ func (tx *Transaction) IsContract() bool { return tx.CreatesContract() } -func (tx *Transaction) CreationAddress() []byte { - return ethcrypto.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] +func (tx *Transaction) CreationAddress(state *ethstate.State) []byte { + // Generate a new address + addr := ethcrypto.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] + //for i := uint64(0); state.GetStateObject(addr) != nil; i++ { + // addr = ethcrypto.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce + i}).Encode())[12:] + //} + + return addr } func (tx *Transaction) Signature(key []byte) []byte { -- cgit v1.2.3 From 0015ce1e353f52cca818d11f566b9a656fb85f24 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 7 Oct 2014 11:18:46 +0200 Subject: kick of bad peers --- ethchain/filter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/filter.go b/ethchain/filter.go index 0a97b3f98..447163b68 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -216,7 +216,7 @@ func (self *Filter) bloomFilter(block *Block) bool { fk := append([]byte("bloom"), block.Hash()...) bin, err := self.eth.Db().Get(fk) if err != nil { - panic(err) + fmt.Println(err) } bloom := NewBloomFilter(bin) -- cgit v1.2.3 From b417766b36f46316cbae6fa42815f1a519e5f733 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 8 Oct 2014 11:59:44 +0200 Subject: Minor tweaks for poc7 --- ethchain/block_chain.go | 34 ++++++++++++++++++++++------------ ethchain/state_transition.go | 9 --------- ethchain/types.go | 18 ++++++++---------- 3 files changed, 30 insertions(+), 31 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 467c54058..113e313ac 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -78,6 +78,22 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { return block } +func (bc *BlockChain) Reset() { + AddTestNetFunds(bc.genesisBlock) + + bc.genesisBlock.state.Trie.Sync() + // Prepare the genesis block + bc.Add(bc.genesisBlock) + fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) + bc.Ethereum.Db().Put(fk, make([]byte, 255)) + bc.CurrentBlock = bc.genesisBlock + + bc.SetTotalDifficulty(ethutil.Big("0")) + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) +} + func (bc *BlockChain) HasBlock(hash []byte) bool { data, _ := ethutil.Config.Db.Get(hash) return len(data) != 0 @@ -149,28 +165,22 @@ func AddTestNetFunds(block *Block) { } func (bc *BlockChain) setLastBlock() { - // Prep genesis - AddTestNetFunds(bc.genesisBlock) - data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { + // Prep genesis + AddTestNetFunds(bc.genesisBlock) + block := NewBlockFromBytes(data) bc.CurrentBlock = block bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) } else { - bc.genesisBlock.state.Trie.Sync() - // Prepare the genesis block - bc.Add(bc.genesisBlock) - fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) - bc.Ethereum.Db().Put(fk, make([]byte, 255)) - bc.CurrentBlock = bc.genesisBlock + bc.Reset() } - // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index fbb729950..28cb66105 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -276,15 +276,6 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context ret, _, err = callerClosure.Call(vm, self.tx.Data) - if err == nil { - // Execute POSTs - for e := vm.Queue().Front(); e != nil; e = e.Next() { - msg := e.Value.(*ethvm.Message) - - msg.Exec(msg.Addr(), transactor) - } - } - return } diff --git a/ethchain/types.go b/ethchain/types.go index 45486b06c..ccd5b7975 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -144,11 +144,10 @@ const ( SWAP16 = 0x9f // 0xf0 range - closures - CREATE = 0xf0 - CALL = 0xf1 - RETURN = 0xf2 - POST = 0xf3 - CALLSTATELESS = 0xf4 + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 + CALLCODE = 0xf3 // 0x70 range - other LOG = 0xfe // XXX Unofficial @@ -293,11 +292,10 @@ var opCodeToString = map[OpCode]string{ SWAP16: "SWAP16", // 0xf0 range - CREATE: "CREATE", - CALL: "CALL", - RETURN: "RETURN", - POST: "POST", - CALLSTATELESS: "CALLSTATELESS", + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", + CALLCODE: "CALLCODE", // 0x70 range - other LOG: "LOG", -- cgit v1.2.3 From 9d86a49a7327199c01977f3372c8adf748252c32 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 8 Oct 2014 12:06:39 +0200 Subject: Renamed Sha3Bin to Sha3 --- ethchain/block.go | 8 ++++---- ethchain/dagger.go | 2 +- ethchain/genesis.go | 6 +++--- ethchain/transaction.go | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 5e8aca33a..d6ff5ef7e 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -144,12 +144,12 @@ func CreateBlock(root interface{}, // Returns a hash of the block func (block *Block) Hash() ethutil.Bytes { - return ethcrypto.Sha3Bin(ethutil.NewValue(block.header()).Encode()) - //return ethcrypto.Sha3Bin(block.Value().Encode()) + return ethcrypto.Sha3(ethutil.NewValue(block.header()).Encode()) + //return ethcrypto.Sha3(block.Value().Encode()) } func (block *Block) HashNoNonce() []byte { - return ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, + return ethcrypto.Sha3(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Trie.Root, block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, block.GasLimit, block.GasUsed, block.Time, block.Extra})) @@ -237,7 +237,7 @@ func (block *Block) SetUncles(uncles []*Block) { block.Uncles = uncles // Sha of the concatenated uncles - block.UncleSha = ethcrypto.Sha3Bin(ethutil.Encode(block.rlpUncles())) + block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) } func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 478b7e877..916d7e9c8 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -61,7 +61,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { t = time.Now() } - sha := ethcrypto.Sha3Bin(big.NewInt(r.Int63()).Bytes()) + sha := ethcrypto.Sha3(big.NewInt(r.Int63()).Bytes()) if pow.Verify(hash, diff, sha) { return sha } diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 8a1219acb..3edbf32de 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -13,13 +13,13 @@ import ( var ZeroHash256 = make([]byte, 32) var ZeroHash160 = make([]byte, 20) -var EmptyShaList = ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{})) +var EmptyShaList = ethcrypto.Sha3(ethutil.Encode([]interface{}{})) var GenesisHeader = []interface{}{ // Previous hash (none) ZeroHash256, // Sha of uncles - ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{})), + ethcrypto.Sha3(ethutil.Encode([]interface{}{})), // Coinbase ZeroHash160, // Root state @@ -42,7 +42,7 @@ var GenesisHeader = []interface{}{ // Extra nil, // Nonce - ethcrypto.Sha3Bin(big.NewInt(42).Bytes()), + ethcrypto.Sha3(big.NewInt(42).Bytes()), } var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}} diff --git a/ethchain/transaction.go b/ethchain/transaction.go index ae77ee58d..fe11be3bb 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -66,7 +66,7 @@ func (self *Transaction) TotalValue() *big.Int { func (tx *Transaction) Hash() []byte { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - return ethcrypto.Sha3Bin(ethutil.NewValue(data).Encode()) + return ethcrypto.Sha3(ethutil.NewValue(data).Encode()) } func (tx *Transaction) CreatesContract() bool { @@ -80,9 +80,9 @@ func (tx *Transaction) IsContract() bool { func (tx *Transaction) CreationAddress(state *ethstate.State) []byte { // Generate a new address - addr := ethcrypto.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] + addr := ethcrypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] //for i := uint64(0); state.GetStateObject(addr) != nil; i++ { - // addr = ethcrypto.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce + i}).Encode())[12:] + // addr = ethcrypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce + i}).Encode())[12:] //} return addr @@ -120,7 +120,7 @@ func (tx *Transaction) Sender() []byte { return nil } - return ethcrypto.Sha3Bin(pubkey[1:])[12:] + return ethcrypto.Sha3(pubkey[1:])[12:] } func (tx *Transaction) Sign(privk []byte) error { -- cgit v1.2.3 From e02c0fa8088943bc995d290e58a7226f4a0ece91 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 10 Oct 2014 17:00:06 +0200 Subject: Added generic big to 256 method. Implemented new iterator --- ethchain/block_chain.go | 25 ++++++++++++++----------- ethchain/state_manager.go | 8 +++++--- 2 files changed, 19 insertions(+), 14 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 113e313ac..a5dcec438 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -40,13 +40,11 @@ func (bc *BlockChain) Genesis() *Block { func (bc *BlockChain) NewBlock(coinbase []byte) *Block { var root interface{} - var lastBlockTime int64 hash := ZeroHash256 if bc.CurrentBlock != nil { root = bc.CurrentBlock.state.Trie.Root hash = bc.LastBlockHash - lastBlockTime = bc.CurrentBlock.Time } block := CreateBlock( @@ -61,15 +59,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { parent := bc.CurrentBlock if parent != nil { - diff := new(big.Int) - - adjust := new(big.Int).Rsh(parent.Difficulty, 10) - if block.Time >= lastBlockTime+5 { - diff.Sub(parent.Difficulty, adjust) - } else { - diff.Add(parent.Difficulty, adjust) - } - block.Difficulty = diff + block.Difficulty = CalcDifficulty(block, parent) block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) @@ -78,6 +68,19 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { return block } +func CalcDifficulty(block, parent *Block) *big.Int { + diff := new(big.Int) + + adjust := new(big.Int).Rsh(parent.Difficulty, 10) + if block.Time >= parent.Time+5 { + diff.Sub(parent.Difficulty, adjust) + } else { + diff.Add(parent.Difficulty, adjust) + } + + return diff +} + func (bc *BlockChain) Reset() { AddTestNetFunds(bc.genesisBlock) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 93fd1ec58..589b99ac2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -346,9 +346,6 @@ func (sm *StateManager) CalculateTD(block *Block) bool { // an uncle or anything that isn't on the current block chain. // Validation validates easy over difficult (dagger takes longer time = difficult) func (sm *StateManager) 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 parent := sm.bc.GetBlock(block.PrevHash) @@ -360,6 +357,11 @@ func (sm *StateManager) ValidateBlock(block *Block) error { } */ + expd := CalcDifficulty(block, parent) + if expd.Cmp(block.Difficulty) < 0 { + return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) + } + diff := block.Time - parent.Time if diff < 0 { return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time) -- cgit v1.2.3 From 56843ca0fca1886213be4ee1e25995a537afda57 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 10 Oct 2014 22:42:37 +0200 Subject: Added some methods to comply to the PoW block interface --- ethchain/block.go | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index d6ff5ef7e..72dc5b55a 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -348,10 +348,18 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { return block } +func (block *Block) Trie() *ethrie.Trie { + return block.state.Trie +} + func (block *Block) GetRoot() interface{} { return block.state.Trie.Root } +func (block *Block) Diff() *big.Int { + return block.Difficulty +} + func (self *Block) Receipts() []*Receipt { return self.receipts } -- cgit v1.2.3 From 2e894b668a2bde3eb83418cfd9128f3a571e0026 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 11 Oct 2014 00:41:37 +0200 Subject: Max callstack --- 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 72dc5b55a..0fb01ea5b 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -348,7 +348,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { return block } -func (block *Block) Trie() *ethrie.Trie { +func (block *Block) Trie() *ethtrie.Trie { return block.state.Trie } -- cgit v1.2.3 From c5bd32b0ad1a3d0fd20a3d1014cc8a97d889dc28 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 14 Oct 2014 11:48:52 +0200 Subject: Refactored VM to two separate VMs; std & debug Standard VM should be about 10x faster than the debug VM. Some error checking has been removed, all of the log statements and therefor quite some unnecessary if-statements. --- ethchain/state_transition.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 28cb66105..10159929b 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -224,7 +224,7 @@ func (self *StateTransition) TransitionState() (err error) { // script section for the state object. self.data = nil - code, err := self.Eval(msg, receiver.Init(), receiver, "init") + code, err := self.Eval(msg, receiver.Init(), receiver) if err != nil { self.state.Set(snapshot) @@ -235,7 +235,7 @@ func (self *StateTransition) TransitionState() (err error) { msg.Output = code } else { if len(receiver.Code) > 0 { - ret, err := self.Eval(msg, receiver.Code, receiver, "code") + ret, err := self.Eval(msg, receiver.Code, receiver) if err != nil { self.state.Set(snapshot) @@ -262,7 +262,7 @@ func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObjec return nil } -func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) { +func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context *ethstate.StateObject) (ret []byte, err error) { var ( transactor = self.Sender() state = self.state @@ -270,9 +270,7 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context callerClosure = ethvm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) ) - vm := ethvm.New(env) - vm.Verbose = true - vm.Fn = typ + vm := ethvm.New(env, ethvm.Type(ethutil.Config.VmType)) ret, _, err = callerClosure.Call(vm, self.tx.Data) -- cgit v1.2.3 From 311c6f8a3fed5ac03ee4b442fd0f420072bc41b4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 15 Oct 2014 17:12:26 +0200 Subject: Fixed remote Arithmetic tests --- ethchain/state_transition.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 10159929b..719e5fd66 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -270,7 +270,8 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context callerClosure = ethvm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) ) - vm := ethvm.New(env, ethvm.Type(ethutil.Config.VmType)) + //vm := ethvm.New(env, ethvm.Type(ethutil.Config.VmType)) + vm := ethutil.New(env, ethvm.DebugVmTy) ret, _, err = callerClosure.Call(vm, self.tx.Data) -- cgit v1.2.3 From febec5ca4a059a3e3a5cc2b5fe0d14ba02492b95 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 16 Oct 2014 13:39:11 +0200 Subject: Switch EXT* codes --- ethchain/types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/types.go b/ethchain/types.go index ccd5b7975..29084c749 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -49,8 +49,8 @@ const ( CODESIZE = 0x38 CODECOPY = 0x39 GASPRICE = 0x3a - EXTCODECOPY = 0x3b - EXTCODESIZE = 0x3c + EXTCODESIZE = 0x3b + EXTCODECOPY = 0x3c // 0x40 range - block operations PREVHASH = 0x40 -- cgit v1.2.3 From bb5038699ef7e08054ef154107e359dce2e3b106 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 16 Oct 2014 13:41:44 +0200 Subject: Corrected package .... --- ethchain/state_transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 719e5fd66..93b991c45 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -271,7 +271,7 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context ) //vm := ethvm.New(env, ethvm.Type(ethutil.Config.VmType)) - vm := ethutil.New(env, ethvm.DebugVmTy) + vm := ethvm.New(env, ethvm.DebugVmTy) ret, _, err = callerClosure.Call(vm, self.tx.Data) -- cgit v1.2.3 From 93fcabd25189b447cc5c52523134cca2fa1d794e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 16 Oct 2014 18:27:05 +0200 Subject: Fixed most of the tests --- ethchain/state_transition.go | 8 +------- ethchain/vm_env.go | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 93b991c45..5bb084ae4 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -72,12 +72,6 @@ func (self *StateTransition) Receiver() *ethstate.StateObject { return self.rec } -func (self *StateTransition) MakeStateObject(state *ethstate.State, tx *Transaction) *ethstate.StateObject { - contract := MakeContract(tx, state) - - return contract -} - func (self *StateTransition) UseGas(amount *big.Int) error { if self.gas.Cmp(amount) < 0 { return OutOfGasError() @@ -190,7 +184,7 @@ func (self *StateTransition) TransitionState() (err error) { snapshot = self.state.Copy() // Create a new state object for the contract - receiver = self.MakeStateObject(self.state, tx) + receiver := MakeContract(tx, self.state) self.rec = receiver if receiver == nil { return fmt.Errorf("Unable to create contract") diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go index 30f9497fa..4600878d1 100644 --- a/ethchain/vm_env.go +++ b/ethchain/vm_env.go @@ -29,3 +29,4 @@ func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.tx.Value } func (self *VMEnv) State() *ethstate.State { return self.state } +func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } -- cgit v1.2.3 From 36cdab206849c7e363e0b9911553098c3e8ca644 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 14 Oct 2014 01:58:31 +0200 Subject: all: use (blocking) event package instead of ethreact --- ethchain/dagger.go | 7 +++--- ethchain/events.go | 10 ++++++++ ethchain/state_manager.go | 55 ++++++++++++++++---------------------------- ethchain/transaction_pool.go | 3 ++- 4 files changed, 35 insertions(+), 40 deletions(-) create mode 100644 ethchain/events.go (limited to 'ethchain') diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 916d7e9c8..2d2b5720f 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" ) @@ -16,7 +15,7 @@ import ( var powlogger = ethlog.NewLogger("POW") type PoW interface { - Search(block *Block, reactChan chan ethreact.Event) []byte + Search(block *Block, stop <-chan struct{}) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool GetHashrate() int64 Turbo(bool) @@ -36,7 +35,7 @@ func (pow *EasyPow) Turbo(on bool) { pow.turbo = on } -func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { +func (pow *EasyPow) Search(block *Block, stop <-chan struct{}) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty @@ -46,7 +45,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { for { select { - case <-reactChan: + case <-stop: powlogger.Infoln("Breaking from mining") return nil default: diff --git a/ethchain/events.go b/ethchain/events.go new file mode 100644 index 000000000..05c21edfe --- /dev/null +++ b/ethchain/events.go @@ -0,0 +1,10 @@ +package ethchain + +type TxEvent struct { + Type int // TxPre || TxPost + Tx *Transaction +} + +type NewBlockEvent struct { + Block *Block +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 589b99ac2..b71cbe8a1 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -11,11 +11,10 @@ import ( "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/eth-go/eventer" + "github.com/ethereum/eth-go/event" ) var statelogger = ethlog.NewLogger("STATE") @@ -37,7 +36,6 @@ type EthManager interface { BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) - Reactor() *ethreact.ReactorEngine PeerCount() int IsMining() bool IsListening() bool @@ -45,7 +43,7 @@ type EthManager interface { KeyManager() *ethcrypto.KeyManager ClientIdentity() ethwire.ClientIdentity Db() ethutil.Database - Eventer() *eventer.EventMachine + EventMux() *event.TypeMux } type StateManager struct { @@ -73,17 +71,15 @@ type StateManager struct { // 'Process' & canonical validation. lastAttemptedBlock *Block - // Quit chan - quit chan bool + events event.Subscription } func NewStateManager(ethereum EthManager) *StateManager { sm := &StateManager{ - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - eth: ethereum, - bc: ethereum.BlockChain(), - quit: make(chan bool), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + eth: ethereum, + bc: ethereum.BlockChain(), } sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy() sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy() @@ -93,36 +89,25 @@ func NewStateManager(ethereum EthManager) *StateManager { func (self *StateManager) Start() { statelogger.Debugln("Starting state manager") - + self.events = self.eth.EventMux().Subscribe(Blocks(nil)) go self.updateThread() } func (self *StateManager) Stop() { statelogger.Debugln("Stopping state manager") - - close(self.quit) + self.events.Unsubscribe() } func (self *StateManager) updateThread() { - blockChan := self.eth.Eventer().Register("blocks") - -out: - for { - select { - case event := <-blockChan: - blocks := event.Data.(Blocks) - for _, block := range blocks { - err := self.Process(block, false) - if err != nil { - statelogger.Infoln(err) - statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) - statelogger.Debugln(block) - break - } + for ev := range self.events.Chan() { + for _, block := range ev.(Blocks) { + err := self.Process(block, false) + if err != nil { + statelogger.Infoln(err) + statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) + statelogger.Debugln(block) + break } - - case <-self.quit: - break out } } } @@ -202,7 +187,7 @@ done: } // Notify all subscribers - self.eth.Reactor().Post("newTx:post", tx) + self.eth.EventMux().Post(TxEvent{TxPost, tx}) receipts = append(receipts, receipt) handled = append(handled, tx) @@ -293,7 +278,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { statelogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4]) if dontReact == false { - sm.eth.Reactor().Post("newBlock", block) + sm.eth.EventMux().Post(NewBlockEvent{block}) state.Manifest().Reset() } @@ -434,7 +419,7 @@ func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { bloomf.Set(msg.From) } - sm.eth.Reactor().Post("messages", state.Manifest().Messages) + sm.eth.EventMux().Post(state.Manifest().Messages) return bloomf } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index da6c3d6ba..0676af3a3 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -24,6 +24,7 @@ type TxMsgTy byte const ( TxPre = iota TxPost + minGasPrice = 1000000 ) @@ -160,7 +161,7 @@ out: txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) // Notify the subscribers - pool.Ethereum.Reactor().Post("newTx:pre", tx) + pool.Ethereum.EventMux().Post(TxEvent{TxPre, tx}) } case <-pool.quit: break out -- cgit v1.2.3 From 20cdb73862c6ae5af10dbaceba34c5073148235d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 14 Oct 2014 02:01:46 +0200 Subject: ethchain: fix tests --- ethchain/filter_test.go | 2 +- ethchain/helper_test.go | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/filter_test.go b/ethchain/filter_test.go index 6dce51b3b..e569b3774 100644 --- a/ethchain/filter_test.go +++ b/ethchain/filter_test.go @@ -3,5 +3,5 @@ package ethchain import "testing" func TestFilter(t *testing.T) { - filter := NewFilter() + NewFilter(NewTestManager()) } diff --git a/ethchain/helper_test.go b/ethchain/helper_test.go index 75d7771fc..2da01d8a6 100644 --- a/ethchain/helper_test.go +++ b/ethchain/helper_test.go @@ -6,16 +6,17 @@ import ( "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "github.com/ethereum/eth-go/event" ) // Implement our EthTest Manager type TestManager struct { stateManager *StateManager - reactor *ethreact.ReactorEngine + eventMux *event.TypeMux + db ethutil.Database txPool *TxPool blockChain *BlockChain Blocks []*Block @@ -49,8 +50,8 @@ func (tm *TestManager) StateManager() *StateManager { return tm.stateManager } -func (tm *TestManager) Reactor() *ethreact.ReactorEngine { - return tm.reactor +func (tm *TestManager) EventMux() *event.TypeMux { + return tm.eventMux } func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { fmt.Println("Broadcast not implemented") @@ -63,7 +64,10 @@ func (tm *TestManager) KeyManager() *ethcrypto.KeyManager { return nil } -func (tm *TestManager) Db() ethutil.Database { return nil } +func (tm *TestManager) Db() ethutil.Database { + return tm.db +} + func NewTestManager() *TestManager { ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH") @@ -75,8 +79,8 @@ func NewTestManager() *TestManager { ethutil.Config.Db = db testManager := &TestManager{} - testManager.reactor = ethreact.New() - + testManager.eventMux = new(event.TypeMux) + testManager.db = db testManager.txPool = NewTxPool(testManager) testManager.blockChain = NewBlockChain(testManager) testManager.stateManager = NewStateManager(testManager) -- cgit v1.2.3 From d2bb83833ffadc91d128a1833853ec3240b8c824 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 18 Oct 2014 13:20:06 +0200 Subject: Moved Filter's wrapping functions to their own util package. Fixes #61 * CLI ethereum should no longer require the Qt/QML package --- ethchain/filter.go | 104 +++++------------------------------------------------ 1 file changed, 9 insertions(+), 95 deletions(-) (limited to 'ethchain') diff --git a/ethchain/filter.go b/ethchain/filter.go index 447163b68..90f2512ab 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -6,12 +6,10 @@ import ( "math" "github.com/ethereum/eth-go/ethstate" - "github.com/ethereum/eth-go/ethutil" - "gopkg.in/qml.v1" ) -type data struct { - id, address []byte +type AccountChange struct { + Address, StateAddress []byte } // Filtering interface @@ -23,7 +21,7 @@ type Filter struct { from, to [][]byte max int - altered []data + Altered []AccountChange BlockCallback func(*Block) MessageCallback func(ethstate.Messages) @@ -35,48 +33,8 @@ func NewFilter(eth EthManager) *Filter { return &Filter{eth: eth} } -func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { - filter := NewFilter(eth) - - if object["earliest"] != nil { - val := ethutil.NewValue(object["earliest"]) - filter.SetEarliestBlock(val.Int()) - } - - if object["latest"] != nil { - val := ethutil.NewValue(object["latest"]) - filter.SetLatestBlock(val.Int()) - } - - if object["to"] != nil { - val := ethutil.NewValue(object["to"]) - filter.AddTo(ethutil.Hex2Bytes(val.Str())) - } - - if object["from"] != nil { - val := ethutil.NewValue(object["from"]) - filter.AddFrom(ethutil.Hex2Bytes(val.Str())) - } - - if object["max"] != nil { - val := ethutil.NewValue(object["max"]) - filter.SetMax(int(val.Uint())) - } - - if object["skip"] != nil { - val := ethutil.NewValue(object["skip"]) - filter.SetSkip(int(val.Uint())) - } - - if object["altered"] != nil { - filter.altered = makeAltered(object["altered"]) - } - - return filter -} - -func (self *Filter) AddAltered(id, address []byte) { - self.altered = append(self.altered, data{id, address}) +func (self *Filter) AddAltered(address, stateAddress []byte) { + self.Altered = append(self.Altered, AccountChange{address, stateAddress}) } // Set the earliest and latest block for filtering. @@ -185,16 +143,16 @@ func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message } var match bool - if len(self.altered) == 0 { + if len(self.Altered) == 0 { match = true } - for _, item := range self.altered { - if len(item.id) > 0 && bytes.Compare(message.To, item.id) != 0 { + for _, accountChange := range self.Altered { + if len(accountChange.Address) > 0 && bytes.Compare(message.To, accountChange.Address) != 0 { continue } - if len(item.address) > 0 && !includes(message.ChangedAddresses, item.address) { + if len(accountChange.StateAddress) > 0 && !includes(message.ChangedAddresses, accountChange.StateAddress) { continue } @@ -246,47 +204,3 @@ func (self *Filter) bloomFilter(block *Block) bool { return fromIncluded && toIncluded } - -// Conversion methodn -func mapToData(m map[string]interface{}) (d data) { - if str, ok := m["id"].(string); ok { - d.id = ethutil.Hex2Bytes(str) - } - - if str, ok := m["at"].(string); ok { - d.address = ethutil.Hex2Bytes(str) - } - - return -} - -// data can come in in the following formats: -// ["aabbccdd", {id: "ccddee", at: "11223344"}], "aabbcc", {id: "ccddee", at: "1122"} -func makeAltered(v interface{}) (d []data) { - if str, ok := v.(string); ok { - d = append(d, data{ethutil.Hex2Bytes(str), nil}) - } else if obj, ok := v.(map[string]interface{}); ok { - d = append(d, mapToData(obj)) - } else if slice, ok := v.([]interface{}); ok { - for _, item := range slice { - d = append(d, makeAltered(item)...) - } - } else if qList, ok := v.(*qml.List); ok { - var s []interface{} - qList.Convert(&s) - - fmt.Println(s) - - d = makeAltered(s) - } else if qMap, ok := v.(*qml.Map); ok { - var m map[string]interface{} - qMap.Convert(&m) - fmt.Println(m) - - d = makeAltered(m) - } else { - panic(fmt.Sprintf("makeAltered err (unknown conversion): %T\n", v)) - } - - return -} -- cgit v1.2.3 From 20c742e47406c13ebc6427951f6fcf1b0056ea26 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 18 Oct 2014 13:31:20 +0200 Subject: Moved ethvm => vm --- ethchain/state_transition.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5bb084ae4..79321eaac 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethvm" + "github.com/ethereum/eth-go/vm" ) /* @@ -160,13 +160,13 @@ func (self *StateTransition) TransitionState() (err error) { sender.Nonce += 1 // Transaction gas - if err = self.UseGas(ethvm.GasTx); err != nil { + if err = self.UseGas(vm.GasTx); err != nil { return } // Pay data gas dataPrice := big.NewInt(int64(len(self.data))) - dataPrice.Mul(dataPrice, ethvm.GasData) + dataPrice.Mul(dataPrice, vm.GasData) if err = self.UseGas(dataPrice); err != nil { return } @@ -261,11 +261,11 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context transactor = self.Sender() state = self.state env = NewEnv(state, self.tx, self.block) - callerClosure = ethvm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) + callerClosure = vm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) ) - //vm := ethvm.New(env, ethvm.Type(ethutil.Config.VmType)) - vm := ethvm.New(env, ethvm.DebugVmTy) + //vm := vm.New(env, vm.Type(ethutil.Config.VmType)) + vm := vm.New(env, vm.DebugVmTy) ret, _, err = callerClosure.Call(vm, self.tx.Data) -- cgit v1.2.3 From 097ba56df59293f9225a8ecdc9e1c43a5ad891bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 20 Oct 2014 11:53:11 +0200 Subject: Renamed block_chain to chain_manager --- ethchain/block_chain.go | 291 ----------------------------------------- ethchain/block_chain_test.go | 1 - ethchain/block_manager_test.go | 36 ----- ethchain/chain_manager.go | 291 +++++++++++++++++++++++++++++++++++++++++ ethchain/chain_manager_test.go | 1 + ethchain/filter.go | 8 +- ethchain/state_manager.go | 16 +-- ethchain/transaction_pool.go | 2 +- 8 files changed, 305 insertions(+), 341 deletions(-) delete mode 100644 ethchain/block_chain.go delete mode 100644 ethchain/block_chain_test.go delete mode 100644 ethchain/block_manager_test.go create mode 100644 ethchain/chain_manager.go create mode 100644 ethchain/chain_manager_test.go (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go deleted file mode 100644 index a5dcec438..000000000 --- a/ethchain/block_chain.go +++ /dev/null @@ -1,291 +0,0 @@ -package ethchain - -import ( - "bytes" - "fmt" - "math/big" - - "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethutil" -) - -var chainlogger = ethlog.NewLogger("CHAIN") - -type BlockChain struct { - Ethereum EthManager - // The famous, the fabulous Mister GENESIIIIIIS (block) - genesisBlock *Block - // Last known total difficulty - TD *big.Int - - LastBlockNumber uint64 - - CurrentBlock *Block - LastBlockHash []byte -} - -func NewBlockChain(ethereum EthManager) *BlockChain { - bc := &BlockChain{} - bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis)) - bc.Ethereum = ethereum - - bc.setLastBlock() - - return bc -} - -func (bc *BlockChain) Genesis() *Block { - return bc.genesisBlock -} - -func (bc *BlockChain) NewBlock(coinbase []byte) *Block { - var root interface{} - hash := ZeroHash256 - - if bc.CurrentBlock != nil { - root = bc.CurrentBlock.state.Trie.Root - hash = bc.LastBlockHash - } - - block := CreateBlock( - root, - hash, - coinbase, - ethutil.BigPow(2, 32), - nil, - "") - - block.MinGasPrice = big.NewInt(10000000000000) - - parent := bc.CurrentBlock - if parent != nil { - block.Difficulty = CalcDifficulty(block, parent) - block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) - - } - - return block -} - -func CalcDifficulty(block, parent *Block) *big.Int { - diff := new(big.Int) - - adjust := new(big.Int).Rsh(parent.Difficulty, 10) - if block.Time >= parent.Time+5 { - diff.Sub(parent.Difficulty, adjust) - } else { - diff.Add(parent.Difficulty, adjust) - } - - return diff -} - -func (bc *BlockChain) Reset() { - AddTestNetFunds(bc.genesisBlock) - - bc.genesisBlock.state.Trie.Sync() - // Prepare the genesis block - bc.Add(bc.genesisBlock) - fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) - bc.Ethereum.Db().Put(fk, make([]byte, 255)) - bc.CurrentBlock = bc.genesisBlock - - bc.SetTotalDifficulty(ethutil.Big("0")) - - // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) -} - -func (bc *BlockChain) HasBlock(hash []byte) bool { - data, _ := ethutil.Config.Db.Get(hash) - return len(data) != 0 -} - -// TODO: At one point we might want to save a block by prevHash in the db to optimise this... -func (bc *BlockChain) HasBlockWithPrevHash(hash []byte) bool { - block := bc.CurrentBlock - - for ; block != nil; block = bc.GetBlock(block.PrevHash) { - if bytes.Compare(hash, block.PrevHash) == 0 { - return true - } - } - return false -} - -func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { - blockDiff := new(big.Int) - - for _, uncle := range block.Uncles { - blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty) - } - blockDiff = blockDiff.Add(blockDiff, block.Difficulty) - - return blockDiff -} - -func (bc *BlockChain) GenesisBlock() *Block { - return bc.genesisBlock -} - -func (self *BlockChain) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) { - block := self.GetBlock(hash) - if block == nil { - return - } - - // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list) - for i := uint64(0); i < max; i++ { - chain = append(chain, block.Hash()) - - if block.Number.Cmp(ethutil.Big0) <= 0 { - break - } - - block = self.GetBlock(block.PrevHash) - } - - return -} - -func AddTestNetFunds(block *Block) { - for _, addr := range []string{ - "51ba59315b3a95761d0863b05ccc7a7f54703d99", - "e4157b34ea9615cfbde6b4fda419828124b70c78", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - } { - codedAddr := ethutil.Hex2Bytes(addr) - account := block.state.GetAccount(codedAddr) - account.Balance = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) - block.state.UpdateStateObject(account) - } -} - -func (bc *BlockChain) setLastBlock() { - data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) - if len(data) != 0 { - // Prep genesis - AddTestNetFunds(bc.genesisBlock) - - block := NewBlockFromBytes(data) - bc.CurrentBlock = block - bc.LastBlockHash = block.Hash() - bc.LastBlockNumber = block.Number.Uint64() - - // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - } else { - bc.Reset() - } - - chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) -} - -func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { - ethutil.Config.Db.Put([]byte("LTD"), 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() - - encodedBlock := block.RlpEncode() - ethutil.Config.Db.Put(block.Hash(), encodedBlock) - ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) -} - -func (self *BlockChain) CalcTotalDiff(block *Block) (*big.Int, error) { - parent := self.GetBlock(block.PrevHash) - if parent == nil { - return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) - } - - parentTd := parent.BlockInfo().TD - - uncleDiff := new(big.Int) - for _, uncle := range block.Uncles { - uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) - } - - td := new(big.Int) - td = td.Add(parentTd, uncleDiff) - td = td.Add(td, block.Difficulty) - - return td, nil -} - -func (bc *BlockChain) GetBlock(hash []byte) *Block { - data, _ := ethutil.Config.Db.Get(hash) - if len(data) == 0 { - return nil - } - - return NewBlockFromBytes(data) -} - -func (self *BlockChain) GetBlockByNumber(num uint64) *Block { - block := self.CurrentBlock - for ; block != nil; block = self.GetBlock(block.PrevHash) { - if block.Number.Uint64() == num { - break - } - } - - if block != nil && block.Number.Uint64() == 0 && num != 0 { - return nil - } - - return block -} - -func (self *BlockChain) GetBlockBack(num uint64) *Block { - block := self.CurrentBlock - - for ; num != 0 && block != nil; num-- { - block = self.GetBlock(block.PrevHash) - } - - return block -} - -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, TD: bc.TD} - - // 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 { - chainlogger.Infoln("Stopped") - } -} diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go deleted file mode 100644 index 3603fd8a7..000000000 --- a/ethchain/block_chain_test.go +++ /dev/null @@ -1 +0,0 @@ -package ethchain diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go deleted file mode 100644 index 3a1e5f510..000000000 --- a/ethchain/block_manager_test.go +++ /dev/null @@ -1,36 +0,0 @@ -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, _ := ethdb.NewMemDatabase() - ethutil.Config.Db = db - bm := NewStateManager(nil) - - block := bm.bc.genesisBlock - bm.Prepare(block.State(), block.State()) - script := Compile([]string{ - "PUSH", - "1", - "PUSH", - "2", - }) - 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}) -} -*/ diff --git a/ethchain/chain_manager.go b/ethchain/chain_manager.go new file mode 100644 index 000000000..227b02c0a --- /dev/null +++ b/ethchain/chain_manager.go @@ -0,0 +1,291 @@ +package ethchain + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethutil" +) + +var chainlogger = ethlog.NewLogger("CHAIN") + +type ChainManager struct { + Ethereum EthManager + // The famous, the fabulous Mister GENESIIIIIIS (block) + genesisBlock *Block + // Last known total difficulty + TD *big.Int + + LastBlockNumber uint64 + + CurrentBlock *Block + LastBlockHash []byte +} + +func NewChainManager(ethereum EthManager) *ChainManager { + bc := &ChainManager{} + bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis)) + bc.Ethereum = ethereum + + bc.setLastBlock() + + return bc +} + +func (bc *ChainManager) Genesis() *Block { + return bc.genesisBlock +} + +func (bc *ChainManager) NewBlock(coinbase []byte) *Block { + var root interface{} + hash := ZeroHash256 + + if bc.CurrentBlock != nil { + root = bc.CurrentBlock.state.Trie.Root + hash = bc.LastBlockHash + } + + block := CreateBlock( + root, + hash, + coinbase, + ethutil.BigPow(2, 32), + nil, + "") + + block.MinGasPrice = big.NewInt(10000000000000) + + parent := bc.CurrentBlock + if parent != nil { + block.Difficulty = CalcDifficulty(block, parent) + block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) + block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) + + } + + return block +} + +func CalcDifficulty(block, parent *Block) *big.Int { + diff := new(big.Int) + + adjust := new(big.Int).Rsh(parent.Difficulty, 10) + if block.Time >= parent.Time+5 { + diff.Sub(parent.Difficulty, adjust) + } else { + diff.Add(parent.Difficulty, adjust) + } + + return diff +} + +func (bc *ChainManager) Reset() { + AddTestNetFunds(bc.genesisBlock) + + bc.genesisBlock.state.Trie.Sync() + // Prepare the genesis block + bc.Add(bc.genesisBlock) + fk := append([]byte("bloom"), bc.genesisBlock.Hash()...) + bc.Ethereum.Db().Put(fk, make([]byte, 255)) + bc.CurrentBlock = bc.genesisBlock + + bc.SetTotalDifficulty(ethutil.Big("0")) + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) +} + +func (bc *ChainManager) HasBlock(hash []byte) bool { + data, _ := ethutil.Config.Db.Get(hash) + return len(data) != 0 +} + +// TODO: At one point we might want to save a block by prevHash in the db to optimise this... +func (bc *ChainManager) HasBlockWithPrevHash(hash []byte) bool { + block := bc.CurrentBlock + + for ; block != nil; block = bc.GetBlock(block.PrevHash) { + if bytes.Compare(hash, block.PrevHash) == 0 { + return true + } + } + return false +} + +func (bc *ChainManager) CalculateBlockTD(block *Block) *big.Int { + blockDiff := new(big.Int) + + for _, uncle := range block.Uncles { + blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty) + } + blockDiff = blockDiff.Add(blockDiff, block.Difficulty) + + return blockDiff +} + +func (bc *ChainManager) GenesisBlock() *Block { + return bc.genesisBlock +} + +func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) { + block := self.GetBlock(hash) + if block == nil { + return + } + + // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list) + for i := uint64(0); i < max; i++ { + chain = append(chain, block.Hash()) + + if block.Number.Cmp(ethutil.Big0) <= 0 { + break + } + + block = self.GetBlock(block.PrevHash) + } + + return +} + +func AddTestNetFunds(block *Block) { + for _, addr := range []string{ + "51ba59315b3a95761d0863b05ccc7a7f54703d99", + "e4157b34ea9615cfbde6b4fda419828124b70c78", + "b9c015918bdaba24b4ff057a92a3873d6eb201be", + "6c386a4b26f73c802f34673f7248bb118f97424a", + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", + "e6716f9544a56c530d868e4bfbacb172315bdead", + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", + } { + codedAddr := ethutil.Hex2Bytes(addr) + account := block.state.GetAccount(codedAddr) + account.Balance = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) + block.state.UpdateStateObject(account) + } +} + +func (bc *ChainManager) setLastBlock() { + data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) + if len(data) != 0 { + // Prep genesis + AddTestNetFunds(bc.genesisBlock) + + block := NewBlockFromBytes(data) + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + bc.LastBlockNumber = block.Number.Uint64() + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) + } else { + bc.Reset() + } + + chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) +} + +func (bc *ChainManager) SetTotalDifficulty(td *big.Int) { + ethutil.Config.Db.Put([]byte("LTD"), td.Bytes()) + bc.TD = td +} + +// Add a block to the chain and record addition information +func (bc *ChainManager) Add(block *Block) { + bc.writeBlockInfo(block) + // Prepare the genesis block + + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + + encodedBlock := block.RlpEncode() + ethutil.Config.Db.Put(block.Hash(), encodedBlock) + ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) +} + +func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) { + parent := self.GetBlock(block.PrevHash) + if parent == nil { + return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) + } + + parentTd := parent.BlockInfo().TD + + uncleDiff := new(big.Int) + for _, uncle := range block.Uncles { + uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) + } + + td := new(big.Int) + td = td.Add(parentTd, uncleDiff) + td = td.Add(td, block.Difficulty) + + return td, nil +} + +func (bc *ChainManager) GetBlock(hash []byte) *Block { + data, _ := ethutil.Config.Db.Get(hash) + if len(data) == 0 { + return nil + } + + return NewBlockFromBytes(data) +} + +func (self *ChainManager) GetBlockByNumber(num uint64) *Block { + block := self.CurrentBlock + for ; block != nil; block = self.GetBlock(block.PrevHash) { + if block.Number.Uint64() == num { + break + } + } + + if block != nil && block.Number.Uint64() == 0 && num != 0 { + return nil + } + + return block +} + +func (self *ChainManager) GetBlockBack(num uint64) *Block { + block := self.CurrentBlock + + for ; num != 0 && block != nil; num-- { + block = self.GetBlock(block.PrevHash) + } + + return block +} + +func (bc *ChainManager) BlockInfoByHash(hash []byte) BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (bc *ChainManager) 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 *ChainManager) writeBlockInfo(block *Block) { + bc.LastBlockNumber++ + bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD} + + // 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 *ChainManager) Stop() { + if bc.CurrentBlock != nil { + chainlogger.Infoln("Stopped") + } +} diff --git a/ethchain/chain_manager_test.go b/ethchain/chain_manager_test.go new file mode 100644 index 000000000..3603fd8a7 --- /dev/null +++ b/ethchain/chain_manager_test.go @@ -0,0 +1 @@ +package ethchain diff --git a/ethchain/filter.go b/ethchain/filter.go index 90f2512ab..4e8df7d5f 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -76,16 +76,16 @@ func (self *Filter) SetSkip(skip int) { func (self *Filter) Find() []*ethstate.Message { var earliestBlockNo uint64 = uint64(self.earliest) if self.earliest == -1 { - earliestBlockNo = self.eth.BlockChain().CurrentBlock.Number.Uint64() + earliestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64() } var latestBlockNo uint64 = uint64(self.latest) if self.latest == -1 { - latestBlockNo = self.eth.BlockChain().CurrentBlock.Number.Uint64() + latestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64() } var ( messages []*ethstate.Message - block = self.eth.BlockChain().GetBlockByNumber(latestBlockNo) + block = self.eth.ChainManager().GetBlockByNumber(latestBlockNo) quit bool ) for i := 0; !quit && block != nil; i++ { @@ -111,7 +111,7 @@ func (self *Filter) Find() []*ethstate.Message { messages = append(messages, self.FilterMessages(msgs)...) } - block = self.eth.BlockChain().GetBlock(block.PrevHash) + block = self.eth.ChainManager().GetBlock(block.PrevHash) } skip := int(math.Min(float64(len(messages)), float64(self.skip))) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index b71cbe8a1..ed513c9dc 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -33,7 +33,7 @@ type Peer interface { type EthManager interface { StateManager() *StateManager - BlockChain() *BlockChain + ChainManager() *ChainManager TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) PeerCount() int @@ -50,7 +50,7 @@ type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex // Canonical block chain - bc *BlockChain + bc *ChainManager // non-persistent key/value memory storage mem map[string]*big.Int // Proof of work used for validating @@ -79,10 +79,10 @@ func NewStateManager(ethereum EthManager) *StateManager { mem: make(map[string]*big.Int), Pow: &EasyPow{}, eth: ethereum, - bc: ethereum.BlockChain(), + bc: ethereum.ChainManager(), } - sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy() - sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy() + sm.transState = ethereum.ChainManager().CurrentBlock.State().Copy() + sm.miningState = ethereum.ChainManager().CurrentBlock.State().Copy() return sm } @@ -113,7 +113,7 @@ func (self *StateManager) updateThread() { } func (sm *StateManager) CurrentState() *ethstate.State { - return sm.eth.BlockChain().CurrentBlock.State() + return sm.eth.ChainManager().CurrentBlock.State() } func (sm *StateManager) TransState() *ethstate.State { @@ -125,12 +125,12 @@ func (sm *StateManager) MiningState() *ethstate.State { } func (sm *StateManager) NewMiningState() *ethstate.State { - sm.miningState = sm.eth.BlockChain().CurrentBlock.State().Copy() + sm.miningState = sm.eth.ChainManager().CurrentBlock.State().Copy() return sm.miningState } -func (sm *StateManager) BlockChain() *BlockChain { +func (sm *StateManager) ChainManager() *ChainManager { return sm.bc } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 0676af3a3..ff3184582 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -96,7 +96,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { 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.Ethereum.BlockChain().CurrentBlock + block := pool.Ethereum.ChainManager().CurrentBlock // Something has gone horribly wrong if this happens if block == nil { return fmt.Errorf("[TXPL] No last block on the block chain") -- cgit v1.2.3 From 520fdfe346ab51708f4f1fdfd0b2e42cc919e613 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 21 Oct 2014 13:25:31 +0200 Subject: PoC7 Net --- ethchain/block.go | 6 ++++-- ethchain/genesis.go | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 0fb01ea5b..fc7c6b13f 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -130,7 +130,7 @@ func CreateBlock(root interface{}, Nonce: Nonce, Time: time.Now().Unix(), Extra: extra, - UncleSha: EmptyShaList, + UncleSha: EmptyShaList, //nil, GasUsed: new(big.Int), MinGasPrice: new(big.Int), GasLimit: new(big.Int), @@ -237,7 +237,9 @@ func (block *Block) SetUncles(uncles []*Block) { block.Uncles = uncles // Sha of the concatenated uncles - block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) + //if len(uncles) > 0 { + // block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) + //} } func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 3edbf32de..ab6469bb4 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -18,8 +18,9 @@ var EmptyShaList = ethcrypto.Sha3(ethutil.Encode([]interface{}{})) var GenesisHeader = []interface{}{ // Previous hash (none) ZeroHash256, - // Sha of uncles ethcrypto.Sha3(ethutil.Encode([]interface{}{})), + // Empty uncles + //"", // Coinbase ZeroHash160, // Root state -- cgit v1.2.3 From 6b92d541dabc289043529f65e586e40c4613e7f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 21 Oct 2014 13:30:23 +0200 Subject: Empty string for uncle --- ethchain/block.go | 8 ++++---- ethchain/genesis.go | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index fc7c6b13f..951bd8de3 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -130,7 +130,7 @@ func CreateBlock(root interface{}, Nonce: Nonce, Time: time.Now().Unix(), Extra: extra, - UncleSha: EmptyShaList, //nil, + UncleSha: nil, GasUsed: new(big.Int), MinGasPrice: new(big.Int), GasLimit: new(big.Int), @@ -237,9 +237,9 @@ func (block *Block) SetUncles(uncles []*Block) { block.Uncles = uncles // Sha of the concatenated uncles - //if len(uncles) > 0 { - // block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) - //} + if len(uncles) > 0 { + block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) + } } func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { diff --git a/ethchain/genesis.go b/ethchain/genesis.go index ab6469bb4..8a6cb5527 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -18,9 +18,8 @@ var EmptyShaList = ethcrypto.Sha3(ethutil.Encode([]interface{}{})) var GenesisHeader = []interface{}{ // Previous hash (none) ZeroHash256, - ethcrypto.Sha3(ethutil.Encode([]interface{}{})), // Empty uncles - //"", + "", // Coinbase ZeroHash160, // Root state -- cgit v1.2.3 From 29b8a0bc5ffa7a674a06a211e1c8bdd1b6ed07b1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Oct 2014 01:01:26 +0200 Subject: Updated the VM & VM tests * Stack Error shouldn't revert to previous state * Updated VM Test tool * Added Transfer method to VM Env --- ethchain/chain_manager.go | 2 +- ethchain/state_transition.go | 23 +++++------------------ ethchain/transaction_pool.go | 2 +- ethchain/vm_env.go | 4 ++++ 4 files changed, 11 insertions(+), 20 deletions(-) (limited to 'ethchain') diff --git a/ethchain/chain_manager.go b/ethchain/chain_manager.go index 227b02c0a..9f82eae41 100644 --- a/ethchain/chain_manager.go +++ b/ethchain/chain_manager.go @@ -162,7 +162,7 @@ func AddTestNetFunds(block *Block) { } { codedAddr := ethutil.Hex2Bytes(addr) account := block.state.GetAccount(codedAddr) - account.Balance = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) + account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 79321eaac..1e6834729 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -89,8 +89,8 @@ func (self *StateTransition) BuyGas() error { var err error sender := self.Sender() - if sender.Balance.Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance) + if sender.Balance().Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance()) } coinbase := self.Coinbase() @@ -171,7 +171,7 @@ func (self *StateTransition) TransitionState() (err error) { return } - if sender.Balance.Cmp(self.value) < 0 { + if sender.Balance().Cmp(self.value) < 0 { return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) } @@ -243,19 +243,6 @@ func (self *StateTransition) TransitionState() (err error) { return } -func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObject) error { - if sender.Balance.Cmp(self.value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Balance) - } - - // Subtract the amount from the senders account - sender.SubAmount(self.value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.value) - - return nil -} - func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context *ethstate.StateObject) (ret []byte, err error) { var ( transactor = self.Sender() @@ -265,9 +252,9 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context ) //vm := vm.New(env, vm.Type(ethutil.Config.VmType)) - vm := vm.New(env, vm.DebugVmTy) + evm := vm.New(env, vm.DebugVmTy) - ret, _, err = callerClosure.Call(vm, self.tx.Data) + ret, _, err = callerClosure.Call(evm, self.tx.Data) return } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ff3184582..0ddc4e435 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -117,7 +117,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { totAmount := new(big.Int).Set(tx.Value) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. - if sender.Balance.Cmp(totAmount) < 0 { + if sender.Balance().Cmp(totAmount) < 0 { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go index 4600878d1..36c9d6002 100644 --- a/ethchain/vm_env.go +++ b/ethchain/vm_env.go @@ -4,6 +4,7 @@ import ( "math/big" "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/vm" ) type VMEnv struct { @@ -30,3 +31,6 @@ func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.tx.Value } func (self *VMEnv) State() *ethstate.State { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } +func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { + return vm.Transfer(from, to, amount) +} -- cgit v1.2.3