core/vm: Upgrade EVM-C API to v3

This commit is contained in:
Paweł Bylica 2017-01-26 00:17:31 +01:00
parent 2b5f3f2042
commit fae74919b1
No known key found for this signature in database
GPG key ID: 7A0C037434FE77EF

View file

@ -25,24 +25,26 @@ static struct evm_instance* new_evmjit()
{ {
// Declare exported Go functions. The are ABI compatible with C callbacks // Declare exported Go functions. The are ABI compatible with C callbacks
// but differ by type names and const pointers. // but differ by type names and const pointers.
void query(void*, size_t, int, void*); void queryState(void*, size_t, int, void* addr, void*);
void update(size_t env, int key, void* arg1, void* arg2); void updateState(size_t env, int key, void* addr, void* arg1, void* arg2);
long long call(void* env, int kind, long long gas, void* address, long long call(void* env, int kind, long long gas, void* address,
void* value, void* input, size_t input_size, void* output, void* value, void* input, size_t input_size, void* output,
size_t output_size); size_t output_size);
void getTxCtx(void*, size_t);
void getBlockHash(void*, size_t, long long);
struct evm_factory factory = evmjit_get_factory(); struct evm_factory factory = evmjit_get_factory();
return factory.create((evm_query_fn)query, (evm_update_fn)update, return factory.create((evm_query_state_fn)queryState,
(evm_call_fn)call); (evm_update_state_fn)updateState, (evm_call_fn)call,
(evm_get_tx_context_fn)getTxCtx, (evm_get_block_hash_fn)getBlockHash);
} }
static struct evm_result evm_execute(struct evm_instance* instance, static struct evm_result evm_execute(struct evm_instance* instance,
struct evm_env* env, enum evm_mode mode, struct evm_uint256be code_hash, struct evm_env* env, enum evm_mode mode, struct evm_uint256be code_hash,
uint8_t const* code, size_t code_size, int64_t gas, uint8_t const* input, uint8_t const* code, size_t code_size, struct evm_message msg)
size_t input_size, struct evm_uint256be value)
{ {
return instance->execute(instance, env, mode, code_hash, code, code_size, return instance->execute(instance, env, mode, code_hash, code, code_size,
gas, input, input_size, value); msg);
} }
static void evm_release_result(struct evm_result* result) static void evm_release_result(struct evm_result* result)
@ -116,6 +118,10 @@ func HashToEvmc(hash common.Hash) C.struct_evm_uint256be {
return C.struct_evm_uint256be{bytes: *(*[32]C.uint8_t)(unsafe.Pointer(&hash[0]))} return C.struct_evm_uint256be{bytes: *(*[32]C.uint8_t)(unsafe.Pointer(&hash[0]))}
} }
func AddressToEvmc(addr common.Address) C.struct_evm_uint160be {
return C.struct_evm_uint160be{bytes: *(*[20]C.uint8_t)(unsafe.Pointer(&addr[0]))}
}
func BigToEvmc(i *big.Int) C.struct_evm_uint256be { func BigToEvmc(i *big.Int) C.struct_evm_uint256be {
return HashToEvmc(common.BigToHash(i)) return HashToEvmc(common.BigToHash(i))
} }
@ -139,8 +145,35 @@ func GoByteSlice(data unsafe.Pointer, size C.size_t) []byte {
return *(*[]byte)(unsafe.Pointer(&sliceHeader)) return *(*[]byte)(unsafe.Pointer(&sliceHeader))
} }
//export query //export getTxCtx
func query(pResult unsafe.Pointer, ctxIdx uintptr, key int32, pArg unsafe.Pointer) { func getTxCtx(pResult unsafe.Pointer, ctxIdx uintptr) {
ctx := getCtx(ctxIdx)
txCtx := (*C.struct_evm_tx_context)(pResult)
txCtx.tx_gas_price = BigToEvmc(ctx.env.GasPrice)
txCtx.tx_origin = AddressToEvmc(ctx.env.Origin)
txCtx.block_coinbase = AddressToEvmc(ctx.env.Coinbase)
txCtx.block_number = C.int64_t(ctx.env.BlockNumber.Int64())
txCtx.block_timestamp = C.int64_t(ctx.env.Time.Int64())
txCtx.block_gas_limit = C.int64_t(ctx.env.GasLimit.Int64())
txCtx.block_difficulty = BigToEvmc(ctx.env.Difficulty)
}
//export getBlockHash
func getBlockHash(pResult unsafe.Pointer, ctxIdx uintptr, number int64) {
// Represent the result memory as Go slice of 32 bytes.
result := GoByteSlice(pResult, 32)
ctx := getCtx(ctxIdx)
b := ctx.env.BlockNumber.Int64()
a := b - 256
var hash common.Hash
if number >= a && number < b {
hash = ctx.env.GetHash(uint64(number))
}
copy(result, hash[:])
}
//export queryState
func queryState(pResult unsafe.Pointer, ctxIdx uintptr, key int32, pAddr unsafe.Pointer, pArg unsafe.Pointer) {
// Represent the result memory as Go slice of 32 bytes. // Represent the result memory as Go slice of 32 bytes.
result := GoByteSlice(pResult, 32) result := GoByteSlice(pResult, 32)
// Or as pointer to int64. // Or as pointer to int64.
@ -149,71 +182,29 @@ func query(pResult unsafe.Pointer, ctxIdx uintptr, key int32, pArg unsafe.Pointe
// Get the execution context. // Get the execution context.
ctx := getCtx(ctxIdx) ctx := getCtx(ctxIdx)
var addr common.Address
copy(addr[:], GoByteSlice(pAddr, 20))
switch key { switch key {
case C.EVM_SLOAD: case C.EVM_SLOAD:
arg := *(*[32]byte)(pArg) arg := *(*[32]byte)(pArg)
val := ctx.env.StateDB.GetState(ctx.contract.Address(), arg) val := ctx.env.StateDB.GetState(ctx.contract.Address(), arg)
copy(result, val[:]) copy(result, val[:])
// fmt.Printf("EVMJIT SLOAD %x : %x\n", arg, result)
case C.EVM_ADDRESS:
addr := ctx.contract.Address()
copy(result[12:], addr[:])
case C.EVM_CALLER:
addr := ctx.contract.Caller()
copy(result[12:], addr[:])
case C.EVM_ORIGIN:
copy(result[12:], ctx.env.Origin[:])
case C.EVM_GAS_PRICE:
val := common.BigToHash(ctx.env.GasPrice)
copy(result, val[:])
case C.EVM_COINBASE:
copy(result[12:], ctx.env.Coinbase[:])
case C.EVM_DIFFICULTY:
val := common.BigToHash(ctx.env.Difficulty)
copy(result, val[:])
case C.EVM_GAS_LIMIT:
*pInt64Result = ctx.env.GasLimit.Int64()
case C.EVM_NUMBER:
*pInt64Result = ctx.env.BlockNumber.Int64()
case C.EVM_TIMESTAMP:
*pInt64Result = ctx.env.Time.Int64()
case C.EVM_CODE_BY_ADDRESS: case C.EVM_CODE_BY_ADDRESS:
arg := GoByteSlice(pArg, 32)
var addr common.Address
copy(addr[:], arg[12:])
code := ctx.env.StateDB.GetCode(addr) code := ctx.env.StateDB.GetCode(addr)
pResAsMemRef := (*MemoryRef)(pResult) pResAsMemRef := (*MemoryRef)(pResult)
pResAsMemRef.ptr = ptr(code) pResAsMemRef.ptr = ptr(code)
pResAsMemRef.len = len(code) pResAsMemRef.len = len(code)
// fmt.Printf("EXTCODE %x : %d\n", addr, pResAsMemRef.len) // fmt.Printf("EXTCODE %x : %d\n", addr, pResAsMemRef.len)
case C.EVM_CODE_SIZE: case C.EVM_CODE_SIZE:
arg := GoByteSlice(pArg, 32)
var addr common.Address
copy(addr[:], arg[12:])
pInt64Result := (*int64)(pResult) pInt64Result := (*int64)(pResult)
*pInt64Result = int64(ctx.env.StateDB.GetCodeSize(addr)) *pInt64Result = int64(ctx.env.StateDB.GetCodeSize(addr))
// fmt.Printf("EXTCODESIZE %x : %d\n", addr, *pInt64Result) // fmt.Printf("EXTCODESIZE %x : %d\n", addr, *pInt64Result)
case C.EVM_BALANCE: case C.EVM_BALANCE:
arg := GoByteSlice(pArg, 32)
var addr common.Address
copy(addr[:], arg[12:])
balance := ctx.env.StateDB.GetBalance(addr) balance := ctx.env.StateDB.GetBalance(addr)
val := common.BigToHash(balance) val := common.BigToHash(balance)
copy(result, val[:]) copy(result, val[:])
case C.EVM_BLOCKHASH:
n := *(*int64)(pArg)
b := ctx.env.BlockNumber.Int64()
a := b - 256
var hash common.Hash
if n >= a && n < b {
hash = ctx.env.GetHash(uint64(n))
}
copy(result, hash[:])
// fmt.Printf("BLOCKHASH %x : %x (%d, %d, %d)\n", result, hash, n, a, b)
case C.EVM_ACCOUNT_EXISTS: case C.EVM_ACCOUNT_EXISTS:
arg := GoByteSlice(pArg, 32)
var addr common.Address
copy(addr[:], arg[12:])
eip158 := ctx.env.ChainConfig().IsEIP158(ctx.env.BlockNumber) eip158 := ctx.env.ChainConfig().IsEIP158(ctx.env.BlockNumber)
var exist int64 var exist int64
if eip158 { if eip158 {
@ -224,17 +215,13 @@ func query(pResult unsafe.Pointer, ctxIdx uintptr, key int32, pArg unsafe.Pointe
exist = 1 exist = 1
} }
*pInt64Result = exist *pInt64Result = exist
// fmt.Printf("EXISTS? %x : %v\n", addr, exist)
case C.EVM_CALL_DEPTH:
*pInt64Result = int64(ctx.env.depth - 1)
default: default:
panic(fmt.Sprintf("Unhandled EVM-C query %d\n", key)) panic(fmt.Sprintf("Unhandled EVM-C query %d\n", key))
} }
} }
//export update //export updateState
func update(ctxIdx uintptr, key int32, pArg1 unsafe.Pointer, pArg2 unsafe.Pointer) { func updateState(ctxIdx uintptr, key int32, pAddr unsafe.Pointer, pArg1 unsafe.Pointer, pArg2 unsafe.Pointer) {
ctx := getCtx(ctxIdx) ctx := getCtx(ctxIdx)
switch key { switch key {
@ -404,11 +391,19 @@ func (evm *EVMJIT) Run(contract *Contract, input []byte) (ret []byte, err error)
// fmt.Printf("EVMJIT pre Run (gas %d %d mode: %d, env: %d) %x\n", contract.Gas, gas, mode, env, evm.contract.Address()) // fmt.Printf("EVMJIT pre Run (gas %d %d mode: %d, env: %d) %x\n", contract.Gas, gas, mode, env, evm.contract.Address())
// Create context for this execution. // Create context for this execution.
ctxId := pinCtx(&EVMCContext{contract, evm.env}) ctxIdx := pinCtx(&EVMCContext{contract, evm.env})
r := C.evm_execute(evm.jit, unsafe.Pointer(ctxId), mode, codeHash, codePtr, codeSize, gas, inputPtr, inputLen, value) var msg C.struct_evm_message
msg.address = AddressToEvmc(contract.Address())
msg.sender = AddressToEvmc(contract.Caller())
msg.value = value
msg.input = inputPtr
msg.input_size = inputLen
msg.gas = gas
msg.depth = C.int32_t(evm.env.depth - 1)
r := C.evm_execute(evm.jit, unsafe.Pointer(ctxIdx), mode, codeHash, codePtr, codeSize, msg)
unpinCtx(ctxId) unpinCtx(ctxIdx)
// fmt.Printf("EVMJIT Run %d %d %x\n", r.code, r.gas_left, evm.contract.Address()) // fmt.Printf("EVMJIT Run %d %d %x\n", r.code, r.gas_left, evm.contract.Address())
if r.gas_left > gas { if r.gas_left > gas {