Fixed minor issue with gas and added state object init

This commit is contained in:
obscuren 2014-04-23 11:51:04 +02:00
parent 61cd1594b5
commit 3a9a252f6e
7 changed files with 135 additions and 56 deletions

View File

@ -91,11 +91,15 @@ func (sm *StateManager) BlockChain() *BlockChain {
return sm.bc return sm.bc
} }
func (sm *StateManager) MakeContract(tx *Transaction) { func (sm *StateManager) MakeContract(tx *Transaction) *StateObject {
contract := MakeContract(tx, sm.procState) contract := MakeContract(tx, sm.procState)
if contract != nil { if contract != nil {
sm.procState.states[string(tx.Hash()[12:])] = contract.state 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 // Apply transactions uses the transaction passed to it and applies them onto
@ -103,11 +107,44 @@ func (sm *StateManager) MakeContract(tx *Transaction) {
func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
// Process each transaction/contract // Process each transaction/contract
for _, tx := range txs { for _, tx := range txs {
fmt.Printf("Processing Tx: %x\n", tx.Hash())
// If there's no recipient, it's a contract // If there's no recipient, it's a contract
// Check if this is a contract creation traction and if so // Check if this is a contract creation traction and if so
// create a contract of this tx. // create a contract of this tx.
if tx.IsContract() { if tx.IsContract() {
sm.MakeContract(tx) 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() {
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 { } else {
// Figure out if the address this transaction was sent to is a // 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 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) { func (sm *StateManager) EvalScript(script []byte, object *StateObject, 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)
}() }
}()
*/
caller := sm.procState.GetAccount(tx.Sender()) caller := sm.procState.GetAccount(tx.Sender())
closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value)

View File

@ -23,12 +23,12 @@ type Transaction struct {
contractCreation bool contractCreation bool
} }
func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte, init []byte) *Transaction {
return &Transaction{Value: value, GasPrice: gasprice, Data: script, Init: init, contractCreation: true} 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 { func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction {
return &Transaction{Recipient: to, Value: value, GasPrice: gasprice, Gas: gas, Data: data} return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data}
} }
func NewTransactionFromBytes(data []byte) *Transaction { func NewTransactionFromBytes(data []byte) *Transaction {
@ -46,9 +46,10 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
} }
func (tx *Transaction) Hash() []byte { 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 { if tx.contractCreation {
data = append(data, string(tx.Init)) data = append(data, tx.Init)
} }
return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) return ethutil.Sha3Bin(ethutil.NewValue(data).Encode())
@ -112,7 +113,6 @@ func (tx *Transaction) RlpData() interface{} {
if tx.contractCreation { if tx.contractCreation {
data = append(data, tx.Init) data = append(data, tx.Init)
} }
//d := ethutil.NewSliceValue(tx.Data).Slice()
return append(data, tx.v, tx.r, tx.s) return append(data, tx.v, tx.r, tx.s)
} }

View File

@ -104,7 +104,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract
// funds won't invalidate this transaction but simple ignores it. // funds won't invalidate this transaction but simple ignores it.
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
if sender.Amount.Cmp(totAmount) < 0 { 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 { 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 { if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
// Subtract the fee // Subtract the fee
sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat))
} else if toContract {
sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat))
} else { } else {
// Subtract the amount from the senders account // Subtract the amount from the senders account
sender.SubAmount(totAmount) sender.SubAmount(totAmount)

View File

@ -35,7 +35,7 @@ const (
oORIGIN = 0x32 oORIGIN = 0x32
oCALLER = 0x33 oCALLER = 0x33
oCALLVALUE = 0x34 oCALLVALUE = 0x34
oCALLDATA = 0x35 oCALLDATALOAD = 0x35
oCALLDATASIZE = 0x36 oCALLDATASIZE = 0x36
oGASPRICE = 0x37 oGASPRICE = 0x37
@ -106,7 +106,7 @@ var opCodeToString = map[OpCode]string{
oORIGIN: "ORIGIN", oORIGIN: "ORIGIN",
oCALLER: "CALLER", oCALLER: "CALLER",
oCALLVALUE: "CALLVALUE", oCALLVALUE: "CALLVALUE",
oCALLDATA: "CALLDATA", oCALLDATALOAD: "CALLDATALOAD",
oCALLDATASIZE: "CALLDATASIZE", oCALLDATASIZE: "CALLDATASIZE",
oGASPRICE: "TXGASPRICE", oGASPRICE: "TXGASPRICE",
@ -180,7 +180,7 @@ var OpCodes = map[string]byte{
"ORIGIN": 0x32, "ORIGIN": 0x32,
"CALLER": 0x33, "CALLER": 0x33,
"CALLVALUE": 0x34, "CALLVALUE": 0x34,
"CALLDATA": 0x35, "CALLDATALOAD": 0x35,
"CALLDATASIZE": 0x36, "CALLDATASIZE": 0x36,
"GASPRICE": 0x38, "GASPRICE": 0x38,

View File

@ -84,11 +84,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
// The base for all big integer arithmetic // The base for all big integer arithmetic
base := new(big.Int) base := new(big.Int)
/* if ethutil.Config.Debug {
if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n")
ethutil.Config.Log.Debugf("# op\n") }
}
*/
for { for {
step++ step++
@ -96,11 +94,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
val := closure.Get(pc) val := closure.Get(pc)
// Get the opcode (it must be an opcode!) // Get the opcode (it must be an opcode!)
op := OpCode(val.Uint()) op := OpCode(val.Uint())
/* if ethutil.Config.Debug {
if ethutil.Config.Debug { ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String())
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) }
}
*/
gas := new(big.Int) gas := new(big.Int)
useGas := func(amount *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: case oCALLVALUE:
// FIXME: Original value of the call, not the current value // FIXME: Original value of the call, not the current value
stack.Push(closure.Value) stack.Push(closure.Value)
case oCALLDATA: case oCALLDATALOAD:
require(1) require(1)
offset := stack.Pop() offset := stack.Pop().Int64()
mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) val := closure.Args[offset : offset+31]
stack.Push(ethutil.BigD(val))
case oCALLDATASIZE: case oCALLDATASIZE:
stack.Push(big.NewInt(int64(len(closure.Args)))) stack.Push(big.NewInt(int64(len(closure.Args))))
case oGASPRICE: case oGASPRICE:

View File

@ -3,7 +3,7 @@ package ethutil
import ( import (
_ "fmt" _ "fmt"
"math/big" "math/big"
"regexp" _ "regexp"
) )
// Op codes // Op codes
@ -143,7 +143,6 @@ init() {
main() { main() {
// main something // main something
} }
*/
func PreProcess(data string) (mainInput, initInput string) { func PreProcess(data string) (mainInput, initInput string) {
reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}"
mainReg := regexp.MustCompile("main" + reg) mainReg := regexp.MustCompile("main" + reg)
@ -163,3 +162,49 @@ func PreProcess(data string) (mainInput, initInput string) {
return 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
}

View File

@ -1,32 +1,31 @@
package ethutil package ethutil
/*
import ( import (
"math" "fmt"
"testing" "testing"
) )
func TestCompile(t *testing.T) { func TestPreProcess(t *testing.T) {
instr, err := CompileInstr("PUSH") main, init := PreProcess(`
init {
if err != nil { // init
t.Error("Failed compiling instruction") if a > b {
if {
}
}
} }
calc := (48 + 0*256 + 0*int64(math.Pow(256, 2))) main {
if BigD(instr).Int64() != calc { // main
t.Error("Expected", calc, ", got:", instr) if a > b {
if c > d {
}
}
} }
} `)
func TestValidInstr(t *testing.T) {
op, args, err := Instr("68163")
if err != nil {
t.Error("Error decoding instruction")
}
fmt.Println("main")
fmt.Println(main)
fmt.Println("init")
fmt.Println(init)
} }
func TestInvalidInstr(t *testing.T) {
}
*/