Giter Site home page Giter Site logo

flow-go-sdk's Introduction

Flow Go SDK

GoDoc

The Flow Go SDK provides a set of packages for Go developers to build applications that interact with the Flow network.

Note: This SDK is also fully compatible with the Flow Emulator and can be used for local development.

What is Flow?

Flow is a new blockchain for open worlds. Read more about it here.

Table of Contents

Getting Started

Installing

To start using the SDK, install Go 1.13 or above and run go get:

go get github.com/onflow/flow-go-sdk

Building and testing Go commands with the SDK require enabling cgo CGO_ENABLED=1 because of the underlying cryptography library. Refer to the crypto repository build for more details.

Note that it is possible to build with cgo disabled CGO_ENABLED=0, but this requires confirming the choice by using the Go build tag no-cgo. This would disable the crypto BLS signature features of the SDK. Any call of a BLS tool would result in a panic.

Generating Keys

Flow uses ECDSA to control access to user accounts. Each key pair can be used in combination with the SHA2-256 or SHA3-256 hashing algorithms.

Here's how to generate an ECDSA private key for the P-256 (secp256r1) curve:

import "github.com/onflow/flow-go-sdk/crypto"

// deterministic seed phrase
// note: this is only an example, please use a secure random generator for the key seed
seed := []byte("elephant ears space cowboy octopus rodeo potato cannon pineapple")

privateKey, err := crypto.GeneratePrivateKey(crypto.ECDSA_P256, seed)

The private key can then be encoded as bytes (i.e. for storage):

encPrivateKey := privateKey.Encode()

A private key has an accompanying public key:

publicKey := privateKey.PublicKey()

Supported Curves

The example above uses an ECDSA key pair on the P-256 (secp256r1) elliptic curve. Flow also supports the secp256k1 curve used by Bitcoin and Ethereum.

Here's how to generate an ECDSA private key for the secp256k1 curve:

privateKey, err := crypto.GeneratePrivateKey(crypto.ECDSA_secp256k1, seed)

Here's a full list of the supported signature and hash algorithms: Flow Signature & Hash Algorithms

Accessing The Flow Network

You can communicate with any Flow Access Node using the Flow Go SDK. This includes official Access Nodes, nodes you run yourself, and hosted nodes. Flow Go SDK supports both gRPC and HTTP methods of communication with Access Nodes.

It's strongly recommended to use gRPC with Go SDK since it's more efficient and faster.

Here's how to create a new gRPC client for any network:

// You can also use grpc.TestnetHost and grpc.EmulatorHost
flowClient, _ := grpc.NewClient(grpc.MainnetHost)

Check out the http_grpc_clients example to learn more.

Creating an Account

Once you have generated a key pair, you can create a new account using its public key.

import (
    "github.com/onflow/flow-go-sdk"
    "github.com/onflow/flow-go-sdk/crypto"
    "github.com/onflow/flow-go-sdk/templates"
)

ctx := context.Background()

// generate a new private key for the account
// note: this is only an example, please use a secure random generator for the key seed
seed := []byte("elephant ears space cowboy octopus rodeo potato cannon pineapple")
privateKey, _ := crypto.GeneratePrivateKey(crypto.ECDSA_P256, seed)

// get the public key
publicKey := privateKey.PublicKey()

// construct an account key from the public key
accountKey := flow.NewAccountKey().
    SetPublicKey(publicKey).
    SetHashAlgo(crypto.SHA3_256).             // pair this key with the SHA3_256 hashing algorithm
    SetWeight(flow.AccountKeyWeightThreshold) // give this key full signing weight

// generate an account creation script
// this creates an account with a single public key and no code
script, _ := templates.CreateAccount([]*flow.AccountKey{accountKey}, nil)

// connect to an emulator running locally
c, err := client.New("localhost:3569")
if err != nil {
    panic("failed to connect to emulator")
}

payer, payerKey, payerSigner := examples.ServiceAccount(c)

tx := flow.NewTransaction().
    SetScript(script).
    SetGasLimit(100).
    SetProposalKey(payer, payerKey.Index, payerKey.SequenceNumber).
    SetPayer(payer)

err = tx.SignEnvelope(payer, payerKey.Index, payerSigner)
if err != nil {
    panic("failed to sign transaction")
}

err = c.SendTransaction(ctx, *tx)
if err != nil {
    panic("failed to send transaction")
}

result, err := c.GetTransactionResult(ctx, tx.ID())
if err != nil {
    panic("failed to get transaction result")
}

var myAddress flow.Address

if result.Status == flow.TransactionStatusSealed {
    for _, event := range result.Events {
        if event.Type == flow.EventAccountCreated {
            accountCreatedEvent := flow.AccountCreatedEvent(event)
            myAddress = accountCreatedEvent.Address()
        }
	}
}

Signing a Transaction

Below is a simple example of how to sign a transaction using a crypto.PrivateKey.

import (
    "github.com/onflow/flow-go-sdk"
    "github.com/onflow/flow-go-sdk/crypto"
)

var (
    myAddress    flow.Address
    myAccountKey flow.AccountKey
    myPrivateKey crypto.PrivateKey
)

tx := flow.NewTransaction().
    SetScript([]byte("transaction { execute { log(\"Hello, World!\") } }")).
    SetGasLimit(100).
    SetProposalKey(myAddress, myAccountKey.Index, myAccountKey.SequenceNumber).
    SetPayer(myAddress)

Transaction signing is done through the crypto.Signer interface. The simplest (and least secure) implementation of crypto.Signer is crypto.InMemorySigner.

Signatures can be generated more securely using keys stored in a hardware device such as an HSM. The crypto.Signer interface is intended to be flexible enough to support a variety of signer implementations and is not limited to in-memory implementations.

// construct a signer from your private key and configured hash algorithm
mySigner, err := crypto.NewInMemorySigner(myPrivateKey, myAccountKey.HashAlgo)
if err != nil {
    panic("failed to create a signer")
}

err = tx.SignEnvelope(myAddress, myAccountKey.Index, mySigner)
if err != nil {
    panic("failed to sign transaction")
}

How Signatures Work in Flow

Flow introduces new concepts that allow for more flexibility when creating and signing transactions. Before trying the examples below, we recommend that you read through the transaction signature documentation.


  • Proposer, payer and authorizer are the same account (0x01).
  • Only the envelope must be signed.
  • Proposal key must have full signing weight.
Account Key ID Weight
0x01 1 1000
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))

