diff --git a/cmd/util/cmd/execution-state-extract/execution_state_extract.go b/cmd/util/cmd/execution-state-extract/execution_state_extract.go index bb79bfc7a75..1ddc1d47eb9 100644 --- a/cmd/util/cmd/execution-state-extract/execution_state_extract.go +++ b/cmd/util/cmd/execution-state-extract/execution_state_extract.go @@ -58,6 +58,7 @@ func extractExecutionState(dir string, if migrate { migrations = []ledger.Migration{ mgr.PruneMigration, + mgr.BrokenContractMigration, mgr.StorageFormatV4Migration, } } diff --git a/cmd/util/ledger/migrations/accounts.go b/cmd/util/ledger/migrations/accounts.go index e5a588225aa..87b8d6f8dd6 100644 --- a/cmd/util/ledger/migrations/accounts.go +++ b/cmd/util/ledger/migrations/accounts.go @@ -11,7 +11,7 @@ import ( ) func AddMissingKeysMigration(payloads []ledger.Payload) ([]ledger.Payload, error) { - l := newView(payloads) + l := NewView(payloads) st := state.NewState(l) sth := state.NewStateHolder(st) a := state.NewAccounts(sth) @@ -137,7 +137,7 @@ type view struct { Ledger *led } -func newView(payloads []ledger.Payload) *view { +func NewView(payloads []ledger.Payload) *view { return &view{ Ledger: newLed(payloads), } @@ -145,7 +145,7 @@ func newView(payloads []ledger.Payload) *view { func (v *view) NewChild() state.View { payload := make([]ledger.Payload, 0) - ch := newView(payload) + ch := NewView(payload) ch.Parent = v return ch } diff --git a/cmd/util/ledger/migrations/broken_contract_migration.go b/cmd/util/ledger/migrations/broken_contract_migration.go new file mode 100644 index 00000000000..cfa84246739 --- /dev/null +++ b/cmd/util/ledger/migrations/broken_contract_migration.go @@ -0,0 +1,85 @@ +package migrations + +import ( + "fmt" + + "github.com/onflow/flow-go/fvm/state" + "github.com/onflow/flow-go/ledger" + "github.com/onflow/flow-go/model/flow" +) + +// BrokenContractMigration fixes some of the early contracts that have been broken due to Cadence upgrades. +func BrokenContractMigration(payloads []ledger.Payload) ([]ledger.Payload, error) { + l := NewView(payloads) + st := state.NewState(l) + sth := state.NewStateHolder(st) + a := state.NewAccounts(sth) + + err := migrateContractForAccount(a, "937cbdee135c656c") + if err != nil { + return nil, err + } + + err = migrateContractForAccount(a, "7f560d7e3ff04a31") + if err != nil { + return nil, err + } + + return l.Payloads(), nil +} + +func migrateContractForAccount(accounts *state.Accounts, addressInHex string) error { + address := flow.HexToAddress(addressInHex) + ok, err := accounts.Exists(address) + if err != nil { + return err + } + if ok { + err = accounts.SetContract("TokenHolderKeyManager", address, GetKeyManagerContractContent()) + if err != nil { + return err + } + } else { + // if not exist log and return gracefully + fmt.Println("warning account does not exist: ", addressInHex) + } + return nil +} + +func GetKeyManagerContractContent() []byte { + return []byte(`import KeyManager from 0x840b99b76051d886 + + // The TokenHolderKeyManager contract is an implementation of + // the KeyManager interface intended for use by FLOW token holders. + // + // One instance is deployed to each token holder account. + // Deployment is executed a with signature from the administrator, + // allowing them to take possession of a KeyAdder resource + // upon initialization. + pub contract TokenHolderKeyManager: KeyManager { + + access(contract) fun addPublicKey(_ publicKey: [UInt8]) { + self.account.addPublicKey(publicKey) + } + + pub resource KeyAdder: KeyManager.KeyAdder { + + pub let address: Address + + pub fun addPublicKey(_ publicKey: [UInt8]) { + TokenHolderKeyManager.addPublicKey(publicKey) + } + + init(address: Address) { + self.address = address + } + } + + init(admin: AuthAccount, path: StoragePath) { + let keyAdder <- create KeyAdder(address: self.account.address) + + admin.save(<- keyAdder, to: path) + } + } + `) +} diff --git a/cmd/util/ledger/migrations/broken_contract_migration_test.go b/cmd/util/ledger/migrations/broken_contract_migration_test.go new file mode 100644 index 00000000000..6340bb9afa6 --- /dev/null +++ b/cmd/util/ledger/migrations/broken_contract_migration_test.go @@ -0,0 +1,36 @@ +package migrations_test + +import ( + "testing" + + "github.com/onflow/flow-go/cmd/util/ledger/migrations" + "github.com/onflow/flow-go/fvm/state" + "github.com/onflow/flow-go/ledger" + "github.com/onflow/flow-go/model/flow" + "github.com/stretchr/testify/require" +) + +func TestBrokenContractMigration(t *testing.T) { + + address := flow.HexToAddress("937cbdee135c656c") + l := migrations.NewView(make([]ledger.Payload, 0)) + st := state.NewState(l) + sth := state.NewStateHolder(st) + accounts := state.NewAccounts(sth) + + err := accounts.Create(nil, address) + require.NoError(t, err) + + err = accounts.SetContract("TokenHolderKeyManager", address, []byte("OLD CONTENT")) + require.NoError(t, err) + + newPayloads, err := migrations.BrokenContractMigration(l.Payloads()) + require.NoError(t, err) + + st = state.NewState(migrations.NewView(newPayloads)) + sth = state.NewStateHolder(st) + accounts = state.NewAccounts(sth) + content, err := accounts.GetContract("TokenHolderKeyManager", address) + require.NoError(t, err) + require.Equal(t, content, migrations.GetKeyManagerContractContent()) +} diff --git a/cmd/util/ledger/migrations/contract_reporter.go b/cmd/util/ledger/migrations/contract_reporter.go index 073baffc460..47cb2a2ffce 100644 --- a/cmd/util/ledger/migrations/contract_reporter.go +++ b/cmd/util/ledger/migrations/contract_reporter.go @@ -48,7 +48,7 @@ func (r ContractReporter) Report(payload []ledger.Payload) error { } }() - l := newView(payload) + l := NewView(payload) st := state.NewState(l) sth := state.NewStateHolder(st) accounts := state.NewAccounts(sth) diff --git a/cmd/util/ledger/migrations/storage_reporter.go b/cmd/util/ledger/migrations/storage_reporter.go index b9c186f2d19..e0053080c42 100644 --- a/cmd/util/ledger/migrations/storage_reporter.go +++ b/cmd/util/ledger/migrations/storage_reporter.go @@ -52,7 +52,7 @@ func (r StorageReporter) Report(payload []ledger.Payload) error { } }() - l := newView(payload) + l := NewView(payload) st := state.NewState(l) for _, p := range payload { diff --git a/cmd/util/ledger/migrations/storage_v4.go b/cmd/util/ledger/migrations/storage_v4.go index cad343c0915..0d3b1d70dc0 100644 --- a/cmd/util/ledger/migrations/storage_v4.go +++ b/cmd/util/ledger/migrations/storage_v4.go @@ -242,6 +242,16 @@ var tokenForwardingLocationMainnet = common.AddressLocation{ Name: "TokenForwarding", } +var tokenHolderKeyManagerLocationMainnet1 = common.AddressLocation{ + Address: common.BytesToAddress([]byte{0x93, 0x7c, 0xbd, 0xee, 0x13, 0x5c, 0x65, 0x6c}), + Name: "TokenHolderKeyManager", +} + +var tokenHolderKeyManagerLocationMainnet2 = common.AddressLocation{ + Address: common.BytesToAddress([]byte{0x7f, 0x56, 0x0d, 0x7e, 0x3f, 0xf0, 0x4a, 0x31}), + Name: "TokenHolderKeyManager", +} + func isTokenForwardingLocation(location common.Location) bool { return common.LocationsMatch(location, tokenForwardingLocationTestnet) || common.LocationsMatch(location, tokenForwardingLocationMainnet) diff --git a/fvm/transactionFeeDeductor.go b/fvm/transactionFeeDeductor.go index 83f3d14ff65..123ec20c307 100644 --- a/fvm/transactionFeeDeductor.go +++ b/fvm/transactionFeeDeductor.go @@ -5,6 +5,7 @@ import ( "github.com/onflow/flow-go/fvm/programs" "github.com/onflow/flow-go/fvm/state" "github.com/onflow/flow-go/module/trace" + "github.com/opentracing/opentracing-go" ) type TransactionFeeDeductor struct{} @@ -20,12 +21,13 @@ func (d *TransactionFeeDeductor) Process( sth *state.StateHolder, programs *programs.Programs, ) error { + var span opentracing.Span if ctx.Tracer != nil && proc.TraceSpan != nil { - span := ctx.Tracer.StartSpanFromParent(proc.TraceSpan, trace.FVMDeductTransactionFees) + span = ctx.Tracer.StartSpanFromParent(proc.TraceSpan, trace.FVMDeductTransactionFees) defer span.Finish() } - txErr, fatalErr := d.deductFees(vm, ctx, proc, sth, programs) + txErr, fatalErr := d.deductFees(vm, ctx, proc, sth, programs, span) // TODO handle deduct fee failures, for now just return as error if txErr != nil { return txErr @@ -39,9 +41,10 @@ func (d *TransactionFeeDeductor) deductFees( proc *TransactionProcedure, sth *state.StateHolder, programs *programs.Programs, + span opentracing.Span, ) (errors.Error, error) { - feeTx := deductTransactionFeeTransaction(proc.Transaction.Payer, ctx.Chain.ServiceAddress()) + feeTx.SetTraceSpan(span) txErr, fatalErr := vm.invokeMetaTransaction( *ctx, feeTx, diff --git a/module/trace/constants.go b/module/trace/constants.go index 33075c6d622..92e61bd9d4e 100644 --- a/module/trace/constants.go +++ b/module/trace/constants.go @@ -149,6 +149,7 @@ const ( FVMExecuteTransaction SpanName = "fvm.executeTransaction" FVMDeductTransactionFees SpanName = "fvm.deductTransactionFees" FVMFrozenAccountCheckTransaction SpanName = "fvm.frozenAccountCheckTransaction" + FVMInvokeMetaTransaction SpanName = "fvm.invokeMetaTransaction" FVMEnvHash SpanName = "fvm.env.Hash" FVMEnvValueExists SpanName = "fvm.env.valueExists"