Skip to content

Commit

Permalink
Upgrade to v1 of flowkit (#108)
Browse files Browse the repository at this point in the history
* alpha of v1 flowkit

* update to latest version

* adding contract do not expose out flowkit

* expose flowaddress

* fixed pinning of version

* upgrade to new version

* Coverage and rollback (#107)

* testing coverage and rollback

* added rollback test

* initial support for rollback after each test

* stopOnError

* TxFN should not store whats in previous tx (#109)

* update to released version of flowkit

---------

Co-authored-by: Hui Ben <ben@find.xyz>
Co-authored-by: Bamthelearner <95492891+Bamthelearner@users.noreply.github.com>

* Enhance transaction (#106)

* added methods to get stakeholders from events

* updated transaction to have more fields built in

* added id to event, transactionid-index

* fix error if type is nil

* change it so that we keep addresses and not types, possibly keep nested fields but not sure

* added zap logger to stream tx

* tidy

* added tx length"

* add import stakeholders

* fix import stakeholder

* fix stakeholder address

* added end block to stream

* added done flag

* revert endHeight change

* added method to beta client

* fix get imports

* add seperate var for imports

* Update event.go

* Update event.go

* ignore

---------

Co-authored-by: Hui Ben <ben@find.xyz>
Co-authored-by: Bamthelearner <95492891+Bamthelearner@users.noreply.github.com>
  • Loading branch information
3 people authored Apr 27, 2023
1 parent 8046858 commit 29a0593
Show file tree
Hide file tree
Showing 29 changed files with 1,336 additions and 371 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ vendor
.idea
profile.cov
test-result.xml
coverage-report.json
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ For a standalone example on how overflow can be used look at https://github.com/
- transform all interactions into a NPM module that can be published for the frontend to use. this json file that is generate has the option to filter out certain interactions and to strip away network suffixes if you have multiple local interactions that should map to the same logical name in the client for each network
- the interaction (script/tx) dsl has a rich set of assertions
- arguments to interactions are all _named_ that is the same name in that is in the argument must be used with the `Arg("name", "value")` builder. The `value` in this example can be either a primitive go value or a `cadence.Value`.
- supports shared instance in test to collect coverage report and rollback after/before each test. See `example` folder.

## Gotchas

Expand Down Expand Up @@ -69,6 +70,7 @@ import (
func main() {

//start an in memory emulator by default
// there are two interfaces published for Overflow, `OverflowClient` and `OverrflowBetaClient` that has unstable api, I urge you to store this as the client and not the impl. Currenly the Overflow method returns the impl so you can choose.
o := Overflow()

//the Tx DSL runs an transaction
Expand Down
5 changes: 3 additions & 2 deletions account_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package overflow

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -40,7 +41,7 @@ func TestGetAccount(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, g)
assert.NotNil(t, g)
account, err := g.GetAccount("account")
account, err := g.GetAccount(context.Background(), "account")
require.NoError(t, err)
assert.Equal(t, "f8d6e0586b0a20c7", account.Address.String())
})
Expand All @@ -49,7 +50,7 @@ func TestGetAccount(t *testing.T) {
g, err := OverflowTesting()
require.NotNil(t, g)
require.NoError(t, err)
_, err = g.GetAccount("doesnotexist")
_, err = g.GetAccount(context.Background(), "doesnotexist")
assert.ErrorContains(t, err, "could not find account with name emulator-doesnotexist in the configuration")

})
Expand Down
9 changes: 5 additions & 4 deletions blocks_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package overflow

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -13,7 +14,7 @@ func TestGetBlock(t *testing.T) {
g, err := OverflowTesting()
require.NoError(t, err)
require.NotNil(t, g)
block, err := g.GetLatestBlock()
block, err := g.GetLatestBlock(context.Background())

assert.Nil(t, err)
assert.GreaterOrEqual(t, block.Height, uint64(0))
Expand All @@ -22,7 +23,7 @@ func TestGetBlock(t *testing.T) {
t.Run("Should get block by height", func(t *testing.T) {
g, err := OverflowTesting()
require.NoError(t, err)
block, err := g.GetBlockAtHeight(0)
block, err := g.GetBlockAtHeight(context.Background(), 0)

assert.Nil(t, err)
assert.Equal(t, uint64(0), block.Height)
Expand All @@ -31,9 +32,9 @@ func TestGetBlock(t *testing.T) {
t.Run("Should get block by ID", func(t *testing.T) {
g, err := OverflowTesting()
require.NoError(t, err)
block, err := g.GetBlockAtHeight(0)
block, err := g.GetBlockAtHeight(context.Background(), 0)
assert.Nil(t, err)
block, err = g.GetBlockById(block.ID.String())
block, err = g.GetBlockById(context.Background(), block.ID.String())
assert.Nil(t, err)
assert.NotNil(t, block)
})
Expand Down
53 changes: 53 additions & 0 deletions cadence.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,59 @@ func CadenceValueToJsonString(value cadence.Value) (string, error) {
return string(j), nil
}

func ExtractAddresses(field cadence.Value) []string {
if field == nil {
return nil
}

switch field := field.(type) {
case cadence.Optional:
return ExtractAddresses(field.Value)
case cadence.Dictionary:
result := []string{}
for _, item := range field.Pairs {
value := ExtractAddresses(item.Value)
key := getAndUnquoteString(item.Key)

if value != nil && key != "" {
result = append(result, value...)
}
}
if len(result) == 0 {
return nil
}
return result
case cadence.Struct:
result := []string{}
for _, subField := range field.Fields {
value := ExtractAddresses(subField)
if value != nil {
result = append(result, value...)
}
}
if len(result) == 0 {
return nil
}
return result
case cadence.Array:
result := []string{}
for _, item := range field.Values {
value := ExtractAddresses(item)
if value != nil {
result = append(result, value...)
}
}
if len(result) == 0 {
return nil
}
return result
case cadence.Address:
return []string{field.String()}
default:
return []string{}
}
}

// CadenceValueToInterface convert a candence.Value into interface{}
func CadenceValueToInterface(field cadence.Value) interface{} {
if field == nil {
Expand Down
45 changes: 44 additions & 1 deletion event.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,32 @@ type OverflowEventList []OverflowEvent
// a type holding all events that are emitted from a Transaction
type OverflowEvents map[string]OverflowEventList

func (me OverflowEvents) GetStakeholders(stakeholders map[string][]string) map[string][]string {

for _, events := range me {
for _, event := range events {
eventStakeholders := event.GetStakeholders()
for stakeholder, roles := range eventStakeholders {

allRoles, ok := stakeholders[stakeholder]
if !ok {
allRoles = []string{}
}
allRoles = append(allRoles, roles...)
stakeholders[stakeholder] = allRoles
}
}
}

return stakeholders
}

type OverflowEvent struct {
Id string `json:"id"`
Fields map[string]interface{} `json:"fields"`
TransactionId string `json:"transactionID"`
Name string `json:"name"`
Addresses map[string][]string `json:"types"`
}

// Check if an event exist in the other events
Expand All @@ -36,6 +58,23 @@ func (o OverflowEvent) ExistIn(events []OverflowEvent) bool {
return false
}

// list of address to a list of roles for that address
func (me OverflowEvent) GetStakeholders() map[string][]string {
stakeholder := map[string][]string{}
for name, value := range me.Addresses {
for _, address := range value {

existing, ok := stakeholder[address]
if !ok {
existing = []string{}
}
existing = append(existing, fmt.Sprintf("%s/%s", me.Name, name))
stakeholder[address] = existing
}
}
return stakeholder
}

func (e OverflowEventList) MarshalAs(marshalTo interface{}) error {
bytes, err := json.Marshal(e)
if err != nil {
Expand Down Expand Up @@ -66,7 +105,7 @@ func (e OverflowEvent) MarshalAs(marshalTo interface{}) error {
func parseEvents(events []flow.Event) (OverflowEvents, OverflowEvent) {
overflowEvents := OverflowEvents{}
fee := OverflowEvent{}
for _, event := range events {
for i, event := range events {

var fieldNames []string

Expand All @@ -75,9 +114,11 @@ func parseEvents(events []flow.Event) (OverflowEvents, OverflowEvent) {
}

finalFields := map[string]interface{}{}
addresses := map[string][]string{}

for id, field := range event.Value.Fields {
name := fieldNames[id]
addresses[name] = ExtractAddresses(field)
value := CadenceValueToInterface(field)
if value != nil {
finalFields[name] = value
Expand All @@ -89,9 +130,11 @@ func parseEvents(events []flow.Event) (OverflowEvents, OverflowEvent) {
events = []OverflowEvent{}
}
events = append(events, OverflowEvent{
Id: fmt.Sprintf("%s-%d", event.TransactionID.Hex(), i),
Fields: finalFields,
Name: event.Type,
TransactionId: event.TransactionID.String(),
Addresses: addresses,
})
overflowEvents[event.Type] = events

Expand Down
22 changes: 19 additions & 3 deletions event_fetcher.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package overflow

import (
"context"
"encoding/json"
"fmt"
"sort"
"strings"
"time"

"github.com/onflow/flow-cli/flowkit"
)

// Event fetching
Expand Down Expand Up @@ -34,6 +37,7 @@ func (self *InMemoryProgressKeeper) WriteProgress(progress int64) error {

// OverflowEventFetcherBuilder builder to hold info about eventhook context.
type OverflowEventFetcherBuilder struct {
Ctx context.Context
OverflowState *OverflowState
EventsAndIgnoreFields OverflowEventFilter
FromIndex int64
Expand All @@ -49,6 +53,7 @@ type OverflowEventFetcherBuilder struct {
// Build an event fetcher builder from the sent in options
func (o *OverflowState) buildEventInteraction(opts ...OverflowEventFetcherOption) *OverflowEventFetcherBuilder {
e := &OverflowEventFetcherBuilder{
Ctx: context.Background(),
OverflowState: o,
EventsAndIgnoreFields: OverflowEventFilter{},
EndAtCurrentHeight: true,
Expand Down Expand Up @@ -127,12 +132,12 @@ func (o *OverflowState) FetchEventsWithResult(opts ...OverflowEventFetcherOption

endIndex := e.EndIndex
if e.EndAtCurrentHeight {
blockHeight, err := e.OverflowState.Services.Blocks.GetLatestBlockHeight()
blockHeight, err := e.OverflowState.GetLatestBlock(e.Ctx)
if err != nil {
res.Error = err
return res
}
endIndex = blockHeight
endIndex = blockHeight.Height
}

fromIndex := e.FromIndex
Expand All @@ -154,7 +159,11 @@ func (o *OverflowState) FetchEventsWithResult(opts ...OverflowEventFetcherOption
if uint64(fromIndex) > endIndex {
return res
}
blockEvents, err := e.OverflowState.Services.Events.Get(events, uint64(fromIndex), endIndex, e.EventBatchSize, e.NumberOfWorkers)
ew := &flowkit.EventWorker{
Count: e.NumberOfWorkers,
BlocksPerWorker: e.EventBatchSize,
}
blockEvents, err := e.OverflowState.Flowkit.GetEvents(e.Ctx, events, uint64(fromIndex), endIndex, ew)
if err != nil {
res.Error = err
return res
Expand Down Expand Up @@ -221,6 +230,13 @@ func (o *OverflowState) FetchEvents(opts ...OverflowEventFetcherOption) ([]Overf
return res.Events, res.Error
}

// Set the Workers size for FetchEvents
func WithEventFetcherContext(ctx context.Context) OverflowEventFetcherOption {
return func(e *OverflowEventFetcherBuilder) {
e.Ctx = ctx
}
}

// Set the Workers size for FetchEvents
func WithWorkers(workers int) OverflowEventFetcherOption {
return func(e *OverflowEventFetcherBuilder) {
Expand Down
5 changes: 3 additions & 2 deletions event_fetcher_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func TestIntegrationEventFetcher(t *testing.T) {
defer os.Remove("progress")
assert.NoError(t, err)
assert.Equal(t, 1, len(ev))
assert.Contains(t, ev[0].String(), "100")
assert.Contains(t, ev[0].String(), "10")
})

t.Run("should fail reading invalid progress from file", func(t *testing.T) {
Expand Down Expand Up @@ -161,7 +161,8 @@ func TestIntegrationEventFetcher(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, int64(0), progress)

res.ProgressWriteFunction()
err = res.ProgressWriteFunction()
require.NoError(t, err)

progress, err = readProgressFromFile(progressFile)
require.NoError(t, err)
Expand Down
34 changes: 34 additions & 0 deletions example/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package example

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestExample(t *testing.T) {

//in order to run a test that will reset to known state in setup_test use the `ot.Run(t,...)``method instead of `t.Run(...)`
ot.Run(t, "Example test", func(t *testing.T) {
block, err := ot.O.GetLatestBlock(context.Background())
require.NoError(t, err)
assert.Equal(t, 8, int(block.Height))

ot.O.MintFlowTokens("first", 1000.0)
require.NoError(t, ot.O.Error)

block, err = ot.O.GetLatestBlock(context.Background())
require.NoError(t, err)
assert.Equal(t, 9, int(block.Height))

})

ot.Run(t, "Example test 2", func(t *testing.T) {
block, err := ot.O.GetLatestBlock(context.Background())
require.NoError(t, err)
assert.Equal(t, 8, int(block.Height))
})

}
Loading

0 comments on commit 29a0593

Please sign in to comment.