Running contracts fixed

This commit is contained in:
obscuren 2014-02-19 11:35:17 +01:00
parent c866fcc5b3
commit 24f2b2afc3
10 changed files with 120 additions and 98 deletions

View File

@ -46,6 +46,8 @@ type Block struct {
// List of transactions and/or contracts // List of transactions and/or contracts
transactions []*Transaction transactions []*Transaction
TxSha []byte TxSha []byte
contractStates map[string]*ethutil.Trie
} }
// New block takes a raw encoded string // New block takes a raw encoded string
@ -79,14 +81,15 @@ func CreateBlock(root interface{},
block := &Block{ block := &Block{
// Slice of transactions to include in this block // Slice of transactions to include in this block
transactions: txes, transactions: txes,
PrevHash: prevHash, PrevHash: prevHash,
Coinbase: base, Coinbase: base,
Difficulty: Difficulty, Difficulty: Difficulty,
Nonce: Nonce, Nonce: Nonce,
Time: time.Now().Unix(), Time: time.Now().Unix(),
Extra: extra, Extra: extra,
UncleSha: EmptyShaList, UncleSha: EmptyShaList,
contractStates: make(map[string]*ethutil.Trie),
} }
block.SetTransactions(txes) block.SetTransactions(txes)
block.SetUncles([]*Block{}) block.SetUncles([]*Block{})
@ -131,6 +134,13 @@ func (block *Block) GetContract(addr []byte) *Contract {
contract := &Contract{} contract := &Contract{}
contract.RlpDecode([]byte(data)) contract.RlpDecode([]byte(data))
cachedState := block.contractStates[string(addr)]
if cachedState != nil {
contract.state = cachedState
} else {
block.contractStates[string(addr)] = contract.state
}
return contract return contract
} }
func (block *Block) UpdateContract(addr []byte, contract *Contract) { func (block *Block) UpdateContract(addr []byte, contract *Contract) {
@ -190,6 +200,25 @@ func (block *Block) BlockInfo() BlockInfo {
return bi 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) { func (block *Block) MakeContract(tx *Transaction) {
// Create contract if there's no recipient // Create contract if there's no recipient
if tx.IsContract() { if tx.IsContract() {
@ -199,9 +228,14 @@ func (block *Block) MakeContract(tx *Transaction) {
contract := NewContract(value, []byte("")) contract := NewContract(value, []byte(""))
block.state.Update(string(addr), string(contract.RlpEncode())) block.state.Update(string(addr), string(contract.RlpEncode()))
for i, val := range tx.Data { 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.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.Time = int64(header.Get(6).BigInt().Uint64())
block.Extra = header.Get(7).Str() block.Extra = header.Get(7).Str()
block.Nonce = header.Get(8).Bytes() 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 // Tx list might be empty if this is an uncle. Uncles only have their
// header set. // header set.

View File

@ -107,7 +107,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error {
// we don't want to undo but since undo only happens on dirty // we don't want to undo but since undo only happens on dirty
// nodes this won't happen because Commit would have been called // nodes this won't happen because Commit would have been called
// before that. // before that.
defer bm.bc.CurrentBlock.State().Undo() defer bm.bc.CurrentBlock.Undo()
hash := block.Hash() 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 // Calculate the new total difficulty and sync back to the db
if bm.CalculateTD(block) { if bm.CalculateTD(block) {
// Sync the current block's state to the database and cancelling out the deferred Undo // 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 // Add the block to the chain
bm.bc.Add(block) bm.bc.Add(block)
@ -280,11 +280,13 @@ func (bm *BlockManager) Stop() {
func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) {
// Recovering function in case the VM had any errors // Recovering function in case the VM had any errors
defer func() { /*
if r := recover(); r != nil { defer func() {
fmt.Println("Recovered from VM execution with err =", r) if r := recover(); r != nil {
} fmt.Println("Recovered from VM execution with err =", r)
}() }
}()
*/
// Process contract // Process contract
bm.ProcContract(tx, block, func(opType OpType) bool { 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) blockInfo := bm.bc.BlockInfo(block)
contract := block.GetContract(tx.Hash()) contract := block.GetContract(tx.Hash())
if contract == nil { if contract == nil {
fmt.Println("Contract not found") fmt.Println("Contract not found")
return return
@ -313,7 +316,7 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac
Pow256 := ethutil.BigPow(2, 256) Pow256 := ethutil.BigPow(2, 256)
if ethutil.Config.Debug { if ethutil.Config.Debug {
fmt.Printf("# op arg\n") fmt.Printf("# op\n")
} }
out: out:
for { for {
@ -321,9 +324,11 @@ out:
base := new(big.Int) base := new(big.Int)
// XXX Should Instr return big int slice instead of string slice? // XXX Should Instr return big int slice instead of string slice?
// Get the next instruction from the contract // Get the next instruction from the contract
//op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc))))) nb := ethutil.BigToBytes(big.NewInt(int64(pc)), 256)
nb := ethutil.NumberToBytes(uint64(pc), 32) r := contract.State().Get(string(nb))
o, _, _ := ethutil.Instr(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) op := OpCode(o)
if !cb(0) { if !cb(0) {
@ -575,7 +580,10 @@ out:
case oSSTORE: case oSSTORE:
// Store Y at index X // Store Y at index X
x, y := bm.stack.Popn() 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: case oJMP:
x := int(bm.stack.Pop().Uint64()) x := int(bm.stack.Pop().Uint64())
// Set pc to x - 1 (minus one so the incrementing at the end won't effect it) // 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) bm.TransactionPool.QueueTransaction(tx)
case oSUICIDE: case oSUICIDE:
//addr := bm.stack.Pop() //addr := bm.stack.Pop()
default:
fmt.Println("Invalid OPCODE", op)
} }
//bm.stack.Print()
pc++ pc++
} }
} }

View File

@ -1,75 +1,29 @@
package ethchain package ethchain
/*
import ( import (
_ "fmt" _ "fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing" "testing"
) )
func TestVm(t *testing.T) { func TestVm(t *testing.T) {
InitFees() InitFees()
ethutil.ReadConfig("")
db, _ := NewMemDatabase() db, _ := ethdb.NewMemDatabase()
Db = db ethutil.Config.Db = db
bm := NewBlockManager(nil)
ctrct := NewTransaction("", 200000000, []string{ block := bm.bc.genesisBlock
"PUSH", "1a2f2e", ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), []string{
"PUSH", "hallo", "PUSH",
"POP", // POP hallo "1",
"PUSH", "3", "PUSH",
"LOAD", // Load hallo back on the stack "2",
"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", "STOP",
}) })
tx := NewTransaction("1e8a42ea8cce13", 100, []string{}) bm.ApplyTransactions(block, []*Transaction{ctrct})
block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx})
db.Put(block.Hash(), block.RlpEncode())
bm := NewBlockManager()
bm.ProcessBlock(block)
} }
*/

View File

@ -163,5 +163,12 @@ func (st *Stack) Push(d *big.Int) {
st.data = append(st.data, d) st.data = append(st.data, d)
} }
func (st *Stack) Print() { 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 --")
}
} }

View File

@ -1,11 +1,14 @@
package ethchain package ethchain
import ( import (
"bytes"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go" "github.com/obscuren/secp256k1-go"
"math/big" "math/big"
) )
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 { type Transaction struct {
Nonce uint64 Nonce uint64
Recipient []byte Recipient []byte
@ -65,7 +68,7 @@ func (tx *Transaction) Hash() []byte {
} }
func (tx *Transaction) IsContract() bool { func (tx *Transaction) IsContract() bool {
return len(tx.Recipient) == 0 return bytes.Compare(tx.Recipient, ContractAddr) == 0
} }
func (tx *Transaction) Signature(key []byte) []byte { func (tx *Transaction) Signature(key []byte) []byte {

View File

@ -2,8 +2,6 @@ package ethchain
import ( import (
"encoding/hex" "encoding/hex"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big" "math/big"
"testing" "testing"
) )
@ -42,13 +40,15 @@ func TestAddressRetrieval2(t *testing.T) {
tx.Sign(key) tx.Sign(key)
//data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7") //data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7")
//tx := NewTransactionFromData(data) //tx := NewTransactionFromData(data)
fmt.Println(tx.RlpValue()) /*
fmt.Println(tx.RlpValue())
fmt.Printf("rlp %x\n", tx.RlpEncode()) fmt.Printf("rlp %x\n", tx.RlpEncode())
fmt.Printf("sha rlp %x\n", tx.Hash()) 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("hex tx key %x\n", tx.PublicKey())
fmt.Printf("seder %x\n", tx.Sender()) fmt.Printf("seder %x\n", tx.Sender())
*/
} }

View File

@ -252,7 +252,7 @@ func (s *Ethereum) Start() {
if ethutil.Config.Seed { if ethutil.Config.Seed {
log.Println("Seeding") log.Println("Seeding")
// Testnet seed bootstrapping // Testnet seed bootstrapping
resp, err := http.Get("http://www.ethereum.org/servers.poc2.txt") resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt")
if err != nil { if err != nil {
log.Println("Fetching seed failed:", err) log.Println("Fetching seed failed:", err)
return return

View File

@ -35,3 +35,9 @@ func BigD(data []byte) *big.Int {
return n return n
} }
func BigToBytes(num *big.Int, base int) []byte {
ret := make([]byte, base/8)
return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...)
}

View File

@ -34,12 +34,14 @@ func ReadConfig(base string) *config {
usr, _ := user.Current() usr, _ := user.Current()
path := path.Join(usr.HomeDir, base) path := path.Join(usr.HomeDir, base)
//Check if the logging directory already exists, create it if not if len(base) > 0 {
_, err := os.Stat(path) //Check if the logging directory already exists, create it if not
if err != nil { _, err := os.Stat(path)
if os.IsNotExist(err) { if err != nil {
log.Printf("Debug logging directory %s doesn't exist, creating it", path) if os.IsNotExist(err) {
os.Mkdir(path, 0777) log.Printf("Debug logging directory %s doesn't exist, creating it", path)
os.Mkdir(path, 0777)
}
} }
} }

View File

@ -119,6 +119,10 @@ func (t *Trie) Undo() {
t.Root = t.prevRoot t.Root = t.prevRoot
} }
func (t *Trie) Cache() *Cache {
return t.cache
}
/* /*
* Public (query) interface functions * Public (query) interface functions
*/ */