key1 := account1.Keys[0]

// create signer from securely-stored private key
key1Signer := getSignerForKey1()

tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer: AuthAccount) { log(signer.address) }
        }
    `)).
    SetGasLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetPayer(account1.Address).
    AddAuthorizer(account1.Address)

// account 1 signs the envelope with key 1
err := tx.SignEnvelope(account1.Address, key1.Index, key1Signer)

Full Runnable Example


  • Proposer, payer and authorizer are the same account (0x01).
  • Only the envelope must be signed.
  • Each key has weight 500, so two signatures are required.
Account Key ID Weight
0x01 1 500
0x01 2 500
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))

key1 := account1.Keys[0]
key2 := account1.Keys[1]

// create signers from securely-stored private keys
key1Signer := getSignerForKey1()
key2Signer := getSignerForKey2()

tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer: AuthAccount) { log(signer.address) }
        }
    `)).
    SetGasLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetPayer(account1.Address).
    AddAuthorizer(account1.Address)

// account 1 signs the envelope with key 1
err := tx.SignEnvelope(account1.Address, key1.Index, key1Signer)

// account 1 signs the envelope with key 2
err = tx.SignEnvelope(account1.Address, key2.Index, key2Signer)

Full Runnable Example


  • Proposer and authorizer are the same account (0x01).
  • Payer is a separate account (0x02).
  • Account 0x01 signs the payload.
  • Account 0x02 signs the envelope.
    • Account 0x02 must sign last since it is the payer.
Account Key ID Weight
0x01 1 1000
0x02 3 1000
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))
account2, _ := c.GetAccount(ctx, flow.HexToAddress("02"))

key1 := account1.Keys[0]
key3 := account2.Keys[0]

// create signers from securely-stored private keys
key1Signer := getSignerForKey1()
key3Signer := getSignerForKey3()

tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer: AuthAccount) { log(signer.address) }
        }
    `)).
    SetGasLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetPayer(account2.Address).
    AddAuthorizer(account1.Address)

// account 1 signs the payload with key 1
err := tx.SignPayload(account1.Address, key1.Index, key1Signer)

// account 2 signs the envelope with key 3
// note: payer always signs last
err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer)

Full Runnable Example


  • Proposer and authorizer are the same account (0x01).
  • Payer is a separate account (0x02).
  • Account 0x01 signs the payload.
  • Account 0x02 signs the envelope.
    • Account 0x02 must sign last since it is the payer.
  • Account 0x02 is also an authorizer to show how to include two AuthAccounts into an transaction
Account Key ID Weight
0x01 1 1000
0x02 3 1000
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))
account2, _ := c.GetAccount(ctx, flow.HexToAddress("02"))

key1 := account1.Keys[0]
key3 := account2.Keys[0]

// create signers from securely-stored private keys
key1Signer := getSignerForKey1()
key3Signer := getSignerForKey3()

tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer1: AuthAccount, signer2: AuthAccount) {
              log(signer.address)
              log(signer2.address)
          }
        }
    `)).
    SetGasLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetPayer(account2.Address).
    AddAuthorizer(account1.Address).
    AddAuthorizer(account2.Address)

// account 1 signs the payload with key 1
err := tx.SignPayload(account1.Address, key1.Index, key1Signer)

// account 2 signs the envelope with key 3
// note: payer always signs last
err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer)

Full Runnable Example


  • Proposer and authorizer are the same account (0x01).
  • Payer is a separate account (0x02).
  • Account 0x01 signs the payload.
  • Account 0x02 signs the envelope.
    • Account 0x02 must sign last since it is the payer.
  • Both accounts must sign twice (once with each of their keys).
Account Key ID Weight
0x01 1 500
0x01 2 500
0x02 3 500
0x02 4 500
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))
account2, _ := c.GetAccount(ctx, flow.HexToAddress("02"))

key1 := account1.Keys[0]
key2 := account1.Keys[1]
key3 := account2.Keys[0]
key4 := account2.Keys[1]

// create signers from securely-stored private keys
key1Signer := getSignerForKey1()
key2Signer := getSignerForKey1()
key3Signer := getSignerForKey3()
key4Signer := getSignerForKey4()

tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer: AuthAccount) { log(signer.address) }
        }
    `)).
    SetGasLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetPayer(account2.Address).
    AddAuthorizer(account1.Address)

// account 1 signs the payload with key 1
err := tx.SignPayload(account1.Address, key1.Index, key1Signer)

// account 1 signs the payload with key 2
err = tx.SignPayload(account1.Address, key2.Index, key2Signer)

// account 2 signs the envelope with key 3
// note: payer always signs last
err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer)

// account 2 signs the envelope with key 4
// note: payer always signs last
err = tx.SignEnvelope(account2.Address, key4.Index, key4Signer)

Full Runnable Example

Sending a Transaction

You can submit a transaction to the network using the Access API client.

import "github.com/onflow/flow-go-sdk/access"

// connect to an emulator running locally
c, err := client.New("localhost:3569")
if err != nil {
    panic("failed to connect to emulator")
}

ctx := context.Background()

err = c.SendTransaction(ctx, tx)
if err != nil {
    panic("failed to send transaction")
}

Querying Transaction Results

After you have submitted a transaction, you can query its status by ID:

result, err := c.GetTransactionResult(ctx, tx.ID())
if err != nil {
    panic("failed to fetch transaction result")
}

The result includes a Status field that will be one of the following values:

  • UNKNOWN - The transaction has not yet been seen by the network.
  • PENDING - The transaction has not yet been included in a block.
  • FINALIZED - The transaction has been included in a block.
  • EXECUTED - The transaction has been executed but the result has not yet been sealed.
  • SEALED - The transaction has been executed and the result is sealed in a block.
if result.Status == flow.TransactionStatusSealed {
  fmt.Println("Transaction is sealed!")
}

The result also contains an Error that holds the error information for a failed transaction.

if result.Error != nil {
    fmt.Printf("Transaction failed with error: %v\n", result.Error)
}

Querying Blocks

You can use the GetLatestBlock method to fetch the latest sealed or unsealed block:

// fetch the latest sealed block
isSealed := true
latestBlock, err := c.GetLatestBlock(ctx, isSealed)
if err != nil {
    panic("failed to fetch latest sealed block")
}

// fetch the latest unsealed block
isSealed := false
latestBlock, err := c.GetLatestBlock(ctx, isSealed)
if err != nil {
    panic("failed to fetch latest unsealed block")
}

A block contains the following fields:

  • ID - The ID (hash) of the block.
  • ParentBlockID - The ID of the previous block in the chain.
  • Height - The height of the block in the chain.
  • CollectionGuarantees - The list of collections included in the block.

Executing a Script

You can use the ExecuteScriptAtLatestBlock method to execute a read-only script against the latest sealed execution state.

This functionality can be used to read state from the blockchain.

Scripts must be in the following form:

  • A single main function with a single return value

This is an example of a valid script:

fun main(): Int { return 1 }
import "github.com/onflow/cadence"

script := []byte("fun main(): Int { return 1 }")

value, err := c.ExecuteScriptAtLatestBlock(ctx, script, nil)
if err != nil {
    panic("failed to execute script")
}

ID := value.(cadence.Int)

// convert to Go int type
myID := ID.Int()

Querying Events

You can query events with the GetEventsForHeightRange function:

import "github.com/onflow/flow-go-sdk/access"

blocks, err := c.GetEventsForHeightRange(ctx, client.EventRangeQuery{
    Type:       "flow.AccountCreated",
    StartHeight: 10,
    EndHeight:   15,
})
if err != nil {
    panic("failed to query events")
}

Event Query Format

An event query includes the following fields:

Type

The event type to filter by. Event types are namespaced by the account and contract in which they are declared.

For example, a Transfer event that was defined in the Token contract deployed at account 0x55555555555555555555 will have a type of A.0x55555555555555555555.Token.Transfer.

Read the language documentation for more information on how to define and emit events in Cadence.

StartHeight, EndHeight

The blocks to filter by. Events will be returned from blocks in the range StartHeight to EndHeight, inclusive.

Event Results

The GetEventsForHeightRange function returns events grouped by block. Each block contains a list of events matching the query in order of execution.

for _, block := range blocks {
    fmt.Printf("Events for block %s:\n", block.BlockID)
    for _, event := range block.Events {
        fmt.Printf(" - %s", event)
    }
}

Querying Accounts

You can query the state of an account with the GetAccount function:

import "github.com/onflow/flow-go-sdk"

address := flow.HexToAddress("01")

account, err := c.GetAccount(ctx, address)
if err != nil {
    panic("failed to fetch account")
}

A flow.Account contains the following fields:

  • Address: flow.Address - The account address.
  • Balance: uint64 - The account balance.
  • Code: []byte - The code deployed at this account.
  • Keys: []flow.AccountKey - A list of the public keys associated with this account.

Examples

The examples directory contains code samples that use the SDK to interact with the Flow Emulator.

flow-go-sdk's People

Contributors

10thfloor avatar aturx avatar bfbachmann avatar bjartek avatar bluesign avatar bthaile avatar chasefleming avatar dependabot[bot] avatar dsainati1 avatar franklywatson avatar harleyapplechoi avatar ianthpun avatar janezpodhostnik avatar joshuahannan avatar jribbink avatar kay-zee avatar laynelafrance avatar m4ksio avatar mrbrianhobo avatar nozim avatar nvdtf avatar peterargue avatar philipstanislaus avatar psiemens avatar savetherbtz avatar sideninja avatar supuns avatar tarakby avatar turbolent avatar yenteh-genies avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flow-go-sdk's Issues

Retry functionality

In my own subclass of client.Client I've added versions of some of the methods that handle retries; they use a WaitForConnectivity method that I call that uses exponential backoff to wait until Ping() is successful.

Is something like this in-scope for the base SDK, and if so, what should the implementation look like?

(I'm unsure if this is better handled via the gRPC Context but I'm not sure if I quite grok how that would work yet...)

Add ability to decode RLP encoded transactions

Is your feature request related to a problem? Please describe.
Some easy method of passing transaction data to and from software using the SDK is required to allow things like multi-sig transactions to be done more easily across machines/services.

Currently, there is a way to RLP encode the transactions, but no easy way to decode it in the SDK

Describe the solution you'd like
Add RLP decoding, which would just reverse the encoding

Describe alternatives you've considered
Only thing to consider is how the canonical forms are handled. Whether they should stay as embedded structs, or be pulled out as private structs

Additional context
Blocker for easy multi sig transactions using go sdk

flow.DefaultHasher is not thread safe

Problem

The flow.Transaction#ID method can produce inconsistent results when being called for different flow.Transaction instances in separate routines. This is due to a race condition in flow.DefaultHasher, a global singleton used to generate all hashes.

Support for ExecuteScriptAtLatestBlock

Stolen from the [https://github.com/onflow/flow-go-sdk#querying-blocks] ExecuteScriptAtLatestBlock method to execute a read-only script against the latest sealed execution state.

Transaction status code does not match transaction status

Instructions

Please fill out the template below to the best of your ability and include a label indicating which tool/service you were working with when you encountered the problem.

Problem

I'm fetching a transaction result via RPC.
The status text is SEALED but the status code is 0.
Expected status code to be 4.
I'm using the Emulator version 0.4.0
The status code is 0 both on account creation transactions and on account code update transactions.

Steps to Reproduce

<Access::TransactionResultResponse: status: :SEALED, status_code: 0, error_message: "", events: [<Entities::Event: type: "flow.AccountCodeUpdated", transaction_id: "\xF8\xA8\x8C]L\xE6J\x8A\tUP\xD9\b'2,\x92=\xB9\x95\xB6t\xED]\x87[\xBFZS\xE8\x87y", transaction_index: 1, event_index: 0, payload: "{\"type\":\"Event\",\"value\":{\"id\":\"flow.AccountCodeUpdated\",\"fields\":[{\"name\":\"address\",\"value\":{\"type\":\"Address\",\"value\":\"0xf4a3472b32eac8d8\"}},{\"name\":\"codeHash\",\"value\":{\"type\":\"Array\",\"value\":[{\"type\":\"UInt8\",\"value\":\"108\"},{\"type\":\"UInt8\",\"value\":\"228\"},{\"type\":\"UInt8\",\"value\":\"7\"},{\"type\":\"UInt8\",\"value\":\"41\"},{\"type\":\"UInt8\",\"value\":\"40\"},{\"type\":\"UInt8\",\"value\":\"251\"},{\"type\":\"UInt8\",\"value\":\"190\"},{\"type\":\"UInt8\",\"value\":\"50\"},{\"type\":\"UInt8\",\"value\":\"157\"},{\"type\":\"UInt8\",\"value\":\"76\"},{\"type\":\"UInt8\",\"value\":\"91\"},{\"type\":\"UInt8\",\"value\":\"143\"},{\"type\":\"UInt8\",\"value\":\"220\"},{\"type\":\"UInt8\",\"value\":\"173\"},{\"type\":\"UInt8\",\"value\":\"168\"},{\"type\":\"UInt8\",\"value\":\"196\"},{\"type\":\"UInt8\",\"value\":\"194\"},{\"type\":\"UInt8\",\"value\":\"62\"},{\"type\":\"UInt8\",\"value\":\"151\"},{\"type\":\"UInt8\",\"value\":\"194\"},{\"type\":\"UInt8\",\"value\":\"110\"},{\"type\":\"UInt8\",\"value\":\"238\"},{\"type\":\"UInt8\",\"value\":\"191\"},{\"type\":\"UInt8\",\"value\":\"2\"},{\"type\":\"UInt8\",\"value\":\"119\"},{\"type\":\"UInt8\",\"value\":\"173\"},{\"type\":\"UInt8\",\"value\":\"247\"},{\"type\":\"UInt8\",\"value\":\"106\"},{\"type\":\"UInt8\",\"value\":\"67\"},{\"type\":\"UInt8\",\"value\":\"136\"},{\"type\":\"UInt8\",\"value\":\"100\"},{\"type\":\"UInt8\",\"value\":\"213\"}]}},{\"name\":\"contracts\",\"value\":{\"type\":\"Array\",\"value\":[{\"type\":\"String\",\"value\":\"A.f4a3472b32eac8d8.HelloWorld\"}]}}]}}\n">]> 
2.7.1 :013 > 

Acceptance Criteria

Context

<what are you currently working on that this is blocking?>

Error with StartHeight, EndHeight Params for GetEventsForHeightRange function

Problem

I'm using flow-go-sdk to interact with nba-smart-contracts.

I'm able to successfully establish a connection using the client and query off the top of the blockEvents, however when attempting to query for a start height less than approx the current height - 10000, the function returns "exit status 2".

Steps to Reproduce

	flowClient, err := client.New("access.mainnet.nodes.onflow.org:9000", grpc.WithInsecure())
	handleErr(err)
	ctx := context.Background()
	err = flowClient.Ping(ctx)
	handleErr(err)

	// get the latest block
	latestBlock, err := flowClient.GetLatestBlock(ctx, false)
	handleErr(err)
	fmt.Println("Current height: ", latestBlock.Height)

	currentHeight := latestBlock.Height

        blockEvents, err := flowClient.GetEventsForHeightRange(ctx, client.EventRangeQuery{
			        Type: "A.0b2a3299cc857e29.TopShot.PlayCreated",
			        StartHeight: currentHeight - 10000, // if this is > 10000 the function breaks
			        EndHeight: currentHeight,
		        })
		        if err != nil {
			        panic("Failed to query events")
		        }

Acceptance Criteria

Ability to query further historical event data on flow blockchain.

Context

Blocking ability to complete historical analysis on nba top shots.

Improve errors returned by Access API Client

Is your feature request related to a problem? Please describe.

The Access API client (client.Client) currently wraps gRPC errors using the %w formatting directly. Unfortunately this strips out the gRPC status code (ref: grpc/grpc-go#2934).

Describe the solution you'd like

Client should return errors that can be inspected by the caller to unpack more information about the type and cause of the error.

Describe alternatives you've considered

We considered returning the gRPC errors directly.

Include domain tag when signing transactions

When signing a transaction, the message being signed should be prefixed with the transaction domain tag (TBD).

The tag should be prepended to the byte slice returned by the PayloadMessage() and EnvelopeMessage() functions on flow.Transaction.

Definition of Done

  • PayloadMessage produces a message that is prefixed with the transaction domain tag
  • EnvelopeMessage produces a message that is prefixed with the transaction domain tag

cc @tarakby

Transaction argument encoding is not consistent with other SDKs

Problem

The flow.Transaction type holds arguments typed as cadence.Value, which means that the encoded form is not realized until the transaction is serialized for the wire or for hashing. This alone does not cause problems with the Go SDK, given that the Go's builtin JSON implementation is deterministic (the same arguments are encoded the same way every time).

However, if a user imports a transaction generated by the JavaScript SDK, decodes the arguments, and the constructs a flow.Transaction object, the final serialized format is not guaranteed to match the original transaction created in JS (i.e. differences in whitespace, indentation, etc.). This also means that the hashes will not match and all signatures will be invalid.

Given that JSON-CDC was not designed as a deterministic byte-wise encoding format, it does not make sense to expect the encoding to stay perfectly consistent across implementations. Thus, the Go SDK should represent transactions in a completely lossless way and avoid re-encoding arguments.

Client: Add the ability to pass in gRPC call options

Is your feature request related to a problem? Please describe.
I can't find a way to add in gRPC call options for client.Client methods right now, this made retrieving some data from the blockchain impossible for huge blocks / transactions.

For example, calling GetTransactionResult for the transaction with the hash b25c5a82b4dc9d6dfd2f7eb2016d272ae4b8f03d65a1803c437b046547f3893f in the testnet would cause an error: client: rpc error: code = ResourceExhausted desc = grpc: received message larger than max (7714488 vs. 4194304)

The solution is to increase the gRPC inbound message maximum limit with grpc.MaxCallRecvMsgSize, but there's no way to do this at the moment.

Describe the solution you'd like
Provide a way to pass in gRPC call options for several client.Client methods where message size could be an issue (GetTransactionResult in my case).

Something like func (c *Client) GetTransactionResult(ctx context.Context, txID flow.Identifier, opts ...grpc.CallOption) so that it won't be a breaking change.

Support standard PKIX, ASN.1 DER key formats

Is your feature request related to a problem? Please describe.
Currently users have to manually encode EC keys by appending their parameters in order to create crypto.PublicKeys with the SDK.

pemKey :=  []byte(`-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUxHNDevkyBG2RfEZNfPr1zNtBtSD
fcrdBwjOU1VvI/p8/yUD35nm2tUaHwaFkM34kW7/ey5JuRc7qGKUhb9Esg==
-----END PUBLIC KEY-----
`)

block, _ := pem.Decode(pemKey)
if block == nil || block.Type != "PUBLIC KEY" {
    panic("Unable to decode PEM block containing public payer pub key")
}

pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
    panic(err)
}
pubKey := pub.(*ecdsa.PublicKey)

_, err = crypto.DecodePublicKey(crypto.ECDSA_P256, append(pubKey.X.Bytes(), pubKey.Y.Bytes()...))
if err != nil {
    panic("Could not decode public payer pub key: " + err.Error())
}

Describe the solution you'd like
The SDK should support this through a similar interface to Go's x509.ParsePKIXPublicKey. I also ask that you make your compressed key encoding scheme clear in your godoc.

Describe alternatives you've considered

Additional context
You used to be able to pass the PKIX, ASN.1 DER encoding to crypto.DecodePublicKey in the old SDK, so I consider this a regression.

Block and BlockHeader methods not compatible with current mainnet release

Instructions

Problem

The Flow Go SDK v0.4.0 breaks when calling the GetBlock... and GetBlockHeader methods of the Access API currently exposed by candidate mainnet.

Steps to Reproduce

For example, the following error is returned when querying GetLatestBlockHeader:

GetLatestBlockHeader: client: timestamp: nil Timestamp

Context

This happens because the current deployed Access API does not include a timestamp in the block header response.

ExecuteScriptAtLatestBlock ignores arguments on devenet

Instructions

Problem

It looks like the arguments sent to scripts to devnet are beeing swallowed.

Error message
2020/08/29 18:52:15 Arguments [foo] 2020/08/29 18:52:16 💩 Error executing script: block output client: rpc error: code = Internal desc = failed to execute the script on the execution node: rpc error: code = Internal desc = failed to execute script: failed to execute script at block (9a4a4b1785007b2ff9d8064231033bda0f7b0cb78073aab1d7d7b377dca4970e): Execution failed: entry point parameter count mismatch: expected 1, got 0 exit status 1

On Emulator the same works fine.

Steps to Reproduce

  1. check out the devnet branch of https://github.com/versus-flow/go-flow-tooling
  2. cd to the example directory
  3. go run example.go

The master branch has an example running against localhost.

Acceptance Criteria

Arguments are sent to devnet

Context

Deploying OWB project to devnet

Update to latest Access API sepc

Is your feature request related to a problem? Please describe.
Access API has been updated recently. Flow-go-sdk needs to be updated to use the latest api.

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

createSignature() might be generating incorrect signerIndex when called through AddPayloadSignature

Instructions

https://github.com/dapperlabs/dapper-flow-api/pull/1586/files

When generating a transaction from an FCL interaction, we call the AddPayloadSignature function rather than SignPayload

It seems that if AddPayloadSignature is called before all the Payer/Proposer/Authorizers are set, there's a chance that the createSignature function does not put the correct signerIndex in the field. The PR above was seeing multiple signerIndex of 0

Problem

Inconsistent transaction state, based on the order of setting payer, proposer, authorizer, and adding signatures. Order should matter here. Depending on when the authorizers are added, and signatures added, we ended up with a different tx hash.

Steps to Reproduce

Have an address be payer and an authorizer, create the signatures, then try creating new transactions where you:

add authorizer
add authorizer signature
set payer
add payer signature

Acceptance Criteria

Should be able to add signatures at any time, and the eventual transaction should always hash to the same value

Consider exposing `languageEncodeBytesArray`

Is your feature request related to a problem? Please describe.
I have a custom account creation script (I am not using examples.CreateAccount), but I need to encode my account public key in the right format in my script. To do so I needed to essentially re-implement a function you already have in flow-go-sdk: languageEncodeBytesArray.

Describe the solution you'd like
I figured it might be convenient for users like me if you exposed the languageEncodeBytesArray fucntion.

Describe alternatives you've considered
I just re-implemented the function myself for now, which honestly is fine.

Additional context
I have none, I'm afraid.

Documentation bug

Problem

I believe there is a bug in the transaction file in the docs. I tried to copy-paste the content and I got the following error:

 --> db9f86f00981f450bbf91c9d36657e138e59fd989132f43c4a49b921b9d48f04:9:36
  |
9 |     log(greeting.concat(",").concat(guest.toString()))
  |                                     ^^^^^ not found in this scope 

I had to fix the transaction to:

...
    log(greeting.concat(",").concat(self.guest.toString()))
...

Add support for querying blocks near a timestamp

Is your feature request related to a problem? Please describe.
Would like to query chain state via ExecuteScript at the last block before a given timestamp. Currently, this involves finding the block corresponding to the desired timestamp on the application side.

Describe the solution you'd like
GetBlockBeforeTimestamp and GetBlockAfterTimestamp endpoints. Possibly even ExecuteScriptBeforeTimestamp/ExecuteScriptAfterTimestamp.

Describe alternatives you've considered
Current alternative I'm using is performing a binary search from latest block to 0 in order to find the block just before a timestamp. However, this pushes extra processing/complexity to the application.

Additional context

crypto: use flow-go/crypto instead of internal

Context

The SDK used its own copy of the crypto code because it got open-sourced while flow-go was still private. That shouldn't be the case anymore as flow-go became public.

Definition of done

Delete flow-go-sdk/crytpo/internal and use onflow/flow-go/crypto instead.

Amount exceeds the allowed max gas limit

In the GoSDK the transaction fees are set inuint64

func (t *Transaction) SetGasLimit(limit uint64) *Transaction {

When quering an account balance I get the balance at a scale of 1/100,000,000 so I assume it's stored as UFix64.

The recommended amount of Flow to send for gas on testnet is: 0.1 F, which adjusted to scale would mean: 10,000,000.

When seting the gas to 10,000,000 for a transaction on testnet I get a max gas limit exceeded error.

client: rpc error: code = Internal desc = failed to send transaction to a collection node: 3 errors occurred:\n\t* failed to send transaction to collection node at collection-016.devnet14.nodes.onflow.org:9000: rpc error: code = Unknown desc = invalid transaction: transaction's gas limit (10000000) exceeds the allowed max gas limit (9999)\n\t* failed to send transaction to collection node at collection-018.devnet14.nodes.onflow.org:9000: rpc error: code = Unknown desc = invalid transaction: transaction's gas limit (10000000) exceeds the allowed max gas limit (9999)\n\t* failed to send transaction to collection node at collection-014.devnet14.nodes.onflow.org:9000: rpc error: code = Unknown desc = invalid transaction: transaction's gas limit (10000000) exceeds the allowed max gas limit (9999)\n\n

invalid contract: Checking failed, not very helpfull error message

Instructions

When trying to deploy a contract that used to work https://github.com/versus-flow/auction-flow-contract/blob/upgrade-flow/contracts/Auction.cdc i now get an error that is not helpfull

Problem

The error message says:

DEBU[0079] ️✉️   Transaction submitted                   txID=468e7ba9ec94691de9d59303dc135150fe83dfef1859c61ccde4d91287673f48
ERROR Execution failed:
invalid contract: Checking failed

WARN[0079] ❗  Transaction reverted    ```

