aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain
diff options
context:
space:
mode:
Diffstat (limited to 'ethchain')
-rw-r--r--ethchain/block.go53
-rw-r--r--ethchain/block_manager.go35
-rw-r--r--ethchain/block_manager_test.go74
-rw-r--r--ethchain/stack.go9
-rw-r--r--ethchain/transaction.go5
-rw-r--r--ethchain/transaction_test.go16
6 files changed, 101 insertions, 91 deletions
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())
+ */
}