Skip to content

Commit

Permalink
also run preceeding transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent committed Jan 28, 2025
1 parent 0c0326b commit 15f26d2
Showing 1 changed file with 108 additions and 20 deletions.
128 changes: 108 additions & 20 deletions cmd/util/cmd/debug-tx/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/hex"

client "github.com/onflow/flow-go-sdk/access/grpc"
"github.com/onflow/flow/protobuf/go/flow/execution"
"github.com/onflow/flow/protobuf/go/flow/executiondata"
"github.com/rs/zerolog/log"
Expand Down Expand Up @@ -86,18 +87,9 @@ func run(*cobra.Command, []string) {

flowClient, err := grpcclient.FlowClient(config)
if err != nil {
log.Fatal().Err(err).Msg("failed to create flow client")
log.Fatal().Err(err).Msg("failed to create client")
}

log.Info().Msg("Fetching transaction ...")

tx, err := flowClient.GetTransaction(context.Background(), sdk.Identifier(txID))
if err != nil {
log.Fatal().Err(err).Msg("failed to fetch transaction")
}

log.Info().Msgf("Fetched transaction: %s", tx.ID())

log.Info().Msg("Fetching transaction result ...")

txResult, err := flowClient.GetTransactionResult(context.Background(), sdk.Identifier(txID))
Expand All @@ -115,6 +107,17 @@ func run(*cobra.Command, []string) {
blockHeight,
)

log.Info().Msg("Fetching transactions of block ...")

txsResult, err := flowClient.GetTransactionsByBlockID(context.Background(), sdk.Identifier(blockID))
if err != nil {
log.Fatal().Err(err).Msg("failed to fetch transactions of block")
}

for _, blockTx := range txsResult {
log.Info().Msgf("Block transaction: %s", blockTx.ID())
}

log.Info().Msg("Fetching block header ...")

header, err := debug.GetAccessAPIBlockHeader(flowClient.RPCClient(), context.Background(), blockID)
Expand All @@ -128,7 +131,7 @@ func run(*cobra.Command, []string) {
header.Height,
)

var snap snapshot.StorageSnapshot
var remoteSnapshot snapshot.StorageSnapshot

if flagUseExecutionDataAPI {
accessConn, err := grpc.NewClient(
Expand All @@ -144,7 +147,7 @@ func run(*cobra.Command, []string) {

// The execution data API provides the *resulting* data,
// so fetch the data for the parent block for the *initial* data.
snap, err = debug.NewExecutionDataStorageSnapshot(executionDataClient, nil, blockHeight-1)
remoteSnapshot, err = debug.NewExecutionDataStorageSnapshot(executionDataClient, nil, blockHeight-1)
if err != nil {
log.Fatal().Err(err).Msg("failed to create storage snapshot")
}
Expand All @@ -159,16 +162,59 @@ func run(*cobra.Command, []string) {
defer executionConn.Close()

executionClient := execution.NewExecutionAPIClient(executionConn)
snap, err = debug.NewExecutionNodeStorageSnapshot(executionClient, nil, blockID)

remoteSnapshot, err = debug.NewExecutionNodeStorageSnapshot(executionClient, nil, blockID)
if err != nil {
log.Fatal().Err(err).Msg("failed to create storage snapshot")
}
}

log.Info().Msg("Debugging transaction ...")
blockSnapshot := newBlockSnapshot(remoteSnapshot)

debugger := debug.NewRemoteDebugger(chain, log.Logger)

for _, blockTx := range txsResult {
blockTxID := flow.Identifier(blockTx.ID())

isDebuggedTx := blockTxID == txID

dumpRegisters := flagDumpRegisters && isDebuggedTx

runTransaction(
debugger,
blockTxID,
flowClient,
blockSnapshot,
header,
dumpRegisters,
)

if isDebuggedTx {
break
}
}
}

func runTransaction(
debugger *debug.RemoteDebugger,
txID flow.Identifier,
flowClient *client.Client,
blockSnapshot *blockSnapshot,
header *flow.Header,
dumpRegisters bool,
) {

log.Info().Msgf("Fetching transaction %s ...", txID)

tx, err := flowClient.GetTransaction(context.Background(), sdk.Identifier(txID))
if err != nil {
log.Fatal().Err(err).Msg("Failed to fetch transaction")
}

log.Info().Msgf("Fetched transaction: %s", tx.ID())

log.Info().Msgf("Debugging transaction %s ...", tx.ID())

txBody := flow.NewTransactionBody().
SetScript(tx.Script).
SetComputeLimit(flagComputeLimit).
Expand All @@ -193,12 +239,29 @@ func run(*cobra.Command, []string) {
proposalKeySequenceNumber,
)

resultSnapshot, txErr, processErr := debugger.RunTransaction(txBody, snap, header)
resultSnapshot, txErr, processErr := debugger.RunTransaction(
txBody,
blockSnapshot,
header,
)
if processErr != nil {
log.Fatal().Err(processErr).Msg("process error")
log.Fatal().Err(processErr).Msg("Failed to process transaction")
}

if txErr != nil {
log.Err(txErr).Msg("Transaction failed")
} else {
log.Info().Msg("Transaction succeeded")
}

if flagDumpRegisters {
for _, updatedRegister := range resultSnapshot.UpdatedRegisters() {
blockSnapshot.Set(
updatedRegister.Key,
updatedRegister.Value,
)
}

if dumpRegisters {
log.Info().Msg("Read registers:")
readRegisterIDs := resultSnapshot.ReadRegisterIDs()
sortRegisters(readRegisterIDs)
Expand All @@ -215,9 +278,6 @@ func run(*cobra.Command, []string) {
)
}
}
if txErr != nil {
log.Err(txErr).Msg("transaction error")
}
}

func sortRegisters(registerIDs []flow.RegisterID) {
Expand All @@ -228,3 +288,31 @@ func sortRegisters(registerIDs []flow.RegisterID) {
)
})
}

type blockSnapshot struct {
cache *debug.InMemoryRegisterCache
backing snapshot.StorageSnapshot
}

var _ snapshot.StorageSnapshot = (*blockSnapshot)(nil)

func newBlockSnapshot(backing snapshot.StorageSnapshot) *blockSnapshot {
cache := debug.NewInMemoryRegisterCache()
return &blockSnapshot{
cache: cache,
backing: backing,
}
}

func (s *blockSnapshot) Get(id flow.RegisterID) (flow.RegisterValue, error) {
data, found := s.cache.Get(id.Key, id.Owner)
if found {
return data, nil
}

return s.backing.Get(id)
}

func (s *blockSnapshot) Set(id flow.RegisterID, value flow.RegisterValue) {
s.cache.Set(id.Key, id.Owner, value)
}

0 comments on commit 15f26d2

Please sign in to comment.