### Steps to Reproduce 

1. Check out https://github.com/versus-flow/auction-flow-contract/tree/upgrade-flow
2. Use v0.11.2 of the flow emulator
3. In one terminal run ```make emulator```
4. In another terminal run ```make demo```

### Acceptance Criteria

There is an error message thrown that makes it easier to understand what is wrong with the contract
  

Broken links in documentation

Is your issue related to a problem? Please describe.
I'm trying to read up on some of the documentation for the flow blockchain and tooling. However, there are some links that are broken and lead to 404 responses. The links that I have found so far are the following:

Repositories:

Flow-SDK README.md

  • Flow Emulator link leads to a 404 page
  • multiple parties two authorizers in the TOC do not lead anywhere (not a big problem because I see it when I scroll the page).
  • Read the language documentation leads to a 404 page
  • Emulator.md leads to 404 page

Flow README.md

  • Using the Emulator leads to a 404 page

Describe the solution you'd like
FIx the links.

Describe alternatives you've considered
Point me in the right direction and I'll fix it myself and send a PR.

Additional context
N/A

Event query works differently on emulator and devnet

Introduction

Problem

When doing an query to get events without specifying a type field the following happends:

  • emulator returns all event types
  • devnet returns no events

Steps to Reproduce

Perform and event query with no parameters specified in the event query struct.

