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 ++++++++++++++++----------------------------------- ethutil/common.go | 1 + ethutil/parsing.go | 2 +- ethutil/rlp_test.go | 6 +++ ethutil/trie_test.go | 2 +- 7 files changed, 103 insertions(+), 111 deletions(-) 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) +} diff --git a/ethutil/common.go b/ethutil/common.go index f15b10e6d..c63af29a6 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -36,6 +36,7 @@ func CurrencyToString(num *big.Int) string { var ( Big1 = big.NewInt(1) + Big2 = big.NewInt(1) Big0 = big.NewInt(0) Big256 = big.NewInt(0xff) ) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 8929f0829..16ed2d06d 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -131,7 +131,7 @@ func Instr(instr string) (int, []string, error) { // Script compilation functions // Compiles strings to machine code -func Compile(instructions ...interface{}) (script []string) { +func Assemble(instructions ...interface{}) (script []string) { script = make([]string, len(instructions)) for i, val := range instructions { diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 2a58bfc0f..dc10db632 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,6 +2,7 @@ package ethutil import ( "bytes" + "fmt" "math/big" "reflect" "testing" @@ -119,6 +120,11 @@ func TestEncodeDecodeBytes(t *testing.T) { } } +func TestEncodeZero(t *testing.T) { + b := NewValue(0).Encode() + fmt.Println(b) +} + func BenchmarkEncodeDecode(b *testing.B) { for i := 0; i < b.N; i++ { bytes := Encode([]interface{}{"dog", "god", "cat"}) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 79e5de921..0be512d9f 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,7 @@ package ethutil import ( - "fmt" + _ "fmt" "reflect" "testing" ) -- cgit v1.2.3 From 308c59320c25845f9668e76559b581e2161fec15 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 15:38:55 +0100 Subject: Fixed typo --- ethutil/rlp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 33ec0d359..e6c75696e 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -57,7 +57,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { switch { case char == 0: return nil - case char <= 0x7c: + case char <= 0x7f: return char case char <= 0xb7: -- 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 ++- peer.go | 3 ++- 4 files changed, 60 insertions(+), 15 deletions(-) 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() } +*/ diff --git a/peer.go b/peer.go index 24a5e97c9..82c983927 100644 --- a/peer.go +++ b/peer.go @@ -334,7 +334,8 @@ func (p *Peer) HandleInbound() { // in the TxPool where it will undergo validation and // processing when a new block is found for i := 0; i < msg.Data.Len(); i++ { - p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) + //p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) + p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromValue(msg.Data.Get(i))) } case ethwire.MsgGetPeersTy: // Flag this peer as a 'requested of new peers' this to -- cgit v1.2.3 From 7660e1ed907e213a53408fe60a63619a68fd817b Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 19:42:01 +0100 Subject: Added a IsList method for type checking []interface{} --- ethutil/value.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethutil/value.go b/ethutil/value.go index 46681ec2a..04131aba9 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -149,6 +149,15 @@ func (val *Value) IsStr() bool { return val.Type() == reflect.String } +// Special list checking function. Something is considered +// a list if it's of type []interface{}. The list is usually +// used in conjunction with rlp decoded streams. +func (val *Value) IsList() bool { + _, ok := val.Val.([]interface{}) + + return ok +} + func (val *Value) IsEmpty() bool { return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0) } -- 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(-) 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(-) 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(-) 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(-) 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(-) 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 +++++++- ethwire/messaging.go | 2 ++ peer.go | 18 ++++++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) 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() diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 185faa341..b622376f3 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -32,6 +32,7 @@ const ( MsgBlockTy = 0x13 MsgGetChainTy = 0x14 MsgNotInChainTy = 0x15 + MsgGetTxsTy = 0x16 MsgTalkTy = 0xff ) @@ -46,6 +47,7 @@ var msgTypeToString = map[MsgType]string{ MsgTxTy: "Transactions", MsgBlockTy: "Blocks", MsgGetChainTy: "Get chain", + MsgGetTxsTy: "Get Txs", MsgNotInChainTy: "Not in chain", } diff --git a/peer.go b/peer.go index 82c983927..279b0bc7f 100644 --- a/peer.go +++ b/peer.go @@ -334,8 +334,8 @@ func (p *Peer) HandleInbound() { // in the TxPool where it will undergo validation and // processing when a new block is found for i := 0; i < msg.Data.Len(); i++ { - //p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) - p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromValue(msg.Data.Get(i))) + tx := ethchain.NewTransactionFromValue(msg.Data.Get(i)) + p.ethereum.TxPool().QueueTransaction(tx) } case ethwire.MsgGetPeersTy: // Flag this peer as a 'requested of new peers' this to @@ -398,6 +398,16 @@ func (p *Peer) HandleInbound() { case ethwire.MsgNotInChainTy: ethutil.Config.Log.Infof("Not in chain %x\n", msg.Data) // TODO + case ethwire.MsgGetTxsTy: + // Get the current transactions of the pool + txs := p.ethereum.TxPool().CurrentTransactions() + // Get the RlpData values from the txs + txsInterface := make([]interface{}, len(txs)) + for i, tx := range txs { + txsInterface[i] = tx.RlpData() + } + // Broadcast it back to the peer + p.QueueMessage(ethwire.NewMessage(ethwire.MsgTxTy, txsInterface)) // Unofficial but fun nonetheless case ethwire.MsgTalkTy: @@ -562,6 +572,10 @@ func (p *Peer) CatchupWithPeer() { p.QueueMessage(msg) ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4]) + + msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) + p.QueueMessage(msg) + ethutil.Config.Log.Debugln("Requested transactions") } } -- 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(-) 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(-) 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(-) 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(-) 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