Skip to content

Commit

Permalink
Merge branch 'master' into UlyanaAndrukhiv/6002-exec-data-pruning
Browse files Browse the repository at this point in the history
  • Loading branch information
UlyanaAndrukhiv authored Jun 25, 2024
2 parents fa5fc2e + 3126f9a commit 55fb3fa
Show file tree
Hide file tree
Showing 15 changed files with 326 additions and 31 deletions.
10 changes: 9 additions & 1 deletion engine/execution/block_result.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package execution

import (
"fmt"

"github.com/onflow/flow-go/fvm/storage/snapshot"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module/executiondatasync/execution_data"
Expand Down Expand Up @@ -31,7 +33,7 @@ func (er *BlockExecutionResult) Size() int {
}

func (er *BlockExecutionResult) CollectionExecutionResultAt(colIndex int) *CollectionExecutionResult {
if colIndex < 0 && colIndex > len(er.collectionExecutionResults) {
if colIndex < 0 || colIndex > len(er.collectionExecutionResults) {
return nil
}
return &er.collectionExecutionResults[colIndex]
Expand Down Expand Up @@ -185,6 +187,12 @@ func (ar *BlockAttestationResult) ChunkAt(index int) *flow.Chunk {
execRes := ar.collectionExecutionResults[index]
attestRes := ar.collectionAttestationResults[index]

if execRes.executionSnapshot == nil {
// This should never happen
// In case it does, attach additional information to the error message
panic(fmt.Sprintf("execution snapshot is nil. Block ID: %s, EndState: %s", ar.Block.ID(), attestRes.endStateCommit))
}

return flow.NewChunk(
ar.Block.ID(),
index,
Expand Down
9 changes: 1 addition & 8 deletions fvm/environment/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,17 @@ import (
"github.com/onflow/cadence"
"github.com/onflow/cadence/runtime"
"github.com/rs/zerolog"
otelTrace "go.opentelemetry.io/otel/trace"

reusableRuntime "github.com/onflow/flow-go/fvm/runtime"
"github.com/onflow/flow-go/fvm/tracing"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module/trace"
)

// Environment implements the accounts business logic and exposes cadence
// runtime interface methods for the runtime.
type Environment interface {
runtime.Interface

// Tracer
StartChildSpan(
name trace.SpanName,
options ...otelTrace.SpanStartOption,
) tracing.TracerSpan
Tracer

Meter

Expand Down
16 changes: 16 additions & 0 deletions fvm/environment/tracer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package environment

import (
otelTrace "go.opentelemetry.io/otel/trace"

"github.com/onflow/flow-go/fvm/tracing"
"github.com/onflow/flow-go/module/trace"
)

// Tracer captures traces
type Tracer interface {
StartChildSpan(
name trace.SpanName,
options ...otelTrace.SpanStartOption,
) tracing.TracerSpan
}
10 changes: 10 additions & 0 deletions fvm/evm/backends/wrappedEnv.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import (
"github.com/onflow/cadence"
"github.com/onflow/cadence/runtime"
"github.com/onflow/cadence/runtime/common"
otelTrace "go.opentelemetry.io/otel/trace"

"github.com/onflow/flow-go/fvm/environment"
"github.com/onflow/flow-go/fvm/errors"
"github.com/onflow/flow-go/fvm/evm/types"
"github.com/onflow/flow-go/fvm/meter"
"github.com/onflow/flow-go/fvm/tracing"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module/trace"
)

// WrappedEnvironment wraps an FVM environment
Expand Down Expand Up @@ -144,6 +147,13 @@ func (we *WrappedEnvironment) GenerateUUID() (uint64, error) {
return uuid, handleEnvironmentError(err)
}

func (we *WrappedEnvironment) StartChildSpan(
name trace.SpanName,
options ...otelTrace.SpanStartOption,
) tracing.TracerSpan {
return we.env.StartChildSpan(name, options...)
}

func handleEnvironmentError(err error) error {
if err == nil {
return nil
Expand Down
22 changes: 18 additions & 4 deletions fvm/evm/emulator/emulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,7 @@ func (bl *BlockView) DirectCall(call *types.DirectCall) (*types.Result, error) {
if err != nil {
return nil, err
}
txHash, err := call.Hash()
if err != nil {
return nil, err
}
txHash := call.Hash()
switch call.SubType {
case types.DepositCallSubType:
return proc.mintTo(call, txHash)
Expand Down Expand Up @@ -256,9 +253,21 @@ func (bl *BlockView) DryRunTransaction(
// return without commiting the state
txResult, err := proc.run(msg, tx.Hash(), 0, tx.Type())
if txResult.Successful() {
// As mentioned in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md#specification
// Define "all but one 64th" of N as N - floor(N / 64).
// If a call asks for more gas than the maximum allowed amount
// (i.e. the total amount of gas remaining in the parent after subtracting
// the gas cost of the call and memory expansion), do not return an OOG error;
// instead, if a call asks for more gas than all but one 64th of the maximum
// allowed amount, call with all but one 64th of the maximum allowed amount of
// gas (this is equivalent to a version of EIP-901 plus EIP-1142).
// CREATE only provides all but one 64th of the parent gas to the child call.
txResult.GasConsumed = AddOne64th(txResult.GasConsumed)

// Adding `gethParams.SstoreSentryGasEIP2200` is needed for this condition:
// https://github.com/onflow/go-ethereum/blob/master/core/vm/operations_acl.go#L29-L32
txResult.GasConsumed += gethParams.SstoreSentryGasEIP2200

// Take into account any gas refunds, which are calculated only after
// transaction execution.
txResult.GasConsumed += txResult.GasRefund
Expand Down Expand Up @@ -587,3 +596,8 @@ func (proc *procedure) run(
}
return &res, nil
}

func AddOne64th(n uint64) uint64 {
// NOTE: Go's integer division floors, but that is desirable here
return n + (n / 64)
}
12 changes: 3 additions & 9 deletions fvm/evm/emulator/emulator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ func TestNativeTokenBridging(t *testing.T) {
res, err := blk.DirectCall(call)
require.NoError(t, err)
require.Equal(t, defaultCtx.DirectCallBaseGasUsage, res.GasConsumed)
expectedHash, err := call.Hash()
require.NoError(t, err)
require.Equal(t, expectedHash, res.TxHash)
require.Equal(t, call.Hash(), res.TxHash)
nonce += 1
})
})
Expand Down Expand Up @@ -94,9 +92,7 @@ func TestNativeTokenBridging(t *testing.T) {
res, err := blk.DirectCall(call)
require.NoError(t, err)
require.Equal(t, defaultCtx.DirectCallBaseGasUsage, res.GasConsumed)
expectedHash, err := call.Hash()
require.NoError(t, err)
require.Equal(t, expectedHash, res.TxHash)
require.Equal(t, call.Hash(), res.TxHash)
nonce += 1
})
})
Expand Down Expand Up @@ -155,9 +151,7 @@ func TestContractInteraction(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, res.DeployedContractAddress)
contractAddr = *res.DeployedContractAddress
expectedHash, err := call.Hash()
require.NoError(t, err)
require.Equal(t, expectedHash, res.TxHash)
require.Equal(t, call.Hash(), res.TxHash)
nonce += 1
})
RunWithNewReadOnlyBlockView(t, env, func(blk types.ReadOnlyBlockView) {
Expand Down
10 changes: 7 additions & 3 deletions fvm/evm/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/onflow/flow-go/fvm/crypto"
envMock "github.com/onflow/flow-go/fvm/environment/mock"
"github.com/onflow/flow-go/fvm/evm"
"github.com/onflow/flow-go/fvm/evm/emulator"
"github.com/onflow/flow-go/fvm/evm/stdlib"
"github.com/onflow/flow-go/fvm/evm/testutils"
. "github.com/onflow/flow-go/fvm/evm/testutils"
Expand Down Expand Up @@ -1534,9 +1535,10 @@ func TestDryRun(t *testing.T) {
// Make sure that gas consumed from `EVM.dryRun` is bigger
// than the actual gas consumption of the equivalent
// `EVM.run`.
totalGas := emulator.AddOne64th(res.GasConsumed) + gethParams.SstoreSentryGasEIP2200
require.Equal(
t,
res.GasConsumed+gethParams.SstoreSentryGasEIP2200,
totalGas,
dryRunResult.GasConsumed,
)
})
Expand Down Expand Up @@ -1667,9 +1669,10 @@ func TestDryRun(t *testing.T) {
// Make sure that gas consumed from `EVM.dryRun` is bigger
// than the actual gas consumption of the equivalent
// `EVM.run`.
totalGas := emulator.AddOne64th(res.GasConsumed) + gethParams.SstoreSentryGasEIP2200
require.Equal(
t,
res.GasConsumed+gethParams.SstoreSentryGasEIP2200,
totalGas,
dryRunResult.GasConsumed,
)
})
Expand Down Expand Up @@ -1798,9 +1801,10 @@ func TestDryRun(t *testing.T) {
// Make sure that gas consumed from `EVM.dryRun` is bigger
// than the actual gas consumption of the equivalent
// `EVM.run`.
totalGas := emulator.AddOne64th(res.GasConsumed) + gethParams.SstoreSentryGasEIP2200 + gethParams.SstoreClearsScheduleRefundEIP3529
require.Equal(
t,
res.GasConsumed+gethParams.SstoreSentryGasEIP2200+gethParams.SstoreClearsScheduleRefundEIP3529,
totalGas,
dryRunResult.GasConsumed,
)
})
Expand Down
20 changes: 20 additions & 0 deletions fvm/evm/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import (
"github.com/onflow/cadence/runtime/common"
gethCommon "github.com/onflow/go-ethereum/common"
gethTypes "github.com/onflow/go-ethereum/core/types"
"go.opentelemetry.io/otel/attribute"

"github.com/onflow/flow-go/fvm/environment"
fvmErrors "github.com/onflow/flow-go/fvm/errors"
"github.com/onflow/flow-go/fvm/evm/debug"
"github.com/onflow/flow-go/fvm/evm/handler/coa"
"github.com/onflow/flow-go/fvm/evm/types"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module/trace"
)

// ContractHandler is responsible for triggering calls to emulator, metering,
Expand Down Expand Up @@ -65,6 +67,8 @@ func NewContractHandler(

// DeployCOA deploys a cadence-owned-account and returns the address
func (h *ContractHandler) DeployCOA(uuid uint64) types.Address {
defer h.backend.StartChildSpan(trace.FVMEVMDeployCOA).End()

res, err := h.deployCOA(uuid)
panicOnErrorOrInvalidOrFailedState(res, err)
return *res.DeployedContractAddress
Expand Down Expand Up @@ -119,6 +123,8 @@ func (h *ContractHandler) RunOrPanic(rlpEncodedTx []byte, coinbase types.Address
// Run tries to run an rlpencoded evm transaction and
// collects the gas fees and pay it to the coinbase address provided.
func (h *ContractHandler) Run(rlpEncodedTx []byte, coinbase types.Address) *types.ResultSummary {
defer h.backend.StartChildSpan(trace.FVMEVMRun).End()

res, err := h.run(rlpEncodedTx, coinbase)
panicOnError(err)
return res.ResultSummary()
Expand All @@ -129,6 +135,10 @@ func (h *ContractHandler) Run(rlpEncodedTx []byte, coinbase types.Address) *type
// All transactions provided in the batch are included in a single block,
// except for invalid transactions
func (h *ContractHandler) BatchRun(rlpEncodedTxs [][]byte, coinbase types.Address) []*types.ResultSummary {
span := h.backend.StartChildSpan(trace.FVMEVMBatchRun)
span.SetAttributes(attribute.Int("tx_counts", len(rlpEncodedTxs)))
defer span.End()

res, err := h.batchRun(rlpEncodedTxs, coinbase)
panicOnError(err)

Expand Down Expand Up @@ -341,6 +351,8 @@ func (h *ContractHandler) DryRun(
rlpEncodedTx []byte,
from types.Address,
) *types.ResultSummary {
defer h.backend.StartChildSpan(trace.FVMEVMDryRun).End()

res, err := h.dryRun(rlpEncodedTx, from)
panicOnError(err)
return res.ResultSummary()
Expand Down Expand Up @@ -667,6 +679,8 @@ func (a *Account) codeHash() ([]byte, error) {
// Deposit deposits the token from the given vault into the flow evm main vault
// and update the account balance with the new amount
func (a *Account) Deposit(v *types.FLOWTokenVault) {
defer a.fch.backend.StartChildSpan(trace.FVMEVMDeposit).End()

res, err := a.deposit(v)
panicOnErrorOrInvalidOrFailedState(res, err)
}
Expand All @@ -692,6 +706,8 @@ func (a *Account) deposit(v *types.FLOWTokenVault) (*types.Result, error) {
// Withdraw deducts the balance from the account and
// withdraw and return flow token from the Flex main vault.
func (a *Account) Withdraw(b types.Balance) *types.FLOWTokenVault {
defer a.fch.backend.StartChildSpan(trace.FVMEVMWithdraw).End()

res, err := a.withdraw(b)
panicOnErrorOrInvalidOrFailedState(res, err)

Expand Down Expand Up @@ -745,6 +761,8 @@ func (a *Account) transfer(to types.Address, balance types.Balance) (*types.Resu
// contained in the result summary as data and
// the contract data is not controlled by the caller accounts
func (a *Account) Deploy(code types.Code, gaslimit types.GasLimit, balance types.Balance) *types.ResultSummary {
defer a.fch.backend.StartChildSpan(trace.FVMEVMDeploy).End()

res, err := a.deploy(code, gaslimit, balance)
panicOnError(err)
return res.ResultSummary()
Expand All @@ -771,6 +789,8 @@ func (a *Account) deploy(code types.Code, gaslimit types.GasLimit, balance types
// given it doesn't goes beyond what Flow transaction allows.
// the balance would be deducted from the OFA account and would be transferred to the target address
func (a *Account) Call(to types.Address, data types.Data, gaslimit types.GasLimit, balance types.Balance) *types.ResultSummary {
defer a.fch.backend.StartChildSpan(trace.FVMEVMCall).End()

res, err := a.call(to, data, gaslimit, balance)
panicOnError(err)
return res.ResultSummary()
Expand Down
52 changes: 52 additions & 0 deletions fvm/evm/handler/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/onflow/flow-go/fvm/evm/types"
"github.com/onflow/flow-go/fvm/systemcontracts"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module/trace"
)

// TODO add test for fatal errors
Expand Down Expand Up @@ -1257,6 +1258,57 @@ func TestHandler_TransactionRun(t *testing.T) {
})
})
})

t.Run("test - open tracing", func(t *testing.T) {
t.Parallel()

testutils.RunWithTestBackend(t, func(backend *testutils.TestBackend) {
testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) {
testutils.RunWithEOATestAccount(t, backend, rootAddr, func(eoa *testutils.EOATestAccount) {

tx := gethTypes.NewTransaction(
uint64(1),
gethCommon.Address{1, 2},
big.NewInt(13),
uint64(0),
big.NewInt(1000),
[]byte{},
)

rlpTx, err := tx.MarshalBinary()
require.NoError(t, err)

handler := SetupHandler(t, backend, rootAddr)

backend.ExpectedSpan(t, trace.FVMEVMDryRun)
handler.DryRun(rlpTx, types.EmptyAddress)

backend.ExpectedSpan(t, trace.FVMEVMRun)
handler.Run(rlpTx, types.EmptyAddress)

backend.ExpectedSpan(t, trace.FVMEVMBatchRun)
handler.BatchRun([][]byte{rlpTx}, types.EmptyAddress)

backend.ExpectedSpan(t, trace.FVMEVMDeployCOA)
coa := handler.DeployCOA(1)

acc := handler.AccountByAddress(coa, true)

backend.ExpectedSpan(t, trace.FVMEVMCall)
acc.Call(types.EmptyAddress, nil, 1000, types.EmptyBalance)

backend.ExpectedSpan(t, trace.FVMEVMDeposit)
acc.Deposit(types.NewFlowTokenVault(types.EmptyBalance))

backend.ExpectedSpan(t, trace.FVMEVMWithdraw)
acc.Withdraw(types.EmptyBalance)

backend.ExpectedSpan(t, trace.FVMEVMDeploy)
acc.Deploy(nil, 1, types.EmptyBalance)
})
})
})
})
}

// returns true if error passes the checks
Expand Down
Loading

0 comments on commit 55fb3fa

Please sign in to comment.