Acceptance Criteria

Document the difference. Return error if not allowed.

Expand access node API

Is your feature request related to a problem? Please describe.
It's pretty hard to get information about what's going on-chain from access nodes (and thus the SDK) at the moment. Here are some things I'd like to be able to do, but currently can't:

  1. Get transactions by block ID
  2. Get transactions by signer account ID (this is probably hard)
  3. Get block ID by transaction hash

Describe the solution you'd like
Implement 1, 3 and maybe 2. 1 is definitely more useful.

Describe alternatives you've considered
There aren't any. Without 1 at the very least, it's impossible for an observer to know about an arbitrary transaction on chain without being given its ID by someone else.

Additional context
Add any other context or screenshots about the feature request here.

Make event query more flexible

Currently the GetEventsForHeightRange API only lets you filter for a specific type of events.

Therefore, in order to find all events from a specific contract, I currently have to either:

  • Get all events in the block range and manually filter them
  • Or fire multiple GetEventsForHeightRange calls, one for each event type from the contract.

It would be great if we could:

  • Get all events from a contract
  • Get all events from an account
  • Get events of multiple types

Put FlowClient behind an interface

Is your feature request related to a problem? Please describe.
Right now the Flow client is just a struct, so mocking it in tests it quite difficult.

Describe the solution you'd like
Ideally the client exposes a concrete interface that we can mock out if we want to.

