Skip to content

Commit

Permalink
Merge branch 'main' into gregor/update-flow-go-latest
Browse files Browse the repository at this point in the history
  • Loading branch information
devbugging authored Apr 30, 2024
2 parents 34d069a + adc9797 commit 0e245ff
Show file tree
Hide file tree
Showing 10 changed files with 877 additions and 182 deletions.
48 changes: 45 additions & 3 deletions api/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,51 @@ func (api *PullAPI) NewFilter(criteria filters.FilterCriteria) (rpc.ID, error) {
}

// GetFilterLogs returns the logs for the filter with the given id.
// If the filter could not be found an empty array of logs is returned.
func (api *PullAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*gethTypes.Log, error) {
panic("not implemented")
// If the filter could not be found, `nil` is returned.
func (api *PullAPI) GetFilterLogs(
ctx context.Context,
id rpc.ID,
) ([]*gethTypes.Log, error) {
api.mux.Lock()
defer api.mux.Unlock()

filter, ok := api.filters[id]
if !ok {
return nil, errors.Join(
errs.ErrNotFound,
fmt.Errorf("filted by id %s does not exist", id),
)
}

if filter.expired() {
api.UninstallFilter(id)
return nil, errors.Join(
errs.ErrNotFound,
fmt.Errorf("filted by id %s has expired", id),
)
}

logsFilter, ok := filter.(*logsFilter)
if !ok {
return nil, fmt.Errorf("filted by id %s is not a logs filter", id)
}

current, err := api.blocks.LatestEVMHeight()
if err != nil {
return nil, err
}

result, err := api.getLogs(current, logsFilter)
if err != nil {
return nil, err
}

logs, ok := result.([]*gethTypes.Log)
if !ok {
return nil, fmt.Errorf("logs filter returned incorrect type: %T", logs)
}

return logs, nil
}

// GetFilterChanges returns the logs for the filter with the given id since
Expand Down
5 changes: 2 additions & 3 deletions services/requester/cadence/call.cdc
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import EVM

access(all)
fun main(hexEncodedTx: String): String {
fun main(hexEncodedTx: String): EVM.Result {
let account = getAuthAccount<auth(Storage) &Account>(Address(0xCOA))

let coa = account.storage.borrow<&EVM.CadenceOwnedAccount>(
from: /storage/evm
) ?? panic("Could not borrow reference to the COA!")
let txResult = EVM.run(tx: hexEncodedTx.decodeHex(), coinbase: coa.address())

return String.encodeHex(txResult.data)
return EVM.run(tx: hexEncodedTx.decodeHex(), coinbase: coa.address())
}
5 changes: 2 additions & 3 deletions services/requester/cadence/estimate_gas.cdc
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import EVM

access(all)
fun main(hexEncodedTx: String): [UInt64; 2] {
fun main(hexEncodedTx: String): EVM.Result {
let account = getAuthAccount<auth(Storage) &Account>(Address(0xCOA))

let coa = account.storage.borrow<&EVM.CadenceOwnedAccount>(
from: /storage/evm
) ?? panic("Could not borrow reference to the COA!")
let txResult = EVM.run(tx: hexEncodedTx.decodeHex(), coinbase: coa.address())

return [txResult.errorCode, txResult.gasUsed]
return EVM.run(tx: hexEncodedTx.decodeHex(), coinbase: coa.address())
}
39 changes: 19 additions & 20 deletions services/requester/requester.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/onflow/flow-go-sdk"
"github.com/onflow/flow-go-sdk/access"
"github.com/onflow/flow-go-sdk/crypto"
"github.com/onflow/flow-go/fvm/evm/stdlib"
evmTypes "github.com/onflow/flow-go/fvm/evm/types"
"github.com/onflow/flow-go/fvm/systemcontracts"
"github.com/onflow/go-ethereum/common"
Expand Down Expand Up @@ -342,17 +343,22 @@ func (e *EVM) Call(
return nil, fmt.Errorf("failed to execute script: %w", err)
}

output, err := cadenceStringToBytes(scriptResult)
evmResult, err := stdlib.ResultSummaryFromEVMResultValue(scriptResult)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to decode EVM result from call: %w", err)
}
if evmResult.ErrorCode != 0 {
return nil, getErrorForCode(evmResult.ErrorCode)
}

result := evmResult.ReturnedValue

e.logger.Info().
Str("data", fmt.Sprintf("%x", data)).
Str("result", hex.EncodeToString(output)).
Str("result", hex.EncodeToString(result)).
Msg("call executed")

return output, nil
return result, nil
}

func (e *EVM) EstimateGas(ctx context.Context, data []byte) (uint64, error) {
Expand All @@ -365,7 +371,7 @@ func (e *EVM) EstimateGas(ctx context.Context, data []byte) (uint64, error) {
return 0, err
}

value, err := e.client.ExecuteScriptAtLatestBlock(
scriptResult, err := e.client.ExecuteScriptAtLatestBlock(
ctx,
e.replaceAddresses(estimateGasScript),
[]cadence.Value{hexEncodedTx},
Expand All @@ -374,22 +380,15 @@ func (e *EVM) EstimateGas(ctx context.Context, data []byte) (uint64, error) {
return 0, fmt.Errorf("failed to execute script: %w", err)
}

// sanity check, should never occur
// TODO(m-Peter): Consider adding a decoder for EVM.Result struct
// to a Go value/type.
if _, ok := value.(cadence.Array); !ok {
e.logger.Panic().Msg(fmt.Sprintf("failed to convert value to array: %v", value))
evmResult, err := stdlib.ResultSummaryFromEVMResultValue(scriptResult)
if err != nil {
return 0, fmt.Errorf("failed to decode EVM result from gas estimation: %w", err)
}

result := value.(cadence.Array)
errorCode := result.Values[0].ToGoValue().(uint64)

if errorCode != 0 {
return 0, getErrorForCode(errorCode)
if evmResult.ErrorCode != 0 {
return 0, getErrorForCode(evmResult.ErrorCode)
}

gasUsed := result.Values[1].ToGoValue().(uint64)
return gasUsed, nil
return evmResult.GasConsumed, nil
}

func (e *EVM) GetCode(
Expand Down Expand Up @@ -536,8 +535,8 @@ func cadenceStringToBytes(value cadence.Value) ([]byte, error) {
}

// TODO(m-Peter): Consider moving this to flow-go repository
func getErrorForCode(errorCode uint64) error {
switch evmTypes.ErrorCode(errorCode) {
func getErrorForCode(errorCode evmTypes.ErrorCode) error {
switch errorCode {
case evmTypes.ValidationErrCodeGasUintOverflow:
return gethVM.ErrGasUintOverflow
case evmTypes.ValidationErrCodeNonceTooLow:
Expand Down
4 changes: 4 additions & 0 deletions tests/e2e_web3js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ func TestWeb3_E2E(t *testing.T) {
runWeb3Test(t, "eth_logs_filtering_test")
})

t.Run("eth_getFilterLogs", func(t *testing.T) {
runWeb3Test(t, "eth_get_filter_logs_test")
})

t.Run("streaming of entities and subscription", func(t *testing.T) {
runWeb3Test(t, "eth_streaming_test")
})
Expand Down
77 changes: 77 additions & 0 deletions tests/web3js/eth_get_filter_logs_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const { assert } = require('chai')
const conf = require('./config')
const helpers = require('./helpers')
const web3 = conf.web3

it('returns a null result for missing filter', async () => {
// check that null is returned when the filter could not be found.
let response = await helpers.callRPCMethod('eth_getFilterLogs', ['0xffa1'])

assert.equal(200, response.status)
assert.isUndefined(response.body['result'])
})

it('create logs filter and call eth_getFilterLogs', async () => {
// deploy contract
let deployed = await helpers.deployContract('storage')
let contractAddress = deployed.receipt.contractAddress

// create logs filter on the address of the deployed contract
let response = await helpers.callRPCMethod('eth_newFilter', [{ 'address': contractAddress }])

assert.equal(200, response.status)
assert.isDefined(response.body['result'])
let filterID = response.body['result']

// make contract function call that emits a log
let res = await helpers.signAndSend({
from: conf.eoa.address,
to: contractAddress,
data: deployed.contract.methods.sum(15, 20).encodeABI(),
gas: 1000000,
gasPrice: 0
})
assert.equal(res.receipt.status, conf.successStatus)

// check the matching items from the logs filter
response = await helpers.callRPCMethod('eth_getFilterLogs', [filterID])

assert.equal(200, response.status)
assert.equal(1, response.body['result'].length)

let logs = response.body['result']
assert.equal(contractAddress.toLowerCase(), logs[0].address)
assert.lengthOf(logs[0].topics, 4)
assert.equal(
'35',
web3.eth.abi.decodeParameter("int256", logs[0].data)
)

// make contract function call that emits another log
res = await helpers.signAndSend({
from: conf.eoa.address,
to: contractAddress,
data: deployed.contract.methods.sum(30, 20).encodeABI(),
gas: 1000000,
gasPrice: 0
})

assert.equal(res.receipt.status, conf.successStatus)

// check the matching items from the logs filter include both logs
// from the above 2 contract function calls
response = await helpers.callRPCMethod('eth_getFilterLogs', [filterID])

assert.equal(200, response.status)
assert.equal(2, response.body['result'].length)
logs = response.body['result']
console.log()

assert.equal(contractAddress.toLowerCase(), logs[1].address)
assert.lengthOf(logs[1].topics, 4)
assert.equal(
'50',
web3.eth.abi.decodeParameter("int256", logs[1].data)
)

}).timeout(10 * 1000)
Loading

0 comments on commit 0e245ff

Please sign in to comment.