Merge branch 'release/poc5-rc11'
This commit is contained in:
commit
95adac7522
@ -6,7 +6,7 @@ Ethereum
|
|||||||
Ethereum Go Development package (C) Jeffrey Wilcke
|
Ethereum Go Development package (C) Jeffrey Wilcke
|
||||||
|
|
||||||
Ethereum is currently in its testing phase. The current state is "Proof
|
Ethereum is currently in its testing phase. The current state is "Proof
|
||||||
of Concept 5.0 RC9". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
|
of Concept 5.0 RC11". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
|
||||||
|
|
||||||
Ethereum Go is split up in several sub packages Please refer to each
|
Ethereum Go is split up in several sub packages Please refer to each
|
||||||
individual package for more information.
|
individual package for more information.
|
||||||
|
@ -21,9 +21,9 @@ func Disassemble(script []byte) (asm []string) {
|
|||||||
asm = append(asm, fmt.Sprintf("%v", op))
|
asm = append(asm, fmt.Sprintf("%v", op))
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32:
|
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
||||||
pc.Add(pc, ethutil.Big1)
|
pc.Add(pc, ethutil.Big1)
|
||||||
a := int64(op) - int64(oPUSH1) + 1
|
a := int64(op) - int64(PUSH1) + 1
|
||||||
data := script[pc.Int64() : pc.Int64()+a]
|
data := script[pc.Int64() : pc.Int64()+a]
|
||||||
val := ethutil.BigD(data)
|
val := ethutil.BigD(data)
|
||||||
|
|
||||||
|
@ -22,8 +22,7 @@ type Closure struct {
|
|||||||
Script []byte
|
Script []byte
|
||||||
State *State
|
State *State
|
||||||
|
|
||||||
Gas *big.Int
|
Gas, UsedGas, Price *big.Int
|
||||||
Price *big.Int
|
|
||||||
|
|
||||||
Args []byte
|
Args []byte
|
||||||
}
|
}
|
||||||
@ -36,6 +35,7 @@ func NewClosure(callee, object *StateObject, script []byte, state *State, gas, p
|
|||||||
// and we don't want the transaction's values to change.
|
// and we don't want the transaction's values to change.
|
||||||
c.Gas = new(big.Int).Set(gas)
|
c.Gas = new(big.Int).Set(gas)
|
||||||
c.Price = new(big.Int).Set(price)
|
c.Price = new(big.Int).Set(price)
|
||||||
|
c.UsedGas = new(big.Int)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -74,10 +74,12 @@ func (c *Closure) Address() []byte {
|
|||||||
|
|
||||||
type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
|
type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
|
||||||
|
|
||||||
func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) {
|
func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, error) {
|
||||||
c.Args = args
|
c.Args = args
|
||||||
|
|
||||||
return vm.RunClosure(c, hook)
|
ret, err := vm.RunClosure(c, hook)
|
||||||
|
|
||||||
|
return ret, c.UsedGas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Closure) Return(ret []byte) []byte {
|
func (c *Closure) Return(ret []byte) []byte {
|
||||||
@ -93,10 +95,23 @@ func (c *Closure) Return(ret []byte) []byte {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Closure) UseGas(gas *big.Int) bool {
|
||||||
|
if c.Gas.Cmp(gas) < 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub the amount of gas from the remaining
|
||||||
|
c.Gas.Sub(c.Gas, gas)
|
||||||
|
c.UsedGas.Add(c.UsedGas, gas)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Implement the Callee interface
|
// Implement the Callee interface
|
||||||
func (c *Closure) ReturnGas(gas, price *big.Int, state *State) {
|
func (c *Closure) ReturnGas(gas, price *big.Int, state *State) {
|
||||||
// Return the gas to the closure
|
// Return the gas to the closure
|
||||||
c.Gas.Add(c.Gas, gas)
|
c.Gas.Add(c.Gas, gas)
|
||||||
|
c.UsedGas.Sub(c.UsedGas, gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Closure) Object() *StateObject {
|
func (c *Closure) Object() *StateObject {
|
||||||
|
@ -105,8 +105,11 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra
|
|||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
usedGas, err := sm.ApplyTransaction(state, block, tx)
|
usedGas, err := sm.ApplyTransaction(state, block, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if IsNonceErr(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
ethutil.Config.Log.Infoln(err)
|
ethutil.Config.Log.Infoln(err)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas))
|
accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas))
|
||||||
@ -116,10 +119,10 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra
|
|||||||
validTxs = append(validTxs, tx)
|
validTxs = append(validTxs, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return receipts, txs
|
return receipts, validTxs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) {
|
func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) {
|
||||||
/*
|
/*
|
||||||
Applies transactions to the given state and creates new
|
Applies transactions to the given state and creates new
|
||||||
state objects where needed.
|
state objects where needed.
|
||||||
@ -129,9 +132,17 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac
|
|||||||
assume there's a return value. The return value will be set to
|
assume there's a return value. The return value will be set to
|
||||||
the script section of the state object.
|
the script section of the state object.
|
||||||
*/
|
*/
|
||||||
totalGasUsed := big.NewInt(0)
|
var (
|
||||||
|
addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) }
|
||||||
|
gas = new(big.Int)
|
||||||
|
script []byte
|
||||||
|
)
|
||||||
|
totalGasUsed = big.NewInt(0)
|
||||||
|
|
||||||
// Apply the transaction to the current state
|
// Apply the transaction to the current state
|
||||||
err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false)
|
gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false)
|
||||||
|
addTotalGas(gas)
|
||||||
|
|
||||||
if tx.CreatesContract() {
|
if tx.CreatesContract() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Create a new state object and the transaction
|
// Create a new state object and the transaction
|
||||||
@ -141,30 +152,32 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac
|
|||||||
// Evaluate the initialization script
|
// Evaluate the initialization script
|
||||||
// and use the return value as the
|
// and use the return value as the
|
||||||
// script section for the state object.
|
// script section for the state object.
|
||||||
script, err := sm.EvalScript(state, contract.Init(), contract, tx, block)
|
script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block)
|
||||||
|
addTotalGas(gas)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("[STATE] Error during init script run %v", err)
|
err = fmt.Errorf("[STATE] Error during init script run %v", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
contract.script = script
|
contract.script = script
|
||||||
state.UpdateStateObject(contract)
|
state.UpdateStateObject(contract)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("[STATE] Unable to create contract")
|
err = fmt.Errorf("[STATE] Unable to create contract")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("[STATE] contract creation tx:", err)
|
err = fmt.Errorf("[STATE] contract creation tx: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Find the state object at the "recipient" address. If
|
// Find the state object at the "recipient" address. If
|
||||||
// there's an object attempt to run the script.
|
// there's an object attempt to run the script.
|
||||||
stateObject := state.GetStateObject(tx.Recipient)
|
stateObject := state.GetStateObject(tx.Recipient)
|
||||||
if err == nil && stateObject != nil && len(stateObject.Script()) > 0 {
|
if err == nil && stateObject != nil && len(stateObject.Script()) > 0 {
|
||||||
sm.EvalScript(state, stateObject.Script(), stateObject, tx, block)
|
_, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block)
|
||||||
} else if err != nil {
|
addTotalGas(gas)
|
||||||
return nil, fmt.Errorf("[STATE] process:", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalGasUsed, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) Process(block *Block, dontReact bool) error {
|
func (sm *StateManager) Process(block *Block, dontReact bool) error {
|
||||||
@ -349,7 +362,7 @@ func (sm *StateManager) Stop() {
|
|||||||
sm.bc.Stop()
|
sm.bc.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, err error) {
|
func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) {
|
||||||
account := state.GetAccount(tx.Sender())
|
account := state.GetAccount(tx.Sender())
|
||||||
|
|
||||||
err = account.ConvertGas(tx.Gas, tx.GasPrice)
|
err = account.ConvertGas(tx.Gas, tx.GasPrice)
|
||||||
@ -369,7 +382,7 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj
|
|||||||
Value: tx.Value,
|
Value: tx.Value,
|
||||||
//Price: tx.GasPrice,
|
//Price: tx.GasPrice,
|
||||||
})
|
})
|
||||||
ret, err = closure.Call(vm, tx.Data, nil)
|
ret, gas, err = closure.Call(vm, tx.Data, nil)
|
||||||
|
|
||||||
// Update the account (refunds)
|
// Update the account (refunds)
|
||||||
state.UpdateStateObject(account)
|
state.UpdateStateObject(account)
|
||||||
|
@ -147,22 +147,6 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
|
|||||||
if len(tx.Recipient) == 0 {
|
if len(tx.Recipient) == 0 {
|
||||||
tx.contractCreation = true
|
tx.contractCreation = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// If the list is of length 10 it's a contract creation tx
|
|
||||||
if decoder.Len() == 10 {
|
|
||||||
tx.contractCreation = true
|
|
||||||
tx.Init = decoder.Get(6).Bytes()
|
|
||||||
|
|
||||||
tx.v = byte(decoder.Get(7).Uint())
|
|
||||||
tx.r = decoder.Get(8).Bytes()
|
|
||||||
tx.s = decoder.Get(9).Bytes()
|
|
||||||
} else {
|
|
||||||
tx.v = byte(decoder.Get(6).Uint())
|
|
||||||
tx.r = decoder.Get(7).Bytes()
|
|
||||||
tx.s = decoder.Get(8).Bytes()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) String() string {
|
func (tx *Transaction) String() string {
|
||||||
@ -228,3 +212,15 @@ func (self *Receipt) String() string {
|
|||||||
self.PostState,
|
self.PostState,
|
||||||
self.CumulativeGasUsed)
|
self.CumulativeGasUsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transaction slice type for basic sorting
|
||||||
|
type Transactions []*Transaction
|
||||||
|
|
||||||
|
func (s Transactions) Len() int { return len(s) }
|
||||||
|
func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
|
type TxByNonce struct{ Transactions }
|
||||||
|
|
||||||
|
func (s TxByNonce) Less(i, j int) bool {
|
||||||
|
return s.Transactions[i].Nonce < s.Transactions[j].Nonce
|
||||||
|
}
|
||||||
|
@ -91,28 +91,37 @@ func (pool *TxPool) addTransaction(tx *Transaction) {
|
|||||||
|
|
||||||
// Process transaction validates the Tx and processes funds from the
|
// Process transaction validates the Tx and processes funds from the
|
||||||
// sender to the recipient.
|
// sender to the recipient.
|
||||||
func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) {
|
func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (gas *big.Int, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ethutil.Config.Log.Infoln(r)
|
ethutil.Config.Log.Infoln(r)
|
||||||
err = fmt.Errorf("%v", r)
|
err = fmt.Errorf("%v", r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
gas = new(big.Int)
|
||||||
|
addGas := func(g *big.Int) { gas.Add(gas, g) }
|
||||||
|
|
||||||
// Get the sender
|
// Get the sender
|
||||||
sender := state.GetAccount(tx.Sender())
|
sender := state.GetAccount(tx.Sender())
|
||||||
|
|
||||||
if sender.Nonce != tx.Nonce {
|
if sender.Nonce != tx.Nonce {
|
||||||
return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce)
|
err = NonceError(tx.Nonce, sender.Nonce)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txTotalBytes := big.NewInt(int64(len(tx.Data)))
|
||||||
|
txTotalBytes.Div(txTotalBytes, ethutil.Big32)
|
||||||
|
addGas(new(big.Int).Mul(txTotalBytes, GasSStore))
|
||||||
|
|
||||||
// Make sure there's enough in the sender's account. Having insufficient
|
// Make sure there's enough in the sender's account. Having insufficient
|
||||||
// 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))
|
||||||
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice))
|
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice))
|
||||||
if sender.Amount.Cmp(totAmount) < 0 {
|
if sender.Amount.Cmp(totAmount) < 0 {
|
||||||
return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
|
err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
//fmt.Println(tx)
|
|
||||||
|
|
||||||
// Get the receiver
|
// Get the receiver
|
||||||
receiver := state.GetAccount(tx.Recipient)
|
receiver := state.GetAccount(tx.Recipient)
|
||||||
@ -120,6 +129,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract
|
|||||||
|
|
||||||
// Send Tx to self
|
// Send Tx to self
|
||||||
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
|
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
|
||||||
|
addGas(GasTx)
|
||||||
// Subtract the fee
|
// Subtract the fee
|
||||||
sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice))
|
sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice))
|
||||||
} else {
|
} else {
|
||||||
@ -225,7 +235,7 @@ func (pool *TxPool) RemoveInvalid(state *State) {
|
|||||||
tx := e.Value.(*Transaction)
|
tx := e.Value.(*Transaction)
|
||||||
sender := state.GetAccount(tx.Sender())
|
sender := state.GetAccount(tx.Sender())
|
||||||
err := pool.ValidateTransaction(tx)
|
err := pool.ValidateTransaction(tx)
|
||||||
if err != nil || sender.Nonce != tx.Nonce {
|
if err != nil || sender.Nonce >= tx.Nonce {
|
||||||
pool.pool.Remove(e)
|
pool.pool.Remove(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,206 +5,206 @@ type OpCode int
|
|||||||
// Op codes
|
// Op codes
|
||||||
const (
|
const (
|
||||||
// 0x0 range - arithmetic ops
|
// 0x0 range - arithmetic ops
|
||||||
oSTOP = 0x00
|
STOP = 0x00
|
||||||
oADD = 0x01
|
ADD = 0x01
|
||||||
oMUL = 0x02
|
MUL = 0x02
|
||||||
oSUB = 0x03
|
SUB = 0x03
|
||||||
oDIV = 0x04
|
DIV = 0x04
|
||||||
oSDIV = 0x05
|
SDIV = 0x05
|
||||||
oMOD = 0x06
|
MOD = 0x06
|
||||||
oSMOD = 0x07
|
SMOD = 0x07
|
||||||
oEXP = 0x08
|
EXP = 0x08
|
||||||
oNEG = 0x09
|
NEG = 0x09
|
||||||
oLT = 0x0a
|
LT = 0x0a
|
||||||
oGT = 0x0b
|
GT = 0x0b
|
||||||
oEQ = 0x0c
|
EQ = 0x0c
|
||||||
oNOT = 0x0d
|
NOT = 0x0d
|
||||||
|
|
||||||
// 0x10 range - bit ops
|
// 0x10 range - bit ops
|
||||||
oAND = 0x10
|
AND = 0x10
|
||||||
oOR = 0x11
|
OR = 0x11
|
||||||
oXOR = 0x12
|
XOR = 0x12
|
||||||
oBYTE = 0x13
|
BYTE = 0x13
|
||||||
|
|
||||||
// 0x20 range - crypto
|
// 0x20 range - crypto
|
||||||
oSHA3 = 0x20
|
SHA3 = 0x20
|
||||||
|
|
||||||
// 0x30 range - closure state
|
// 0x30 range - closure state
|
||||||
oADDRESS = 0x30
|
ADDRESS = 0x30
|
||||||
oBALANCE = 0x31
|
BALANCE = 0x31
|
||||||
oORIGIN = 0x32
|
ORIGIN = 0x32
|
||||||
oCALLER = 0x33
|
CALLER = 0x33
|
||||||
oCALLVALUE = 0x34
|
CALLVALUE = 0x34
|
||||||
oCALLDATALOAD = 0x35
|
CALLDATALOAD = 0x35
|
||||||
oCALLDATASIZE = 0x36
|
CALLDATASIZE = 0x36
|
||||||
oGASPRICE = 0x37
|
GASPRICE = 0x37
|
||||||
|
|
||||||
// 0x40 range - block operations
|
// 0x40 range - block operations
|
||||||
oPREVHASH = 0x40
|
PREVHASH = 0x40
|
||||||
oCOINBASE = 0x41
|
COINBASE = 0x41
|
||||||
oTIMESTAMP = 0x42
|
TIMESTAMP = 0x42
|
||||||
oNUMBER = 0x43
|
NUMBER = 0x43
|
||||||
oDIFFICULTY = 0x44
|
DIFFICULTY = 0x44
|
||||||
oGASLIMIT = 0x45
|
GASLIMIT = 0x45
|
||||||
|
|
||||||
// 0x50 range - 'storage' and execution
|
// 0x50 range - 'storage' and execution
|
||||||
oPOP = 0x51
|
POP = 0x51
|
||||||
oDUP = 0x52
|
DUP = 0x52
|
||||||
oSWAP = 0x53
|
SWAP = 0x53
|
||||||
oMLOAD = 0x54
|
MLOAD = 0x54
|
||||||
oMSTORE = 0x55
|
MSTORE = 0x55
|
||||||
oMSTORE8 = 0x56
|
MSTORE8 = 0x56
|
||||||
oSLOAD = 0x57
|
SLOAD = 0x57
|
||||||
oSSTORE = 0x58
|
SSTORE = 0x58
|
||||||
oJUMP = 0x59
|
JUMP = 0x59
|
||||||
oJUMPI = 0x5a
|
JUMPI = 0x5a
|
||||||
oPC = 0x5b
|
PC = 0x5b
|
||||||
oMSIZE = 0x5c
|
MSIZE = 0x5c
|
||||||
|
|
||||||
// 0x60 range
|
// 0x60 range
|
||||||
oPUSH1 = 0x60
|
PUSH1 = 0x60
|
||||||
oPUSH2 = 0x61
|
PUSH2 = 0x61
|
||||||
oPUSH3 = 0x62
|
PUSH3 = 0x62
|
||||||
oPUSH4 = 0x63
|
PUSH4 = 0x63
|
||||||
oPUSH5 = 0x64
|
PUSH5 = 0x64
|
||||||
oPUSH6 = 0x65
|
PUSH6 = 0x65
|
||||||
oPUSH7 = 0x66
|
PUSH7 = 0x66
|
||||||
oPUSH8 = 0x67
|
PUSH8 = 0x67
|
||||||
oPUSH9 = 0x68
|
PUSH9 = 0x68
|
||||||
oPUSH10 = 0x69
|
PUSH10 = 0x69
|
||||||
oPUSH11 = 0x6a
|
PUSH11 = 0x6a
|
||||||
oPUSH12 = 0x6b
|
PUSH12 = 0x6b
|
||||||
oPUSH13 = 0x6c
|
PUSH13 = 0x6c
|
||||||
oPUSH14 = 0x6d
|
PUSH14 = 0x6d
|
||||||
oPUSH15 = 0x6e
|
PUSH15 = 0x6e
|
||||||
oPUSH16 = 0x6f
|
PUSH16 = 0x6f
|
||||||
oPUSH17 = 0x70
|
PUSH17 = 0x70
|
||||||
oPUSH18 = 0x71
|
PUSH18 = 0x71
|
||||||
oPUSH19 = 0x72
|
PUSH19 = 0x72
|
||||||
oPUSH20 = 0x73
|
PUSH20 = 0x73
|
||||||
oPUSH21 = 0x74
|
PUSH21 = 0x74
|
||||||
oPUSH22 = 0x75
|
PUSH22 = 0x75
|
||||||
oPUSH23 = 0x76
|
PUSH23 = 0x76
|
||||||
oPUSH24 = 0x77
|
PUSH24 = 0x77
|
||||||
oPUSH25 = 0x78
|
PUSH25 = 0x78
|
||||||
oPUSH26 = 0x79
|
PUSH26 = 0x79
|
||||||
oPUSH27 = 0x7a
|
PUSH27 = 0x7a
|
||||||
oPUSH28 = 0x7b
|
PUSH28 = 0x7b
|
||||||
oPUSH29 = 0x7c
|
PUSH29 = 0x7c
|
||||||
oPUSH30 = 0x7d
|
PUSH30 = 0x7d
|
||||||
oPUSH31 = 0x7e
|
PUSH31 = 0x7e
|
||||||
oPUSH32 = 0x7f
|
PUSH32 = 0x7f
|
||||||
|
|
||||||
// 0xf0 range - closures
|
// 0xf0 range - closures
|
||||||
oCREATE = 0xf0
|
CREATE = 0xf0
|
||||||
oCALL = 0xf1
|
CALL = 0xf1
|
||||||
oRETURN = 0xf2
|
RETURN = 0xf2
|
||||||
|
|
||||||
// 0x70 range - other
|
// 0x70 range - other
|
||||||
oLOG = 0xfe // XXX Unofficial
|
LOG = 0xfe // XXX Unofficial
|
||||||
oSUICIDE = 0xff
|
SUICIDE = 0xff
|
||||||
)
|
)
|
||||||
|
|
||||||
// Since the opcodes aren't all in order we can't use a regular slice
|
// Since the opcodes aren't all in order we can't use a regular slice
|
||||||
var opCodeToString = map[OpCode]string{
|
var opCodeToString = map[OpCode]string{
|
||||||
// 0x0 range - arithmetic ops
|
// 0x0 range - arithmetic ops
|
||||||
oSTOP: "STOP",
|
STOP: "STOP",
|
||||||
oADD: "ADD",
|
ADD: "ADD",
|
||||||
oMUL: "MUL",
|
MUL: "MUL",
|
||||||
oSUB: "SUB",
|
SUB: "SUB",
|
||||||
oDIV: "DIV",
|
DIV: "DIV",
|
||||||
oSDIV: "SDIV",
|
SDIV: "SDIV",
|
||||||
oMOD: "MOD",
|
MOD: "MOD",
|
||||||
oSMOD: "SMOD",
|
SMOD: "SMOD",
|
||||||
oEXP: "EXP",
|
EXP: "EXP",
|
||||||
oNEG: "NEG",
|
NEG: "NEG",
|
||||||
oLT: "LT",
|
LT: "LT",
|
||||||
oGT: "GT",
|
GT: "GT",
|
||||||
oEQ: "EQ",
|
EQ: "EQ",
|
||||||
oNOT: "NOT",
|
NOT: "NOT",
|
||||||
|
|
||||||
// 0x10 range - bit ops
|
// 0x10 range - bit ops
|
||||||
oAND: "AND",
|
AND: "AND",
|
||||||
oOR: "OR",
|
OR: "OR",
|
||||||
oXOR: "XOR",
|
XOR: "XOR",
|
||||||
oBYTE: "BYTE",
|
BYTE: "BYTE",
|
||||||
|
|
||||||
// 0x20 range - crypto
|
// 0x20 range - crypto
|
||||||
oSHA3: "SHA3",
|
SHA3: "SHA3",
|
||||||
|
|
||||||
// 0x30 range - closure state
|
// 0x30 range - closure state
|
||||||
oADDRESS: "ADDRESS",
|
ADDRESS: "ADDRESS",
|
||||||
oBALANCE: "BALANCE",
|
BALANCE: "BALANCE",
|
||||||
oORIGIN: "ORIGIN",
|
ORIGIN: "ORIGIN",
|
||||||
oCALLER: "CALLER",
|
CALLER: "CALLER",
|
||||||
oCALLVALUE: "CALLVALUE",
|
CALLVALUE: "CALLVALUE",
|
||||||
oCALLDATALOAD: "CALLDATALOAD",
|
CALLDATALOAD: "CALLDATALOAD",
|
||||||
oCALLDATASIZE: "CALLDATASIZE",
|
CALLDATASIZE: "CALLDATASIZE",
|
||||||
oGASPRICE: "TXGASPRICE",
|
GASPRICE: "TXGASPRICE",
|
||||||
|
|
||||||
// 0x40 range - block operations
|
// 0x40 range - block operations
|
||||||
oPREVHASH: "PREVHASH",
|
PREVHASH: "PREVHASH",
|
||||||
oCOINBASE: "COINBASE",
|
COINBASE: "COINBASE",
|
||||||
oTIMESTAMP: "TIMESTAMP",
|
TIMESTAMP: "TIMESTAMP",
|
||||||
oNUMBER: "NUMBER",
|
NUMBER: "NUMBER",
|
||||||
oDIFFICULTY: "DIFFICULTY",
|
DIFFICULTY: "DIFFICULTY",
|
||||||
oGASLIMIT: "GASLIMIT",
|
GASLIMIT: "GASLIMIT",
|
||||||
|
|
||||||
// 0x50 range - 'storage' and execution
|
// 0x50 range - 'storage' and execution
|
||||||
oDUP: "DUP",
|
DUP: "DUP",
|
||||||
oSWAP: "SWAP",
|
SWAP: "SWAP",
|
||||||
oMLOAD: "MLOAD",
|
MLOAD: "MLOAD",
|
||||||
oMSTORE: "MSTORE",
|
MSTORE: "MSTORE",
|
||||||
oMSTORE8: "MSTORE8",
|
MSTORE8: "MSTORE8",
|
||||||
oSLOAD: "SLOAD",
|
SLOAD: "SLOAD",
|
||||||
oSSTORE: "SSTORE",
|
SSTORE: "SSTORE",
|
||||||
oJUMP: "JUMP",
|
JUMP: "JUMP",
|
||||||
oJUMPI: "JUMPI",
|
JUMPI: "JUMPI",
|
||||||
oPC: "PC",
|
PC: "PC",
|
||||||
oMSIZE: "MSIZE",
|
MSIZE: "MSIZE",
|
||||||
|
|
||||||
// 0x60 range - push
|
// 0x60 range - push
|
||||||
oPUSH1: "PUSH1",
|
PUSH1: "PUSH1",
|
||||||
oPUSH2: "PUSH2",
|
PUSH2: "PUSH2",
|
||||||
oPUSH3: "PUSH3",
|
PUSH3: "PUSH3",
|
||||||
oPUSH4: "PUSH4",
|
PUSH4: "PUSH4",
|
||||||
oPUSH5: "PUSH5",
|
PUSH5: "PUSH5",
|
||||||
oPUSH6: "PUSH6",
|
PUSH6: "PUSH6",
|
||||||
oPUSH7: "PUSH7",
|
PUSH7: "PUSH7",
|
||||||
oPUSH8: "PUSH8",
|
PUSH8: "PUSH8",
|
||||||
oPUSH9: "PUSH9",
|
PUSH9: "PUSH9",
|
||||||
oPUSH10: "PUSH10",
|
PUSH10: "PUSH10",
|
||||||
oPUSH11: "PUSH11",
|
PUSH11: "PUSH11",
|
||||||
oPUSH12: "PUSH12",
|
PUSH12: "PUSH12",
|
||||||
oPUSH13: "PUSH13",
|
PUSH13: "PUSH13",
|
||||||
oPUSH14: "PUSH14",
|
PUSH14: "PUSH14",
|
||||||
oPUSH15: "PUSH15",
|
PUSH15: "PUSH15",
|
||||||
oPUSH16: "PUSH16",
|
PUSH16: "PUSH16",
|
||||||
oPUSH17: "PUSH17",
|
PUSH17: "PUSH17",
|
||||||
oPUSH18: "PUSH18",
|
PUSH18: "PUSH18",
|
||||||
oPUSH19: "PUSH19",
|
PUSH19: "PUSH19",
|
||||||
oPUSH20: "PUSH20",
|
PUSH20: "PUSH20",
|
||||||
oPUSH21: "PUSH21",
|
PUSH21: "PUSH21",
|
||||||
oPUSH22: "PUSH22",
|
PUSH22: "PUSH22",
|
||||||
oPUSH23: "PUSH23",
|
PUSH23: "PUSH23",
|
||||||
oPUSH24: "PUSH24",
|
PUSH24: "PUSH24",
|
||||||
oPUSH25: "PUSH25",
|
PUSH25: "PUSH25",
|
||||||
oPUSH26: "PUSH26",
|
PUSH26: "PUSH26",
|
||||||
oPUSH27: "PUSH27",
|
PUSH27: "PUSH27",
|
||||||
oPUSH28: "PUSH28",
|
PUSH28: "PUSH28",
|
||||||
oPUSH29: "PUSH29",
|
PUSH29: "PUSH29",
|
||||||
oPUSH30: "PUSH30",
|
PUSH30: "PUSH30",
|
||||||
oPUSH31: "PUSH31",
|
PUSH31: "PUSH31",
|
||||||
oPUSH32: "PUSH32",
|
PUSH32: "PUSH32",
|
||||||
|
|
||||||
// 0xf0 range
|
// 0xf0 range
|
||||||
oCREATE: "CREATE",
|
CREATE: "CREATE",
|
||||||
oCALL: "CALL",
|
CALL: "CALL",
|
||||||
oRETURN: "RETURN",
|
RETURN: "RETURN",
|
||||||
|
|
||||||
// 0x70 range - other
|
// 0x70 range - other
|
||||||
oLOG: "LOG",
|
LOG: "LOG",
|
||||||
oSUICIDE: "SUICIDE",
|
SUICIDE: "SUICIDE",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o OpCode) String() string {
|
func (o OpCode) String() string {
|
||||||
@ -322,10 +322,3 @@ func IsOpCode(s string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppendScript(init, script []byte) []byte {
|
|
||||||
s := append(init, byte(oRETURN))
|
|
||||||
s = append(s, script...)
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
164
ethchain/vm.go
164
ethchain/vm.go
@ -21,11 +21,10 @@ var (
|
|||||||
GasTx = big.NewInt(500)
|
GasTx = big.NewInt(500)
|
||||||
)
|
)
|
||||||
|
|
||||||
func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int {
|
func CalculateTxGas(initSize *big.Int) *big.Int {
|
||||||
totalGas := new(big.Int)
|
totalGas := new(big.Int)
|
||||||
totalGas.Add(totalGas, GasCreate)
|
|
||||||
|
|
||||||
txTotalBytes := new(big.Int).Add(initSize, scriptSize)
|
txTotalBytes := new(big.Int).Set(initSize)
|
||||||
txTotalBytes.Div(txTotalBytes, ethutil.Big32)
|
txTotalBytes.Div(txTotalBytes, ethutil.Big32)
|
||||||
totalGas.Add(totalGas, new(big.Int).Mul(txTotalBytes, GasSStore))
|
totalGas.Add(totalGas, new(big.Int).Mul(txTotalBytes, GasSStore))
|
||||||
|
|
||||||
@ -92,12 +91,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
pc := big.NewInt(0)
|
pc := big.NewInt(0)
|
||||||
// Current step count
|
// Current step count
|
||||||
step := 0
|
step := 0
|
||||||
|
prevStep := 0
|
||||||
|
|
||||||
if ethutil.Config.Debug {
|
if ethutil.Config.Debug {
|
||||||
ethutil.Config.Log.Debugf("# op\n")
|
ethutil.Config.Log.Debugf("# op\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
prevStep = step
|
||||||
// The base for all big integer arithmetic
|
// The base for all big integer arithmetic
|
||||||
base := new(big.Int)
|
base := new(big.Int)
|
||||||
|
|
||||||
@ -111,16 +112,16 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
gas := new(big.Int)
|
gas := new(big.Int)
|
||||||
useGas := func(amount *big.Int) {
|
setStepGasUsage := func(amount *big.Int) {
|
||||||
gas.Add(gas, amount)
|
gas.Add(gas, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case oSHA3:
|
case SHA3:
|
||||||
useGas(GasSha)
|
setStepGasUsage(GasSha)
|
||||||
case oSLOAD:
|
case SLOAD:
|
||||||
useGas(GasSLoad)
|
setStepGasUsage(GasSLoad)
|
||||||
case oSSTORE:
|
case SSTORE:
|
||||||
var mult *big.Int
|
var mult *big.Int
|
||||||
y, x := stack.Peekn()
|
y, x := stack.Peekn()
|
||||||
val := closure.GetMem(x)
|
val := closure.GetMem(x)
|
||||||
@ -131,67 +132,64 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
} else {
|
} else {
|
||||||
mult = ethutil.Big1
|
mult = ethutil.Big1
|
||||||
}
|
}
|
||||||
useGas(new(big.Int).Mul(mult, GasSStore))
|
setStepGasUsage(new(big.Int).Mul(mult, GasSStore))
|
||||||
case oBALANCE:
|
case BALANCE:
|
||||||
useGas(GasBalance)
|
setStepGasUsage(GasBalance)
|
||||||
case oCREATE:
|
case CREATE:
|
||||||
require(3)
|
require(3)
|
||||||
|
|
||||||
args := stack.Get(big.NewInt(3))
|
args := stack.Get(big.NewInt(3))
|
||||||
initSize := new(big.Int).Add(args[1], args[0])
|
initSize := new(big.Int).Add(args[1], args[0])
|
||||||
|
|
||||||
useGas(CalculateTxGas(initSize, ethutil.Big0))
|
setStepGasUsage(CalculateTxGas(initSize))
|
||||||
case oCALL:
|
case CALL:
|
||||||
useGas(GasCall)
|
setStepGasUsage(GasCall)
|
||||||
case oMLOAD, oMSIZE, oMSTORE8, oMSTORE:
|
case MLOAD, MSIZE, MSTORE8, MSTORE:
|
||||||
useGas(GasMemory)
|
setStepGasUsage(GasMemory)
|
||||||
default:
|
default:
|
||||||
useGas(GasStep)
|
setStepGasUsage(GasStep)
|
||||||
}
|
}
|
||||||
|
|
||||||
if closure.Gas.Cmp(gas) < 0 {
|
if !closure.UseGas(gas) {
|
||||||
ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas)
|
ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas)
|
||||||
|
|
||||||
return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas)
|
return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sub the amount of gas from the remaining
|
|
||||||
closure.Gas.Sub(closure.Gas, gas)
|
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case oLOG:
|
case LOG:
|
||||||
stack.Print()
|
stack.Print()
|
||||||
mem.Print()
|
mem.Print()
|
||||||
// 0x20 range
|
// 0x20 range
|
||||||
case oADD:
|
case ADD:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// (x + y) % 2 ** 256
|
// (x + y) % 2 ** 256
|
||||||
base.Add(x, y)
|
base.Add(x, y)
|
||||||
// Pop result back on the stack
|
// Pop result back on the stack
|
||||||
stack.Push(base)
|
stack.Push(base)
|
||||||
case oSUB:
|
case SUB:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// (x - y) % 2 ** 256
|
// (x - y) % 2 ** 256
|
||||||
base.Sub(x, y)
|
base.Sub(x, y)
|
||||||
// Pop result back on the stack
|
// Pop result back on the stack
|
||||||
stack.Push(base)
|
stack.Push(base)
|
||||||
case oMUL:
|
case MUL:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// (x * y) % 2 ** 256
|
// (x * y) % 2 ** 256
|
||||||
base.Mul(x, y)
|
base.Mul(x, y)
|
||||||
// Pop result back on the stack
|
// Pop result back on the stack
|
||||||
stack.Push(base)
|
stack.Push(base)
|
||||||
case oDIV:
|
case DIV:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// floor(x / y)
|
// floor(x / y)
|
||||||
base.Div(x, y)
|
base.Div(x, y)
|
||||||
// Pop result back on the stack
|
// Pop result back on the stack
|
||||||
stack.Push(base)
|
stack.Push(base)
|
||||||
case oSDIV:
|
case SDIV:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// n > 2**255
|
// n > 2**255
|
||||||
@ -208,12 +206,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
}
|
}
|
||||||
// Push result on to the stack
|
// Push result on to the stack
|
||||||
stack.Push(z)
|
stack.Push(z)
|
||||||
case oMOD:
|
case MOD:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
base.Mod(x, y)
|
base.Mod(x, y)
|
||||||
stack.Push(base)
|
stack.Push(base)
|
||||||
case oSMOD:
|
case SMOD:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// n > 2**255
|
// n > 2**255
|
||||||
@ -230,17 +228,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
}
|
}
|
||||||
// Push result on to the stack
|
// Push result on to the stack
|
||||||
stack.Push(z)
|
stack.Push(z)
|
||||||
case oEXP:
|
case EXP:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
base.Exp(x, y, Pow256)
|
base.Exp(x, y, Pow256)
|
||||||
|
|
||||||
stack.Push(base)
|
stack.Push(base)
|
||||||
case oNEG:
|
case NEG:
|
||||||
require(1)
|
require(1)
|
||||||
base.Sub(Pow256, stack.Pop())
|
base.Sub(Pow256, stack.Pop())
|
||||||
stack.Push(base)
|
stack.Push(base)
|
||||||
case oLT:
|
case LT:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// x < y
|
// x < y
|
||||||
@ -249,7 +247,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
} else {
|
} else {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
}
|
}
|
||||||
case oGT:
|
case GT:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// x > y
|
// x > y
|
||||||
@ -258,7 +256,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
} else {
|
} else {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
}
|
}
|
||||||
case oEQ:
|
case EQ:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
// x == y
|
// x == y
|
||||||
@ -267,7 +265,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
} else {
|
} else {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
}
|
}
|
||||||
case oNOT:
|
case NOT:
|
||||||
require(1)
|
require(1)
|
||||||
x := stack.Pop()
|
x := stack.Pop()
|
||||||
if x.Cmp(ethutil.BigFalse) == 0 {
|
if x.Cmp(ethutil.BigFalse) == 0 {
|
||||||
@ -277,7 +275,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x10 range
|
// 0x10 range
|
||||||
case oAND:
|
case AND:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) {
|
if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) {
|
||||||
@ -286,7 +284,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
}
|
}
|
||||||
|
|
||||||
case oOR:
|
case OR:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) {
|
if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) {
|
||||||
@ -294,11 +292,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
} else {
|
} else {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
}
|
}
|
||||||
case oXOR:
|
case XOR:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
stack.Push(base.Xor(x, y))
|
stack.Push(base.Xor(x, y))
|
||||||
case oBYTE:
|
case BYTE:
|
||||||
require(2)
|
require(2)
|
||||||
val, th := stack.Popn()
|
val, th := stack.Popn()
|
||||||
if th.Cmp(big.NewInt(32)) < 0 {
|
if th.Cmp(big.NewInt(32)) < 0 {
|
||||||
@ -308,92 +306,92 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x20 range
|
// 0x20 range
|
||||||
case oSHA3:
|
case SHA3:
|
||||||
require(2)
|
require(2)
|
||||||
size, offset := stack.Popn()
|
size, offset := stack.Popn()
|
||||||
data := mem.Get(offset.Int64(), size.Int64())
|
data := mem.Get(offset.Int64(), size.Int64())
|
||||||
|
|
||||||
stack.Push(ethutil.BigD(data))
|
stack.Push(ethutil.BigD(data))
|
||||||
// 0x30 range
|
// 0x30 range
|
||||||
case oADDRESS:
|
case ADDRESS:
|
||||||
stack.Push(ethutil.BigD(closure.Object().Address()))
|
stack.Push(ethutil.BigD(closure.Object().Address()))
|
||||||
case oBALANCE:
|
case BALANCE:
|
||||||
stack.Push(closure.object.Amount)
|
stack.Push(closure.object.Amount)
|
||||||
case oORIGIN:
|
case ORIGIN:
|
||||||
stack.Push(ethutil.BigD(vm.vars.Origin))
|
stack.Push(ethutil.BigD(vm.vars.Origin))
|
||||||
case oCALLER:
|
case CALLER:
|
||||||
stack.Push(ethutil.BigD(closure.Callee().Address()))
|
stack.Push(ethutil.BigD(closure.Callee().Address()))
|
||||||
case oCALLVALUE:
|
case CALLVALUE:
|
||||||
stack.Push(vm.vars.Value)
|
stack.Push(vm.vars.Value)
|
||||||
case oCALLDATALOAD:
|
case CALLDATALOAD:
|
||||||
require(1)
|
require(1)
|
||||||
offset := stack.Pop().Int64()
|
offset := stack.Pop().Int64()
|
||||||
val := closure.Args[offset : offset+32]
|
val := closure.Args[offset : offset+32]
|
||||||
|
|
||||||
stack.Push(ethutil.BigD(val))
|
stack.Push(ethutil.BigD(val))
|
||||||
case oCALLDATASIZE:
|
case CALLDATASIZE:
|
||||||
stack.Push(big.NewInt(int64(len(closure.Args))))
|
stack.Push(big.NewInt(int64(len(closure.Args))))
|
||||||
case oGASPRICE:
|
case GASPRICE:
|
||||||
stack.Push(closure.Price)
|
stack.Push(closure.Price)
|
||||||
|
|
||||||
// 0x40 range
|
// 0x40 range
|
||||||
case oPREVHASH:
|
case PREVHASH:
|
||||||
stack.Push(ethutil.BigD(vm.vars.PrevHash))
|
stack.Push(ethutil.BigD(vm.vars.PrevHash))
|
||||||
case oCOINBASE:
|
case COINBASE:
|
||||||
stack.Push(ethutil.BigD(vm.vars.Coinbase))
|
stack.Push(ethutil.BigD(vm.vars.Coinbase))
|
||||||
case oTIMESTAMP:
|
case TIMESTAMP:
|
||||||
stack.Push(big.NewInt(vm.vars.Time))
|
stack.Push(big.NewInt(vm.vars.Time))
|
||||||
case oNUMBER:
|
case NUMBER:
|
||||||
stack.Push(big.NewInt(int64(vm.vars.BlockNumber)))
|
stack.Push(big.NewInt(int64(vm.vars.BlockNumber)))
|
||||||
case oDIFFICULTY:
|
case DIFFICULTY:
|
||||||
stack.Push(vm.vars.Diff)
|
stack.Push(vm.vars.Diff)
|
||||||
case oGASLIMIT:
|
case GASLIMIT:
|
||||||
// TODO
|
// TODO
|
||||||
stack.Push(big.NewInt(0))
|
stack.Push(big.NewInt(0))
|
||||||
|
|
||||||
// 0x50 range
|
// 0x50 range
|
||||||
case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32:
|
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
||||||
a := big.NewInt(int64(op) - int64(oPUSH1) + 1)
|
a := big.NewInt(int64(op) - int64(PUSH1) + 1)
|
||||||
pc.Add(pc, ethutil.Big1)
|
pc.Add(pc, ethutil.Big1)
|
||||||
data := closure.Gets(pc, a)
|
data := closure.Gets(pc, a)
|
||||||
val := ethutil.BigD(data.Bytes())
|
val := ethutil.BigD(data.Bytes())
|
||||||
// Push value to stack
|
// Push value to stack
|
||||||
stack.Push(val)
|
stack.Push(val)
|
||||||
pc.Add(pc, a.Sub(a, big.NewInt(1)))
|
pc.Add(pc, a.Sub(a, big.NewInt(1)))
|
||||||
step++
|
|
||||||
|
|
||||||
case oPOP:
|
step += int(op) - int(PUSH1) + 1
|
||||||
|
case POP:
|
||||||
require(1)
|
require(1)
|
||||||
stack.Pop()
|
stack.Pop()
|
||||||
case oDUP:
|
case DUP:
|
||||||
require(1)
|
require(1)
|
||||||
stack.Push(stack.Peek())
|
stack.Push(stack.Peek())
|
||||||
case oSWAP:
|
case SWAP:
|
||||||
require(2)
|
require(2)
|
||||||
x, y := stack.Popn()
|
x, y := stack.Popn()
|
||||||
stack.Push(y)
|
stack.Push(y)
|
||||||
stack.Push(x)
|
stack.Push(x)
|
||||||
case oMLOAD:
|
case MLOAD:
|
||||||
require(1)
|
require(1)
|
||||||
offset := stack.Pop()
|
offset := stack.Pop()
|
||||||
stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32)))
|
stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32)))
|
||||||
case oMSTORE: // Store the value at stack top-1 in to memory at location stack top
|
case MSTORE: // Store the value at stack top-1 in to memory at location stack top
|
||||||
require(2)
|
require(2)
|
||||||
// Pop value of the stack
|
// Pop value of the stack
|
||||||
val, mStart := stack.Popn()
|
val, mStart := stack.Popn()
|
||||||
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256))
|
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256))
|
||||||
case oMSTORE8:
|
case MSTORE8:
|
||||||
require(2)
|
require(2)
|
||||||
val, mStart := stack.Popn()
|
val, mStart := stack.Popn()
|
||||||
base.And(val, new(big.Int).SetInt64(0xff))
|
base.And(val, new(big.Int).SetInt64(0xff))
|
||||||
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
|
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
|
||||||
case oSLOAD:
|
case SLOAD:
|
||||||
require(1)
|
require(1)
|
||||||
loc := stack.Pop()
|
loc := stack.Pop()
|
||||||
val := closure.GetMem(loc)
|
val := closure.GetMem(loc)
|
||||||
//fmt.Println("get", val.BigInt(), "@", loc)
|
//fmt.Println("get", val.BigInt(), "@", loc)
|
||||||
stack.Push(val.BigInt())
|
stack.Push(val.BigInt())
|
||||||
case oSSTORE:
|
case SSTORE:
|
||||||
require(2)
|
require(2)
|
||||||
val, loc := stack.Popn()
|
val, loc := stack.Popn()
|
||||||
//fmt.Println("storing", val, "@", loc)
|
//fmt.Println("storing", val, "@", loc)
|
||||||
@ -401,13 +399,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
|
|
||||||
// Add the change to manifest
|
// Add the change to manifest
|
||||||
vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val)
|
vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val)
|
||||||
case oJUMP:
|
case JUMP:
|
||||||
require(1)
|
require(1)
|
||||||
pc = stack.Pop()
|
pc = stack.Pop()
|
||||||
// Reduce pc by one because of the increment that's at the end of this for loop
|
// Reduce pc by one because of the increment that's at the end of this for loop
|
||||||
//pc.Sub(pc, ethutil.Big1)
|
//pc.Sub(pc, ethutil.Big1)
|
||||||
continue
|
continue
|
||||||
case oJUMPI:
|
case JUMPI:
|
||||||
require(2)
|
require(2)
|
||||||
cond, pos := stack.Popn()
|
cond, pos := stack.Popn()
|
||||||
if cond.Cmp(ethutil.BigTrue) == 0 {
|
if cond.Cmp(ethutil.BigTrue) == 0 {
|
||||||
@ -415,12 +413,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
//pc.Sub(pc, ethutil.Big1)
|
//pc.Sub(pc, ethutil.Big1)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case oPC:
|
case PC:
|
||||||
stack.Push(pc)
|
stack.Push(pc)
|
||||||
case oMSIZE:
|
case MSIZE:
|
||||||
stack.Push(big.NewInt(int64(mem.Len())))
|
stack.Push(big.NewInt(int64(mem.Len())))
|
||||||
// 0x60 range
|
// 0x60 range
|
||||||
case oCREATE:
|
case CREATE:
|
||||||
require(3)
|
require(3)
|
||||||
|
|
||||||
value := stack.Pop()
|
value := stack.Pop()
|
||||||
@ -439,9 +437,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
// Transfer all remaining gas to the new
|
// Transfer all remaining gas to the new
|
||||||
// contract so it may run the init script
|
// contract so it may run the init script
|
||||||
gas := new(big.Int).Set(closure.Gas)
|
gas := new(big.Int).Set(closure.Gas)
|
||||||
closure.Gas.Sub(closure.Gas, gas)
|
closure.UseGas(gas)
|
||||||
|
|
||||||
// Create the closure
|
// Create the closure
|
||||||
closure := NewClosure(closure.callee,
|
c := NewClosure(closure.callee,
|
||||||
closure.Object(),
|
closure.Object(),
|
||||||
contract.initScript,
|
contract.initScript,
|
||||||
vm.state,
|
vm.state,
|
||||||
@ -449,7 +448,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
closure.Price)
|
closure.Price)
|
||||||
// Call the closure and set the return value as
|
// Call the closure and set the return value as
|
||||||
// main script.
|
// main script.
|
||||||
closure.Script, err = closure.Call(vm, nil, hook)
|
c.Script, gas, err = c.Call(vm, nil, hook)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
|
|
||||||
@ -460,7 +460,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
|
|
||||||
vm.state.UpdateStateObject(contract)
|
vm.state.UpdateStateObject(contract)
|
||||||
}
|
}
|
||||||
case oCALL:
|
case CALL:
|
||||||
require(7)
|
require(7)
|
||||||
// Closure addr
|
// Closure addr
|
||||||
addr := stack.Pop()
|
addr := stack.Pop()
|
||||||
@ -492,7 +492,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
// Copy
|
// Copy
|
||||||
gas = new(big.Int).Set(closure.Gas)
|
gas = new(big.Int).Set(closure.Gas)
|
||||||
}
|
}
|
||||||
closure.Gas.Sub(closure.Gas, gas)
|
closure.UseGas(gas)
|
||||||
|
|
||||||
// Add the value to the state object
|
// Add the value to the state object
|
||||||
contract.AddAmount(value)
|
contract.AddAmount(value)
|
||||||
@ -500,7 +500,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
// Create a new callable closure
|
// Create a new callable closure
|
||||||
closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price)
|
closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price)
|
||||||
// Executer the closure and get the return value (if any)
|
// Executer the closure and get the return value (if any)
|
||||||
ret, err := closure.Call(vm, args, hook)
|
ret, _, err := closure.Call(vm, args, hook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
// Reset the changes applied this object
|
// Reset the changes applied this object
|
||||||
@ -516,13 +516,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes())
|
ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes())
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
}
|
}
|
||||||
case oRETURN:
|
case RETURN:
|
||||||
require(2)
|
require(2)
|
||||||
size, offset := stack.Popn()
|
size, offset := stack.Popn()
|
||||||
ret := mem.Get(offset.Int64(), size.Int64())
|
ret := mem.Get(offset.Int64(), size.Int64())
|
||||||
|
|
||||||
return closure.Return(ret), nil
|
return closure.Return(ret), nil
|
||||||
case oSUICIDE:
|
case SUICIDE:
|
||||||
require(1)
|
require(1)
|
||||||
|
|
||||||
receiver := vm.state.GetAccount(stack.Pop().Bytes())
|
receiver := vm.state.GetAccount(stack.Pop().Bytes())
|
||||||
@ -532,7 +532,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
closure.object.state.Purge()
|
closure.object.state.Purge()
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case oSTOP: // Stop the closure
|
case STOP: // Stop the closure
|
||||||
return closure.Return(nil), nil
|
return closure.Return(nil), nil
|
||||||
default:
|
default:
|
||||||
ethutil.Config.Log.Debugf("Invalid opcode %x\n", op)
|
ethutil.Config.Log.Debugf("Invalid opcode %x\n", op)
|
||||||
@ -543,7 +543,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
|||||||
pc.Add(pc, ethutil.Big1)
|
pc.Add(pc, ethutil.Big1)
|
||||||
|
|
||||||
if hook != nil {
|
if hook != nil {
|
||||||
if !hook(step-1, op, mem, stack, closure.Object()) {
|
if !hook(prevStep, op, mem, stack, closure.Object()) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/ethereum/eth-go/ethchain"
|
"github.com/ethereum/eth-go/ethchain"
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
"github.com/ethereum/eth-go/ethwire"
|
"github.com/ethereum/eth-go/ethwire"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Miner struct {
|
type Miner struct {
|
||||||
@ -12,7 +13,7 @@ type Miner struct {
|
|||||||
ethereum ethchain.EthManager
|
ethereum ethchain.EthManager
|
||||||
coinbase []byte
|
coinbase []byte
|
||||||
reactChan chan ethutil.React
|
reactChan chan ethutil.React
|
||||||
txs []*ethchain.Transaction
|
txs ethchain.Transactions
|
||||||
uncles []*ethchain.Block
|
uncles []*ethchain.Block
|
||||||
block *ethchain.Block
|
block *ethchain.Block
|
||||||
powChan chan []byte
|
powChan chan []byte
|
||||||
@ -132,6 +133,8 @@ func (self *Miner) mineNewBlock() {
|
|||||||
self.block.SetUncles(self.uncles)
|
self.block.SetUncles(self.uncles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort the transactions by nonce in case of odd network propagation
|
||||||
|
sort.Sort(ethchain.TxByNonce{self.txs})
|
||||||
// Accumulate all valid transaction and apply them to the new state
|
// Accumulate all valid transaction and apply them to the new state
|
||||||
receipts, txs := stateManager.ApplyTransactions(self.block.State(), self.block, self.txs)
|
receipts, txs := stateManager.ApplyTransactions(self.block.State(), self.block, self.txs)
|
||||||
self.txs = txs
|
self.txs = txs
|
||||||
|
@ -57,25 +57,33 @@ func (self *PBlock) GetTransaction(hash string) *PTx {
|
|||||||
type PTx struct {
|
type PTx struct {
|
||||||
ref *ethchain.Transaction
|
ref *ethchain.Transaction
|
||||||
|
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Gas string `json:"gas"`
|
Gas string `json:"gas"`
|
||||||
GasPrice string `json:"gasPrice"`
|
GasPrice string `json:"gasPrice"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Sender string `json:"sender"`
|
Sender string `json:"sender"`
|
||||||
Data string `json:"data"`
|
RawData string `json:"rawData"`
|
||||||
Contract bool `json:"isContract"`
|
Data string `json:"data"`
|
||||||
|
Contract bool `json:"isContract"`
|
||||||
|
CreatesContract bool `json:"createsContract"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPTx(tx *ethchain.Transaction) *PTx {
|
func NewPTx(tx *ethchain.Transaction) *PTx {
|
||||||
hash := hex.EncodeToString(tx.Hash())
|
hash := hex.EncodeToString(tx.Hash())
|
||||||
receiver := hex.EncodeToString(tx.Recipient)
|
receiver := hex.EncodeToString(tx.Recipient)
|
||||||
|
|
||||||
|
if receiver == "" {
|
||||||
|
receiver = hex.EncodeToString(tx.CreationAddress())
|
||||||
|
}
|
||||||
sender := hex.EncodeToString(tx.Sender())
|
sender := hex.EncodeToString(tx.Sender())
|
||||||
|
createsContract := tx.CreatesContract()
|
||||||
|
|
||||||
data := strings.Join(ethchain.Disassemble(tx.Data), "\n")
|
data := strings.Join(ethchain.Disassemble(tx.Data), "\n")
|
||||||
|
|
||||||
isContract := len(tx.Data) > 0
|
isContract := len(tx.Data) > 0
|
||||||
|
|
||||||
return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: isContract, Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender}
|
return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: isContract, Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: hex.EncodeToString(tx.Data)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PTx) ToString() string {
|
func (self *PTx) ToString() string {
|
||||||
|
@ -88,3 +88,13 @@ func IsHex(str string) bool {
|
|||||||
l := len(str)
|
l := len(str)
|
||||||
return l >= 4 && l%2 == 0 && str[0:2] == "0x"
|
return l >= 4 && l%2 == 0 && str[0:2] == "0x"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) {
|
||||||
|
if len(str) > 1 && str[0:2] == "0x" {
|
||||||
|
ret = FromHex(str[2:])
|
||||||
|
} else {
|
||||||
|
ret = cb(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -43,7 +43,7 @@ func ReadConfig(base string, logTypes LoggerType, id string) *config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC10"}
|
Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"}
|
||||||
Config.Identifier = id
|
Config.Identifier = id
|
||||||
Config.Log = NewLogger(logTypes, LogLevelDebug)
|
Config.Log = NewLogger(logTypes, LogLevelDebug)
|
||||||
Config.SetClientString("/Ethereum(G)")
|
Config.SetClientString("/Ethereum(G)")
|
||||||
|
Loading…
Reference in New Issue
Block a user