Describe alternatives you've considered
Developers who wish to mock out the client could also wrap it in their own interface, but they really shouldn't have to do that imo.

Additional context
Add any other context or screenshots about the feature request here.

Emulator crash

Instructions

Please fill out the template below to the best of your ability and include a label indicating which tool/service you were working with when you encountered the problem.

Problem

I've tried the JS wallet demo, run an example and crashed the Emulator.
I'm using the latest version of the Emulator.

Steps to Reproduce

I've run this code locally. The HelloWorld contract is not deployed.

const response = await fcl.send([
    sdk.script`
	import HelloWorld from 0x02

	pub fun main() {
	    let helloAccount = getAccount(0x02)
	    let helloCapability = helloAccount.getCapability(/public/Hello)
	    let helloReference = helloCapability!.borrow<&HelloWorld.HelloAsset>()

	    log(helloReference?.hello())
	}
    `,
])
no code deployed at address  
panic: cannot convert value of type <nil>

goroutine 78 [running]:
github.com/onflow/cadence.convertValue(0x0, 0x0, 0x0, 0x0, 0x0)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/onflow/cadence/convert_values.go:109 +0xf71
github.com/onflow/cadence.ConvertValue(...)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/onflow/cadence/convert_values.go:33
github.com/dapperlabs/flow-emulator.(*computer).ExecuteScript(0xc0002c0740, 0xc00062c1e0, 0xc000046d40, 0x37, 0x40, 0x0, 0x5a34698, 0x0)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/dapperlabs/flow-emulator/computer.go:145 +0x548
github.com/dapperlabs/flow-emulator.(*Blockchain).ExecuteScriptAtBlock(0xc00024b220, 0xc000046d40, 0x37, 0x40, 0x0, 0x0, 0x0, 0x0)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/dapperlabs/flow-emulator/blockchain.go:624 +0x124
github.com/dapperlabs/flow-emulator/server.(*Backend).executeScriptAtBlock(0xc0002c0760, 0xc000046d40, 0x37, 0x40, 0x0, 0x4f2eca0, 0xc000310240, 0xc00006fa10)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/dapperlabs/flow-emulator/server/backend.go:429 +0x7d
github.com/dapperlabs/flow-emulator/server.(*Backend).ExecuteScriptAtLatestBlock(0xc0002c0760, 0x4f3d360, 0xc000726390, 0xc0002d6d00, 0xc0002c0760, 0x6688e38, 0xc000310240)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/dapperlabs/flow-emulator/server/backend.go:278 +0x15e
github.com/onflow/flow/protobuf/go/flow/access._AccessAPI_ExecuteScriptAtLatestBlock_Handler.func1(0x4f3d360, 0xc000726390, 0x4cc9fa0, 0xc0002d6d00, 0x2c, 0xc0004d2230, 0x0, 0xc00006fad0)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/onflow/flow/protobuf/go/flow/access/access.pb.go:1781 +0x86
github.com/grpc-ecosystem/go-grpc-prometheus.(*ServerMetrics).UnaryServerInterceptor.func1(0x4f3d360, 0xc000726390, 0x4cc9fa0, 0xc0002d6d00, 0xc0007e2b20, 0xc0007e2b40, 0xc00006fb40, 0x41097b8, 0x4cbc1e0, 0xc000726390)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_metrics.go:107 +0xad
github.com/onflow/flow/protobuf/go/flow/access._AccessAPI_ExecuteScriptAtLatestBlock_Handler(0x4d41040, 0xc0002c0760, 0x4f3d360, 0xc000726390, 0xc00008a300, 0xc000268310, 0x4f3d360, 0xc000726390, 0xc000046d00, 0x39)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/github.com/onflow/flow/protobuf/go/flow/access/access.pb.go:1783 +0x14b
google.golang.org/grpc.(*Server).processUnaryRPC(0xc0001d16c0, 0x4f4d1c0, 0xc0000c2630, 0xc000362200, 0xc0002cc390, 0x5a069c0, 0x0, 0x0, 0x0)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/google.golang.org/grpc/server.go:1082 +0x4fd
google.golang.org/grpc.(*Server).handleStream(0xc0001d16c0, 0x4f4d1c0, 0xc0000c2630, 0xc000362200, 0x0)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/google.golang.org/grpc/server.go:1405 +0xd23
google.golang.org/grpc.(*Server).serveStreams.func1.1(0xc000814410, 0xc0001d16c0, 0x4f4d1c0, 0xc0000c2630, 0xc000362200)
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/google.golang.org/grpc/server.go:746 +0xbb
created by google.golang.org/grpc.(*Server).serveStreams.func1
	/Users/petersiemens/go/src/github.com/dapperlabs/flow-cli/vendor/google.golang.org/grpc/server.go:744 +0xa1

