diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 75a78e9f3b..23da77fae3 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 1e43a2bae4..421f26c98c 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 5cdda17e25..957381ac76 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 24aad82c37..827d4f27f4 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 c249adfebc..33541cb3ba 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: diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 328704caea..9775cf328e 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -3,7 +3,7 @@ package ethutil import ( _ "fmt" "math/big" - "regexp" + _ "regexp" ) // Op codes @@ -143,7 +143,6 @@ init() { main() { // main something } -*/ func PreProcess(data string) (mainInput, initInput string) { reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" mainReg := regexp.MustCompile("main" + reg) @@ -163,3 +162,49 @@ func PreProcess(data string) (mainInput, initInput string) { return } +*/ + +// Very, very dumb parser. Heed no attention :-) +func FindFor(blockMatcher, input string) string { + curCount := -1 + length := len(blockMatcher) + matchfst := rune(blockMatcher[0]) + var currStr string + + for i, run := range input { + // Find init + if curCount == -1 && run == matchfst && input[i:i+length] == blockMatcher { + curCount = 0 + } else if curCount > -1 { + if run == '{' { + curCount++ + if curCount == 1 { + continue + } + } else if run == '}' { + curCount-- + if curCount == 0 { + // we are done + curCount = -1 + break + } + } + + if curCount > 0 { + currStr += string(run) + } + } + } + + return currStr +} + +func PreProcess(data string) (mainInput, initInput string) { + mainInput = FindFor("main", data) + if mainInput == "" { + mainInput = data + } + initInput = FindFor("init", data) + + return +} diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go index 6b59777e69..a9ad347dd2 100644 --- a/ethutil/parsing_test.go +++ b/ethutil/parsing_test.go @@ -1,32 +1,31 @@ package ethutil -/* import ( - "math" + "fmt" "testing" ) -func TestCompile(t *testing.T) { - instr, err := CompileInstr("PUSH") - - if err != nil { - t.Error("Failed compiling instruction") +func TestPreProcess(t *testing.T) { + main, init := PreProcess(` + init { + // init + if a > b { + if { + } + } } - calc := (48 + 0*256 + 0*int64(math.Pow(256, 2))) - if BigD(instr).Int64() != calc { - t.Error("Expected", calc, ", got:", instr) + main { + // main + if a > b { + if c > d { + } + } } -} - -func TestValidInstr(t *testing.T) { - op, args, err := Instr("68163") - if err != nil { - t.Error("Error decoding instruction") - } - -} + `) -func TestInvalidInstr(t *testing.T) { + fmt.Println("main") + fmt.Println(main) + fmt.Println("init") + fmt.Println(init) } -*/