mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-25 10:41:41 +00:00
Fix returning prematurely within if(runCall){...}.
Renames
This commit is contained in:
@ -39,11 +39,11 @@ func Call(fromAddress, toAddress, data []byte) (*ctypes.ResponseCall, error) {
|
|||||||
BlockHeight: int64(st.LastBlockHeight),
|
BlockHeight: int64(st.LastBlockHeight),
|
||||||
BlockHash: LeftPadWord256(st.LastBlockHash),
|
BlockHash: LeftPadWord256(st.LastBlockHash),
|
||||||
BlockTime: st.LastBlockTime.Unix(),
|
BlockTime: st.LastBlockTime.Unix(),
|
||||||
GasLimit: 10000000,
|
GasLimit: st.GetGasLimit(),
|
||||||
}
|
}
|
||||||
|
|
||||||
vmach := vm.NewVM(txCache, params, caller.Address, nil)
|
vmach := vm.NewVM(txCache, params, caller.Address, nil)
|
||||||
gas := int64(1000000000)
|
gas := st.GetGasLimit()
|
||||||
ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas)
|
ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -64,11 +64,11 @@ func CallCode(fromAddress, code, data []byte) (*ctypes.ResponseCall, error) {
|
|||||||
BlockHeight: int64(st.LastBlockHeight),
|
BlockHeight: int64(st.LastBlockHeight),
|
||||||
BlockHash: LeftPadWord256(st.LastBlockHash),
|
BlockHash: LeftPadWord256(st.LastBlockHash),
|
||||||
BlockTime: st.LastBlockTime.Unix(),
|
BlockTime: st.LastBlockTime.Unix(),
|
||||||
GasLimit: 10000000,
|
GasLimit: st.GetGasLimit(),
|
||||||
}
|
}
|
||||||
|
|
||||||
vmach := vm.NewVM(txCache, params, caller.Address, nil)
|
vmach := vm.NewVM(txCache, params, caller.Address, nil)
|
||||||
gas := int64(1000000000)
|
gas := st.GetGasLimit()
|
||||||
ret, err := vmach.Call(caller, callee, code, data, 0, &gas)
|
ret, err := vmach.Call(caller, callee, code, data, 0, &gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -356,10 +356,10 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
return types.ErrTxInvalidAddress
|
return types.ErrTxInvalidAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
createAccount := len(tx.Address) == 0
|
createContract := len(tx.Address) == 0
|
||||||
if createAccount {
|
if createContract {
|
||||||
if !hasCreateContractPermission(blockCache, inAcc) {
|
if !hasCreateContractPermission(blockCache, inAcc) {
|
||||||
return fmt.Errorf("Account %X does not have Create permission", tx.Input.Address)
|
return fmt.Errorf("Account %X does not have CreateContract permission", tx.Input.Address)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !hasCallPermission(blockCache, inAcc) {
|
if !hasCallPermission(blockCache, inAcc) {
|
||||||
@ -383,13 +383,18 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
return types.ErrTxInsufficientFunds
|
return types.ErrTxInsufficientFunds
|
||||||
}
|
}
|
||||||
|
|
||||||
if !createAccount {
|
if !createContract {
|
||||||
// Validate output
|
// Validate output
|
||||||
if len(tx.Address) != 20 {
|
if len(tx.Address) != 20 {
|
||||||
log.Info(Fmt("Destination address is not 20 bytes %X", tx.Address))
|
log.Info(Fmt("Destination address is not 20 bytes %X", tx.Address))
|
||||||
return types.ErrTxInvalidAddress
|
return types.ErrTxInvalidAddress
|
||||||
}
|
}
|
||||||
// this may be nil if we are still in mempool and contract was created in same block as this tx
|
// check if its a native contract
|
||||||
|
if vm.RegisteredNativeContract(LeftPadWord256(tx.Address)) {
|
||||||
|
return fmt.Errorf("NativeContracts can not be called using CallTx. Use a contract or the appropriate tx type (eg. PermissionsTx, NameTx)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output account may be nil if we are still in mempool and contract was created in same block as this tx
|
||||||
// but that's fine, because the account will be created properly when the create tx runs in the block
|
// but that's fine, because the account will be created properly when the create tx runs in the block
|
||||||
// and then this won't return nil. otherwise, we take their fee
|
// and then this won't return nil. otherwise, we take their fee
|
||||||
outAcc = blockCache.GetAccount(tx.Address)
|
outAcc = blockCache.GetAccount(tx.Address)
|
||||||
@ -400,90 +405,101 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
// Good!
|
// Good!
|
||||||
value := tx.Input.Amount - tx.Fee
|
value := tx.Input.Amount - tx.Fee
|
||||||
inAcc.Sequence += 1
|
inAcc.Sequence += 1
|
||||||
|
inAcc.Balance -= tx.Fee
|
||||||
|
blockCache.UpdateAccount(inAcc)
|
||||||
|
|
||||||
|
// The logic in runCall MUST NOT return.
|
||||||
if runCall {
|
if runCall {
|
||||||
|
|
||||||
|
// VM call variables
|
||||||
var (
|
var (
|
||||||
gas int64 = tx.GasLimit
|
gas int64 = tx.GasLimit
|
||||||
err error = nil
|
err error = nil
|
||||||
caller *vm.Account = toVMAccount(inAcc)
|
caller *vm.Account = toVMAccount(inAcc)
|
||||||
callee *vm.Account = nil
|
callee *vm.Account = nil // initialized below
|
||||||
code []byte = nil
|
code []byte = nil
|
||||||
|
ret []byte = nil
|
||||||
txCache = NewTxCache(blockCache)
|
txCache = NewTxCache(blockCache)
|
||||||
params = vm.Params{
|
params = vm.Params{
|
||||||
BlockHeight: int64(_s.LastBlockHeight),
|
BlockHeight: int64(_s.LastBlockHeight),
|
||||||
BlockHash: LeftPadWord256(_s.LastBlockHash),
|
BlockHash: LeftPadWord256(_s.LastBlockHash),
|
||||||
BlockTime: _s.LastBlockTime.Unix(),
|
BlockTime: _s.LastBlockTime.Unix(),
|
||||||
GasLimit: 10000000,
|
GasLimit: _s.GetGasLimit(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// get or create callee
|
if !createContract && (outAcc == nil || len(outAcc.Code) == 0) {
|
||||||
if !createAccount {
|
// if you call an account that doesn't exist
|
||||||
|
// or an account with no code then we take fees (sorry pal)
|
||||||
if outAcc == nil || len(outAcc.Code) == 0 {
|
// NOTE: it's fine to create a contract and call it within one
|
||||||
// check if its a native contract
|
// block (nonce will prevent re-ordering of those txs)
|
||||||
if vm.RegisteredNativeContract(LeftPadWord256(tx.Address)) {
|
// but to create with one contract and call with another
|
||||||
return fmt.Errorf("NativeContracts can not be called using CallTx. Use a contract or the appropriate tx type (eg. PermissionsTx, NameTx)")
|
// you have to wait a block to avoid a re-ordering attack
|
||||||
}
|
// that will take your fees
|
||||||
|
if outAcc == nil {
|
||||||
// if you call an account that doesn't exist
|
log.Info(Fmt("%X tries to call %X but it does not exist.",
|
||||||
// or an account with no code then we take fees (sorry pal)
|
inAcc.Address, tx.Address))
|
||||||
// NOTE: it's fine to create a contract and call it within one
|
} else {
|
||||||
// block (nonce will prevent re-ordering of those txs)
|
log.Info(Fmt("%X tries to call %X but code is blank.",
|
||||||
// but to create with one account and call with another
|
inAcc.Address, tx.Address))
|
||||||
// you have to wait a block to avoid a re-ordering attack
|
}
|
||||||
// that will take your fees
|
err = types.ErrTxInvalidAddress
|
||||||
inAcc.Balance -= tx.Fee
|
goto CALL_COMPLETE
|
||||||
blockCache.UpdateAccount(inAcc)
|
}
|
||||||
if outAcc == nil {
|
|
||||||
log.Info(Fmt("Cannot find destination address %X. Deducting fee from caller", tx.Address))
|
// get or create callee
|
||||||
} else {
|
if createContract {
|
||||||
log.Info(Fmt("Attempting to call an account (%X) with no code. Deducting fee from caller", tx.Address))
|
if HasPermission(blockCache, inAcc, ptypes.CreateContract) {
|
||||||
}
|
callee = txCache.CreateAccount(caller)
|
||||||
return types.ErrTxInvalidAddress
|
log.Info(Fmt("Created new contract %X", callee.Address))
|
||||||
|
code = tx.Data
|
||||||
|
} else {
|
||||||
|
log.Info(Fmt("Error on execution: Caller %X cannot create contract",
|
||||||
|
caller.Address))
|
||||||
|
err = types.ErrTxPermissionDenied
|
||||||
|
goto CALL_COMPLETE
|
||||||
}
|
}
|
||||||
callee = toVMAccount(outAcc)
|
|
||||||
code = callee.Code
|
|
||||||
log.Info(Fmt("Calling contract %X with code %X", callee.Address, callee.Code))
|
|
||||||
} else {
|
} else {
|
||||||
callee = txCache.CreateAccount(caller)
|
callee = toVMAccount(outAcc)
|
||||||
log.Info(Fmt("Created new account %X", callee.Address))
|
log.Info(Fmt("Calling contract %X with code %X", callee.Address, callee.Code))
|
||||||
code = tx.Data
|
code = callee.Code
|
||||||
}
|
}
|
||||||
log.Info(Fmt("Code for this contract: %X", code))
|
log.Info(Fmt("Code for this contract: %X", code))
|
||||||
|
|
||||||
txCache.UpdateAccount(caller) // because we bumped nonce
|
// Run VM call and sync txCache to blockCache.
|
||||||
txCache.UpdateAccount(callee) // so the txCache knows about the callee and the create and/or transfer takes effect
|
{ // Capture scope for goto.
|
||||||
|
// Write caller/callee to txCache.
|
||||||
vmach := vm.NewVM(txCache, params, caller.Address, types.TxID(_s.ChainID, tx))
|
txCache.UpdateAccount(caller)
|
||||||
vmach.SetFireable(evc)
|
txCache.UpdateAccount(callee)
|
||||||
|
vmach := vm.NewVM(txCache, params, caller.Address, types.TxID(_s.ChainID, tx))
|
||||||
// NOTE: Call() transfers the value from caller to callee iff call succeeds.
|
vmach.SetFireable(evc)
|
||||||
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
|
// NOTE: Call() transfers the value from caller to callee iff call succeeds.
|
||||||
exception := ""
|
ret, err = vmach.Call(caller, callee, code, tx.Data, value, &gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exception = err.Error()
|
// Failure. Charge the gas fee. The 'value' was otherwise not transferred.
|
||||||
// Failure. Charge the gas fee. The 'value' was otherwise not transferred.
|
log.Info(Fmt("Error on execution: %v", err))
|
||||||
log.Info(Fmt("Error on execution: %v", err))
|
goto CALL_COMPLETE
|
||||||
inAcc.Balance -= tx.Fee
|
|
||||||
blockCache.UpdateAccount(inAcc)
|
|
||||||
// Throw away 'txCache' which holds incomplete updates (don't sync it).
|
|
||||||
} else {
|
|
||||||
log.Info("Successful execution")
|
|
||||||
// Success
|
|
||||||
if createAccount {
|
|
||||||
callee.Code = ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info("Successful execution")
|
||||||
|
if createContract {
|
||||||
|
callee.Code = ret
|
||||||
|
}
|
||||||
txCache.Sync()
|
txCache.Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CALL_COMPLETE: // err may or may not be nil.
|
||||||
|
|
||||||
// Create a receipt from the ret and whether errored.
|
// Create a receipt from the ret and whether errored.
|
||||||
log.Notice("VM call complete", "caller", caller, "callee", callee, "return", ret, "err", err)
|
log.Notice("VM call complete", "caller", caller, "callee", callee, "return", ret, "err", err)
|
||||||
|
|
||||||
// Fire Events for sender and receiver
|
// Fire Events for sender and receiver
|
||||||
// a separate event will be fired from vm for each additional call
|
// a separate event will be fired from vm for each additional call
|
||||||
if evc != nil {
|
if evc != nil {
|
||||||
|
exception := ""
|
||||||
|
if err != nil {
|
||||||
|
exception = err.Error()
|
||||||
|
}
|
||||||
evc.FireEvent(types.EventStringAccInput(tx.Input.Address), types.EventMsgCallTx{tx, ret, exception})
|
evc.FireEvent(types.EventStringAccInput(tx.Input.Address), types.EventMsgCallTx{tx, ret, exception})
|
||||||
evc.FireEvent(types.EventStringAccOutput(tx.Address), types.EventMsgCallTx{tx, ret, exception})
|
evc.FireEvent(types.EventStringAccOutput(tx.Address), types.EventMsgCallTx{tx, ret, exception})
|
||||||
}
|
}
|
||||||
@ -493,7 +509,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
// So mempool will skip the actual .Call(),
|
// So mempool will skip the actual .Call(),
|
||||||
// and only deduct from the caller's balance.
|
// and only deduct from the caller's balance.
|
||||||
inAcc.Balance -= value
|
inAcc.Balance -= value
|
||||||
if createAccount {
|
if createContract {
|
||||||
inAcc.Sequence += 1
|
inAcc.Sequence += 1
|
||||||
}
|
}
|
||||||
blockCache.UpdateAccount(inAcc)
|
blockCache.UpdateAccount(inAcc)
|
||||||
@ -556,7 +572,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
|
|||||||
// ensure we are owner
|
// ensure we are owner
|
||||||
if bytes.Compare(entry.Owner, tx.Input.Address) != 0 {
|
if bytes.Compare(entry.Owner, tx.Input.Address) != 0 {
|
||||||
log.Info(Fmt("Sender %X is trying to update a name (%s) for which he is not owner", tx.Input.Address, tx.Name))
|
log.Info(Fmt("Sender %X is trying to update a name (%s) for which he is not owner", tx.Input.Address, tx.Name))
|
||||||
return types.ErrIncorrectOwner
|
return types.ErrTxPermissionDenied
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
expired = true
|
expired = true
|
||||||
|
@ -147,6 +147,14 @@ func (s *State) SetDB(db dbm.DB) {
|
|||||||
s.DB = db
|
s.DB = db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
// State.params
|
||||||
|
|
||||||
|
func (s *State) GetGasLimit() int64 {
|
||||||
|
return 1000000 // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// State.params
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
// State.accounts
|
// State.accounts
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ var (
|
|||||||
ErrTxInvalidPubKey = errors.New("Error invalid pubkey")
|
ErrTxInvalidPubKey = errors.New("Error invalid pubkey")
|
||||||
ErrTxInvalidSignature = errors.New("Error invalid signature")
|
ErrTxInvalidSignature = errors.New("Error invalid signature")
|
||||||
ErrTxInvalidString = errors.New("Error invalid string")
|
ErrTxInvalidString = errors.New("Error invalid string")
|
||||||
ErrIncorrectOwner = errors.New("Error incorrect owner")
|
ErrTxPermissionDenied = errors.New("Error permission denied")
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrTxInvalidSequence struct {
|
type ErrTxInvalidSequence struct {
|
||||||
|
@ -5,6 +5,7 @@ const (
|
|||||||
GasGetAccount int64 = 1
|
GasGetAccount int64 = 1
|
||||||
GasStorageUpdate int64 = 1
|
GasStorageUpdate int64 = 1
|
||||||
|
|
||||||
|
GasBaseOp int64 = 0 // TODO: make this 1
|
||||||
GasStackOp int64 = 1
|
GasStackOp int64 = 1
|
||||||
|
|
||||||
GasEcRecover int64 = 1
|
GasEcRecover int64 = 1
|
||||||
|
@ -21,6 +21,9 @@ type Account struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (acc *Account) String() string {
|
func (acc *Account) String() string {
|
||||||
|
if acc == nil {
|
||||||
|
return "nil-VMAccount"
|
||||||
|
}
|
||||||
return Fmt("VMAccount{%X B:%v C:%X N:%v S:%X}",
|
return Fmt("VMAccount{%X B:%v C:%X N:%v S:%X}",
|
||||||
acc.Address, acc.Balance, acc.Code, acc.Nonce, acc.StorageRoot)
|
acc.Address, acc.Balance, acc.Code, acc.Nonce, acc.StorageRoot)
|
||||||
}
|
}
|
||||||
|
59
vm/vm.go
59
vm/vm.go
@ -140,6 +140,18 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to deduct gasToUse from gasLeft. If ok return false, otherwise
|
||||||
|
// set err and return true.
|
||||||
|
func useGasNegative(gasLeft *int64, gasToUse int64, err *error) bool {
|
||||||
|
if *gasLeft >= gasToUse {
|
||||||
|
*gasLeft -= gasToUse
|
||||||
|
return false
|
||||||
|
} else if *err == nil {
|
||||||
|
*err = ErrInsufficientGas
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Just like Call() but does not transfer 'value' or modify the callDepth.
|
// Just like Call() but does not transfer 'value' or modify the callDepth.
|
||||||
func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) {
|
func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) {
|
||||||
dbg.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input)
|
dbg.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input)
|
||||||
@ -148,12 +160,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
pc int64 = 0
|
pc int64 = 0
|
||||||
stack = NewStack(dataStackCapacity, gas, &err)
|
stack = NewStack(dataStackCapacity, gas, &err)
|
||||||
memory = make([]byte, memoryCapacity)
|
memory = make([]byte, memoryCapacity)
|
||||||
ok = false // convenience
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// If there is an error, return
|
|
||||||
if err != nil {
|
// Use BaseOp gas.
|
||||||
|
if useGasNegative(gas, GasBaseOp, &err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,8 +436,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
dbg.Printf(" => 0x%X\n", res)
|
dbg.Printf(" => 0x%X\n", res)
|
||||||
|
|
||||||
case SHA3: // 0x20
|
case SHA3: // 0x20
|
||||||
if ok = useGas(gas, GasSha3); !ok {
|
if useGasNegative(gas, GasSha3, &err) {
|
||||||
return nil, firstErr(err, ErrInsufficientGas)
|
return nil, err
|
||||||
}
|
}
|
||||||
offset, size := stack.Pop64(), stack.Pop64()
|
offset, size := stack.Pop64(), stack.Pop64()
|
||||||
data, ok := subslice(memory, offset, size)
|
data, ok := subslice(memory, offset, size)
|
||||||
@ -442,8 +454,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
|
|
||||||
case BALANCE: // 0x31
|
case BALANCE: // 0x31
|
||||||
addr := stack.Pop()
|
addr := stack.Pop()
|
||||||
if ok = useGas(gas, GasGetAccount); !ok {
|
if useGasNegative(gas, GasGetAccount, &err) {
|
||||||
return nil, firstErr(err, ErrInsufficientGas)
|
return nil, err
|
||||||
}
|
}
|
||||||
acc := vm.appState.GetAccount(addr)
|
acc := vm.appState.GetAccount(addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
@ -520,8 +532,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
|
|
||||||
case EXTCODESIZE: // 0x3B
|
case EXTCODESIZE: // 0x3B
|
||||||
addr := stack.Pop()
|
addr := stack.Pop()
|
||||||
if ok = useGas(gas, GasGetAccount); !ok {
|
if useGasNegative(gas, GasGetAccount, &err) {
|
||||||
return nil, firstErr(err, ErrInsufficientGas)
|
return nil, err
|
||||||
}
|
}
|
||||||
acc := vm.appState.GetAccount(addr)
|
acc := vm.appState.GetAccount(addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
@ -534,8 +546,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
|
|
||||||
case EXTCODECOPY: // 0x3C
|
case EXTCODECOPY: // 0x3C
|
||||||
addr := stack.Pop()
|
addr := stack.Pop()
|
||||||
if ok = useGas(gas, GasGetAccount); !ok {
|
if useGasNegative(gas, GasGetAccount, &err) {
|
||||||
return nil, firstErr(err, ErrInsufficientGas)
|
return nil, err
|
||||||
}
|
}
|
||||||
acc := vm.appState.GetAccount(addr)
|
acc := vm.appState.GetAccount(addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
@ -579,8 +591,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
dbg.Printf(" => %v\n", vm.params.GasLimit)
|
dbg.Printf(" => %v\n", vm.params.GasLimit)
|
||||||
|
|
||||||
case POP: // 0x50
|
case POP: // 0x50
|
||||||
stack.Pop()
|
popped := stack.Pop()
|
||||||
dbg.Printf(" => %v\n", vm.params.GasLimit)
|
dbg.Printf(" => 0x%X\n", popped)
|
||||||
|
|
||||||
case MLOAD: // 0x51
|
case MLOAD: // 0x51
|
||||||
offset := stack.Pop64()
|
offset := stack.Pop64()
|
||||||
@ -616,8 +628,10 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
|
|
||||||
case SSTORE: // 0x55
|
case SSTORE: // 0x55
|
||||||
loc, data := stack.Pop(), stack.Pop()
|
loc, data := stack.Pop(), stack.Pop()
|
||||||
|
if useGasNegative(gas, GasStorageUpdate, &err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
vm.appState.SetStorage(callee.Address, loc, data)
|
vm.appState.SetStorage(callee.Address, loc, data)
|
||||||
useGas(gas, GasStorageUpdate)
|
|
||||||
dbg.Printf(" {0x%X : 0x%X}\n", loc, data)
|
dbg.Printf(" {0x%X : 0x%X}\n", loc, data)
|
||||||
|
|
||||||
case JUMP: // 0x56
|
case JUMP: // 0x56
|
||||||
@ -762,8 +776,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
vm.fireCallEvent(&exception, &ret, callee, &Account{Address: addr}, args, value, gas)
|
vm.fireCallEvent(&exception, &ret, callee, &Account{Address: addr}, args, value, gas)
|
||||||
} else {
|
} else {
|
||||||
// EVM contract
|
// EVM contract
|
||||||
if ok = useGas(gas, GasGetAccount); !ok {
|
if useGasNegative(gas, GasGetAccount, &err) {
|
||||||
return nil, firstErr(err, ErrInsufficientGas)
|
return nil, err
|
||||||
}
|
}
|
||||||
acc := vm.appState.GetAccount(addr)
|
acc := vm.appState.GetAccount(addr)
|
||||||
// since CALL is used also for sending funds,
|
// since CALL is used also for sending funds,
|
||||||
@ -821,8 +835,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
|
|||||||
|
|
||||||
case SUICIDE: // 0xFF
|
case SUICIDE: // 0xFF
|
||||||
addr := stack.Pop()
|
addr := stack.Pop()
|
||||||
if ok = useGas(gas, GasGetAccount); !ok {
|
if useGasNegative(gas, GasGetAccount, &err) {
|
||||||
return nil, firstErr(err, ErrInsufficientGas)
|
return nil, err
|
||||||
}
|
}
|
||||||
// TODO if the receiver is , then make it the fee.
|
// TODO if the receiver is , then make it the fee.
|
||||||
receiver := vm.appState.GetAccount(addr)
|
receiver := vm.appState.GetAccount(addr)
|
||||||
@ -893,15 +907,6 @@ func firstErr(errA, errB error) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func useGas(gas *int64, gasToUse int64) bool {
|
|
||||||
if *gas > gasToUse {
|
|
||||||
*gas -= gasToUse
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func transfer(from, to *Account, amount int64) error {
|
func transfer(from, to *Account, amount int64) error {
|
||||||
if from.Balance < amount {
|
if from.Balance < amount {
|
||||||
return ErrInsufficientBalance
|
return ErrInsufficientBalance
|
||||||
|
Reference in New Issue
Block a user