Acceptance Criteria

Context

Trying the JS wallet demo.

View unsealed transaction or collection script?

Is your feature request related to a problem? Please describe.

As far as I can tell, it is not possible to view unsealed transaction info with the SDK. I also cannot tell if an unsealed transaction is the same as a collection guarantee. Is the collection ID the same as what the transaction ID will be once the collection is sealed into a block?

I am obtaining collection guarantees via flowClient.GetLatestBlock. From there, I receive CollectionGuarantees, which each carry an ID. I then send the collection ID to flowClient.GetTransaction but never receive a valid transaction. Checking the transaction result using the collection ID also fails so I assume these are not interchangeable.

	flowClient, err := client.New("access.mainnet.nodes.onflow.org:9000", grpc.WithInsecure())
	unsealedBlocks, err := flowClient.GetLatestBlock(context.Background(), false)
	for _, collection := range unsealedBlocks.CollectionGuarantees {
		log.Println("Unsealed TX ID ", collection.CollectionID.String())

		txresult, err := flowClient.GetTransactionResult(context.Background(), collection.CollectionID)
		log.Println(txresult.Status)

                //wait some seconds for the transaction to confirm?
		time.Sleep(time.Second * 20)
		tx, err := flowClient.GetTransaction(context.Background(), collection.CollectionID)
		txstring := string(tx.Script)
		log.Println(txstring)
	}

Describe the solution you'd like

  • An explanation and distinction between collection guarantees and transactions.
  • Information on accessing the script of pending transactions.

Add support for querying and parsing built-in events

Flow defines the following built-in system events which are emitted when creating and updating accounts:

"flow.AccountCreated"
"flow.AccountKeyAdded"
"flow.AccountKeyRemoved"
"flow.AccountCodeUpdated"

The SDK should provide support for querying and parsing these events. Currently the SDK supports flow.AccountCreated and the (now deprecated) flow.AccountUpdated event, but it should should all four events above.

For reference, these events are defined in Cadence here: https://github.com/onflow/cadence/blob/30a200f9c324a208336e233b8b3293370a68a3ed/runtime/stdlib/flow_builtin.go#L219-L246

Definition of Done

  • A user can query events of type flow.AccountCreated
  • A user can query events of type flow.AccountKeyAdded
  • A user can query events of type flow.AccountKeyRemoved
  • A user can query events of type flow.AccountCodeUpdated
  • A user can read all fields on event of type flow.AccountCreated as native Go values
  • A user can read all fields on event of type flow.AccountKeyAdded as native Go values
  • A user can read all fields on event of type flow.AccountKeyRemoved as native Go values
  • A user can read all fields on event of type flow.AccountCodeUpdated as native Go values
  • A user can read documentation for the following built-in events:
    • flow.AccountCreated
    • flow.AccountKeyAdded
    • flow.AccountKeyRemoved
    • flow.AccountCodeUpdated

Incorrect transaction signature ordering

Problem

The compareSignatures function used to sort transaction signatures does not work as intended.

Steps to Reproduce

When reconstructing this transaction from JSON, the resulting PayloadSignature list is out of order:

TX: {
    "Script": "dHJhbnNhY3Rpb24geyBwcmVwYXJlKGFjY3Q6IEF1dGhBY2NvdW50KSB7IGxvZygidGVzdCIpIH0gfQ==",
    "Arguments": null,
    "ReferenceBlockID": [
        98,
        239,
        207,
        132,
        153,
        68,
        2,
        217,
        35,
        124,
        96,
        24,
        12,
        12,
        138,
        153,
        193,
        11,
        200,
        251,
        2,
        107,
        90,
        232,
        6,
        129,
        40,
        132,
        206,
        70,
        119,
        145
    ],
    "GasLimit": 9999,
    "ProposalKey": {
        "Address": "045a1763c93006ca",
        "KeyIndex": 8,
        "SequenceNumber": 0
    },
    "Payer": "f8d6e0586b0a20c7",
    "Authorizers": [
        "e03daebed8ca0615"
    ],
    "PayloadSignatures": [
        {
            "Address": "e03daebed8ca0615",
            "SignerIndex": 2,
            "KeyIndex": 0,
            "Signature": "i163yvJQjY2cZEhIjDZ2FJWScXT3ICO/HSXYcLkKrwjLsnbZYZD84N2fmdaQPgR8R4iA5pu/N9hR/BoTLunubA=="
        },
        {
            "Address": "045a1763c93006ca",
            "SignerIndex": 0,
            "KeyIndex": 8,
            "Signature": "zyLRWunnkwncc3wsfkXhTqC6AMJXRFcpgQ4OYJR3vp1MQ/Od8YCsE00enOU/WYMlLz0bXi0KzWaoOE5pOsi6ig=="
        }
    ],
    "EnvelopeSignatures": [
        {
            "Address": "f8d6e0586b0a20c7",
            "SignerIndex": 1,
            "KeyIndex": 0,
            "Signature": "t0mNo6ckUOnMH0c+vCj8nOkfrlMWtyF0pD0bVuDwO2rxF+z7uk8lBncDY9jBi4zbeLturBctobMEMwQ6VM2uUg=="
        }
    ]
}

