Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions config/dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ type Source struct {
}

type Dependency struct {
Name string
Source Source
Hash string
Aliases Aliases
Canonical string
Name string
Source Source
Hash string
BlockHeight uint64
Aliases Aliases
Canonical string
}

type Dependencies []Dependency
Expand Down
25 changes: 14 additions & 11 deletions config/json/dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) {
}

dep = config.Dependency{
Name: dependencyName,
Hash: dependency.Extended.Hash,
Canonical: dependency.Extended.Canonical,
Name: dependencyName,
Hash: dependency.Extended.Hash,
BlockHeight: dependency.Extended.BlockHeight,
Canonical: dependency.Extended.Canonical,
Source: config.Source{
NetworkName: depNetwork,
Address: flow.HexToAddress(depAddress),
Expand Down Expand Up @@ -100,10 +101,11 @@ func transformDependenciesToJSON(configDependencies config.Dependencies, configC

jsonDeps[dep.Name] = jsonDependency{
Extended: jsonDependencyExtended{
Source: buildSourceString(dep.Source),
Hash: dep.Hash,
Aliases: aliases,
Canonical: dep.Canonical,
Source: buildSourceString(dep.Source),
Hash: dep.Hash,
BlockHeight: dep.BlockHeight,
Aliases: aliases,
Canonical: dep.Canonical,
},
}
}
Expand All @@ -125,10 +127,11 @@ func buildSourceString(source config.Source) string {

// jsonDependencyExtended for json parsing advanced config.
type jsonDependencyExtended struct {
Source string `json:"source"`
Hash string `json:"hash"`
Aliases map[string]string `json:"aliases"`
Canonical string `json:"canonical,omitempty"`
Source string `json:"source"`
Hash string `json:"hash"`
BlockHeight uint64 `json:"block_height,omitempty"`
Aliases map[string]string `json:"aliases"`
Canonical string `json:"canonical,omitempty"`
}

// jsonDependency structure for json parsing.
Expand Down
64 changes: 64 additions & 0 deletions config/json/dependency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,67 @@ func Test_TransformDependenciesWithCanonicalToJSON(t *testing.T) {
assert.Equal(t, "", result["NumberFormatter"].Extended.Canonical)
assert.Equal(t, "NumberFormatter", result["NumberFormatterAlias"].Extended.Canonical)
}

func Test_ConfigDependenciesWithBlockHeight(t *testing.T) {
b := []byte(`{
"HelloWorld": {
"source": "testnet://877931736ee77cff.HelloWorld",
"hash": "abcd1234",
"block_height": 12345678,
"aliases": {
"emulator": "f8d6e0586b0a20c7"
}
}
}`)

var jsonDependencies jsonDependencies
err := json.Unmarshal(b, &jsonDependencies)
assert.NoError(t, err)

dependencies, err := jsonDependencies.transformToConfig()
assert.NoError(t, err)

assert.Len(t, dependencies, 1)

dep := dependencies.ByName("HelloWorld")
assert.NotNil(t, dep)
assert.Equal(t, "abcd1234", dep.Hash)
assert.Equal(t, uint64(12345678), dep.BlockHeight)
}

func Test_TransformDependenciesWithBlockHeightToJSON(t *testing.T) {
b := []byte(`{
"HelloWorld": {
"source": "testnet://877931736ee77cff.HelloWorld",
"hash": "abcd1234",
"block_height": 12345678,
"aliases": {
"emulator": "f8d6e0586b0a20c7"
}
}
}`)

var jsonContracts jsonContracts
errContracts := json.Unmarshal(b, &jsonContracts)
assert.NoError(t, errContracts)

var jsonDependencies jsonDependencies
err := json.Unmarshal(b, &jsonDependencies)
assert.NoError(t, err)

contracts, err := jsonContracts.transformToConfig()
assert.NoError(t, err)
dependencies, err := jsonDependencies.transformToConfig()
assert.NoError(t, err)

j := transformDependenciesToJSON(dependencies, contracts)
x, _ := json.Marshal(j)

// Parse back and check block_height field
var result map[string]jsonDependency
err = json.Unmarshal(x, &result)
assert.NoError(t, err)

assert.Equal(t, "abcd1234", result["HelloWorld"].Extended.Hash)
assert.Equal(t, uint64(12345678), result["HelloWorld"].Extended.BlockHeight)
}
9 changes: 9 additions & 0 deletions gateway/emulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ func (g *EmulatorGateway) GetAccount(ctx context.Context, address flow.Address)
return account, nil
}

func (g *EmulatorGateway) GetAccountAtBlockHeight(ctx context.Context, address flow.Address, blockHeight uint64) (*flow.Account, error) {
account, err := g.adapter.GetAccountAtBlockHeight(ctx, address, blockHeight)
if err != nil {
return nil, UnwrapStatusError(err)
}
return account, nil
}


func (g *EmulatorGateway) SendSignedTransaction(ctx context.Context, tx *flow.Transaction) (*flow.Transaction, error) {
err := g.adapter.SendTransaction(ctx, *tx)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
// Gateway describes blockchain access interface
type Gateway interface {
GetAccount(context.Context, flow.Address) (*flow.Account, error)
GetAccountAtBlockHeight(context.Context, flow.Address, uint64) (*flow.Account, error)
SendSignedTransaction(context.Context, *flow.Transaction) (*flow.Transaction, error)
GetTransaction(context.Context, flow.Identifier) (*flow.Transaction, error)
GetTransactionResultsByBlockID(ctx context.Context, blockID flow.Identifier) ([]*flow.TransactionResult, error)
Expand Down
11 changes: 11 additions & 0 deletions gateway/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ func (g *GrpcGateway) GetAccount(ctx context.Context, address flow.Address) (*fl
return account, nil
}

// GetAccountAtBlockHeight gets an account by address at a specific block height from the Flow Access API.
func (g *GrpcGateway) GetAccountAtBlockHeight(ctx context.Context, address flow.Address, blockHeight uint64) (*flow.Account, error) {
account, err := g.client.GetAccountAtBlockHeight(ctx, address, blockHeight)
if err != nil {
return nil, fmt.Errorf("failed to get account with address %s at block height %d: %w", address, blockHeight, err)
}

return account, nil
}


// SendSignedTransaction sends a transaction to flow that is already prepared and signed.
func (g *GrpcGateway) SendSignedTransaction(ctx context.Context, tx *flow.Transaction) (*flow.Transaction, error) {
err := g.client.SendTransaction(ctx, *tx)
Expand Down
30 changes: 30 additions & 0 deletions gateway/mocks/Gateway.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 18 additions & 1 deletion gateway/mocks/gateway_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

const (
GetAccountFunc = "GetAccount"
GetAccountAtBlockHeightFunc = "GetAccountAtBlockHeight"
SendSignedTransactionFunc = "SendSignedTransaction"
GetCollectionFunc = "GetCollection"
GetTransactionResultFunc = "GetTransactionResult"
Expand All @@ -49,6 +50,7 @@ type TestGateway struct {
Mock *Gateway
SendSignedTransaction *mock.Call
GetAccount *mock.Call
GetAccountAtBlockHeight *mock.Call
GetCollection *mock.Call
GetTransactionResult *mock.Call
GetEvents *mock.Call
Expand Down Expand Up @@ -83,6 +85,12 @@ func DefaultMockGateway() *TestGateway {
ctxMock,
mock.AnythingOfType("flow.Address"),
),
GetAccountAtBlockHeight: m.On(
GetAccountAtBlockHeightFunc,
ctxMock,
mock.AnythingOfType("flow.Address"),
mock.AnythingOfType("uint64"),
),
GetCollection: m.On(
GetCollectionFunc,
ctxMock,
Expand Down Expand Up @@ -146,7 +154,16 @@ func DefaultMockGateway() *TestGateway {

t.GetAccount.Run(func(args mock.Arguments) {
addr := args.Get(1).(flow.Address)
t.GetAccount.Return(tests.NewAccountWithAddress(addr.String()), nil)
acc := tests.NewAccountWithAddress(addr.String())
t.GetAccount.Return(acc, nil)
})

t.GetAccountAtBlockHeight.Run(func(args mock.Arguments) {
addr := args.Get(1).(flow.Address)
// Return the same account structure as GetAccount for consistency
// If the test needs specific contracts, it should override this mock
acc := tests.NewAccountWithAddress(addr.String())
t.GetAccountAtBlockHeight.Return(acc, nil)
})

t.ExecuteScript.Run(func(args mock.Arguments) {
Expand Down
3 changes: 3 additions & 0 deletions schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@
"hash": {
"type": "string"
},
"block_height": {
"type": "integer"
},
"aliases": {
"patternProperties": {
".*": {
Expand Down
Loading