Running contracts fixed

pull/150/head
obscuren 11 years ago
parent c866fcc5b3
commit 24f2b2afc3
  1. 53
      ethchain/block.go
  2. 35
      ethchain/block_manager.go
  3. 74
      ethchain/block_manager_test.go
  4. 9
      ethchain/stack.go
  5. 5
      ethchain/transaction.go
  6. 16
      ethchain/transaction_test.go
  7. 2
      ethereum.go
  8. 6
      ethutil/big.go
  9. 14
      ethutil/config.go
  10. 4
      ethutil/trie.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.

@ -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++
}
}

@ -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})
}
*/

@ -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 --")
}
}

@ -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 {

@ -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())
*/
}

@ -252,7 +252,7 @@ func (s *Ethereum) Start() {
if ethutil.Config.Seed {
log.Println("Seeding")
// 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 {
log.Println("Fetching seed failed:", err)
return

@ -35,3 +35,9 @@ func BigD(data []byte) *big.Int {
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()...)
}

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

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

Loading…
Cancel
Save