Context

Reported by @omatvejev.

create_account err.

rpc error: code = InvalidArgument desc = address 9125ec0636c0b042 is invalid for chain flow-mainnet

Flow emulator for Go examples fails to start

Problem

The Flow emulator fails to start in the examples directory due to an incorrect ECDSA_P256 key size.

Steps to Reproduce

➜  ~/flow-go-sdk/examples> flow emulator start -v
> invalid project configuration: input has incorrect ECDSA_P256 key size

Editing flow.json to match the schema of the config file found in the kitties-items repo allows it to start, but then the examples.go file fails to run.

{
  "emulators": {
    "default": {
      "port": 3569,
      "serviceAccount": "emulator-account"
    }
  },
  "accounts": {
    "emulator-account": {
      "address": "f8d6e0586b0a20c7",
      "keys": "fd987817c2f796143ce97853c104b29b5e6d19747232b391033a7ddf511e355b",
      "chain": "flow-emulator"
    }
  },
  "contracts": {
    "FlowServiceAccount": "f8d6e0586b0a20c7",
    "FlowFees": "e5a8b7f23e8b548f",
    "FlowStorageFees": "f8d6e0586b0a20c7",
    "FlowToken": "0ae53cb6e3f42a79",
    "FungibleToken": "ee82856bf20e2aa6"
  }
}

➜  ~/flow-go-sdk/examples git:(master) ✗ make create-account
go run ./create_account/main.go
err: decode private key failed: the signature scheme UNKNOWN is not supported
panic: decode private key failed: the signature scheme UNKNOWN is not supported

goroutine 1 [running]:
github.com/onflow/flow-go-sdk/examples.Handle(0x194bb60, 0xc0002a4100)
	/Users/kevin/Development/searanchlabs/flow-go-sdk/examples/examples.go:243 +0xe9
github.com/onflow/flow-go-sdk/examples.ServiceAccount(0xc0002a2078, 0x0, 0xc000275d78, 0x1, 0x1)
	/Users/kevin/Development/searanchlabs/flow-go-sdk/examples/examples.go:91 +0xc5
main.CreateAccountDemo()
	/Users/kevin/Development/searanchlabs/flow-go-sdk/examples/create_account/main.go:43 +0xdb
main.main()
	/Users/kevin/Development/searanchlabs/flow-go-sdk/examples/create_account/main.go:35 +0x25
exit status 2
make: *** [create-account] Error 1

Acceptance Criteria

Flow emulator starts and running make create-account along with other examples completes without error.

Context

It looks like the schema for flow.json has been updated in the emulator but not in the examples code.

Support secp256k1 in DecodePublicKeyPEM

Is your feature request related to a problem? Please describe.
Currently, DecodePublicKeyPEM only supports P256, would be great to support both signing algs (i.e. add secp256k1 support)

Describe the solution you'd like
As described by @tarakby here: #175 (comment)

Describe alternatives you've considered
N/A

Additional context

The Seals property of BlockPayload is not implemented

Is your feature request related to a problem? Please describe.

The SDK currently does not fill the Seals property of BlockPayload, which would be nice to use for checking whether a block is sealed.

Describe the solution you'd like

This property should be filled out.

Describe alternatives you've considered

Yønder on the Discord told me I could check the sealed status of the transactions in the block instead, but I took a stab at implementing this in #147.

Additional context

image

image

Consistent parsing hex values

It would be helpful if all hex values passed to parsing functions would handle 0x prefix.
Currently flow.HexToAddress() handles 0x prefix.

Functions that currently don't:

  • flow.HexToID()
  • crypto.DecodePublicKeyHex() (not sure if it makes sense to handle prefix in this one)

Example is outdated

Instructions

Example is outdated

Problem

It is not possible to start the example with newest emulator since the flow.json format changed.

Steps to Reproduce

  • clone repo
  • cd example
  • flow emulator -v

Acceptance Criteria

It is possible to start the emulator and perform the tests using the example

Rate limits documentation

Problem

/flow.access.AccessAPI/GetEventsForHeightRange rate limit reached, please retry later.

Steps to Reproduce

Spam API calls.

Acceptance Criteria

Should report what is current rate limit for calling API or API endpoint should exist to report current rate limiting.

Context

I was playing around with blockchain events processor and since API is limited some calls must be made quite often (due to limited API functionality). It is unclear how often calling API is still acceptable.

gRPC Connection closed consistently

Instructions

NBA topshot client.
Start a client watching every second for latest block hight(1 second cooldown if same block). if a new block is detected, grab the listing and purchase events.

Problem

panic: rpc error: code = Unavailable desc = connection closed consistently after few minutes to up to hours

Acceptance Criteria

Not sure of the issue if server side or there is some kind of rate limit?! would appreciate is someone has more insights.

Steps

client: client.New("access.mainnet.nodes.onflow.org:9000", grpc.WithInsecure())
watched events: A.c1e4f4f4c4257510.Market.MomentListed A.c1e4f4f4c4257510.Market.MomentPurchased

Context

NBA topshot client.

Account Creation Example Failing With 0.11.1

Problem

make create account fails

Steps to Reproduce

Terminal 1

flow init
flow emulator start

Output:

INFO[0000] ⚙️   Using service account 0xf8d6e0586b0a20c7  serviceAddress=f8d6e0586b0a20c7 serviceHashAlgo=SHA3_256 servicePrivKey=XXXXXXXXXX serviceSigAlgo=ECDSA_P256
INFO[0000] 🌱  Starting gRPC server on port 3569          port=3569
INFO[0000] 🌱  Starting HTTP server on port 8080          port=8080
WARN[0008] ❗  Transaction reverted                       txID=d63972b3b0ebe78dd0cef20b02ef49432faeb46af1715c9c6936c32cadbb478f
WARN[0008] ERR [d63972] invalid signature: signature could not be verified using public key with index 0 on account f8d6e0586b0a20c7

Terminal 2

cd flow-go-sdk/examples
make create-account

Output:

Waiting for transaction d63972b3b0ebe78dd0cef20b02ef49432faeb46af1715c9c6936c32cadbb478f to be sealed...

Transaction d63972b3b0ebe78dd0cef20b02ef49432faeb46af1715c9c6936c32cadbb478f sealed
Account created with address: 0000000000000000

Register callbacks for new blocks

It would be good if we could register callbacks to be executed when a new block is minted/sealed. This will make building a blockchain event processor easier, for instance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.