flow

package module
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2021 License: Apache-2.0 Imports: 15 Imported by: 310

README

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.

English | Chinese

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

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

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 := crypto.NewInMemorySigner(myPrivateKey, myAccountKey.HashAlgo)

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.


Single party, single signature
  • 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 1.0
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


Single party, multiple signatures
  • Proposer, payer and authorizer are the same account (0x01).
  • Only the envelope must be signed.
  • Each key has weight 0.5, so two signatures are required.
Account Key ID Weight
0x01 1 0.5
0x01 2 0.5
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


Multiple parties
  • 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 1.0
0x02 3 1.0
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


Multiple parties, two authorizers
  • 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 1.0
0x02 3 1.0
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


Multiple parties, multiple signatures
  • 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 0.5
0x01 2 0.5
0x02 3 0.5
0x02 4 0.5
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/client"

// 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/client"

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.

Documentation

Overview

Package flow provides libraries and tools for building Go applications on Flow.

Index

Examples

Constants

View Source
const (
	EventAccountCreated         string = "flow.AccountCreated"
	EventAccountAdded           string = "flow.AccountKeyAdded"
	EventAccountKeyRemoved      string = "flow.AccountKeyRemoved"
	EventAccountContractAdded   string = "flow.AccountContractAdded"
	EventAccountContractUpdated string = "flow.AccountContractUpdated"
	EventAccountContractRemoved string = "flow.AccountContractRemoved"
)

List of built-in account event types.

View Source
const AccountKeyWeightThreshold int = 1000

AccountKeyWeightThreshold is the total key weight required to authorize access to an account.

View Source
const AddressLength = (linearCodeN + 7) >> 3

AddressLength is the size of an account address in bytes.

Variables

View Source
var EmptyAddress = Address{}

EmptyAddress is the empty address (0x0000000000000000).

View Source
var EmptyID = Identifier{}

EmptyID is the empty identifier.

View Source
var TransactionDomainTag = paddedDomainTag("FLOW-V0.0-transaction")

TransactionDomainTag is the prefix of all signed transaction payloads.

A domain tag is encoded as UTF-8 bytes, right padded to a total length of 32 bytes.

View Source
var UserDomainTag = paddedDomainTag("FLOW-V0.0-user")

UserDomainTag is the prefix of all signed user space payloads.

A domain tag is encoded as UTF-8 bytes, right padded to a total length of 32 bytes.

Functions

func SignUserMessage added in v0.7.0

func SignUserMessage(signer crypto.Signer, message []byte) ([]byte, error)

SignUserMessage signs a message in the user domain.

User messages are distinct from other signed messages (i.e. transactions), and can be verified directly in on-chain Cadence code.

Types

type Account

type Account struct {
	Address   Address
	Balance   uint64
	Code      []byte
	Keys      []*AccountKey
	Contracts map[string][]byte
}

An Account is an account on the Flow network.

type AccountCreatedEvent

type AccountCreatedEvent Event

An AccountCreatedEvent is emitted when a transaction creates a new Flow account.

This event contains the following fields: - Address: Address

func (AccountCreatedEvent) Address

func (evt AccountCreatedEvent) Address() Address

Address returns the address of the newly-created account.

type AccountKey

type AccountKey struct {
	Index          int
	PublicKey      crypto.PublicKey
	SigAlgo        crypto.SignatureAlgorithm
	HashAlgo       crypto.HashAlgorithm
	Weight         int
	SequenceNumber uint64
	Revoked        bool
}

An AccountKey is a public key associated with an account.

func DecodeAccountKey

func DecodeAccountKey(b []byte) (*AccountKey, error)

DecodeAccountKey decodes the RLP byte representation of an account key.

func NewAccountKey

func NewAccountKey() *AccountKey

NewAccountKey returns an empty account key.

func (AccountKey) Encode

func (a AccountKey) Encode() []byte

Encode returns the canonical RLP byte representation of this account key.

func (*AccountKey) FromPrivateKey

func (a *AccountKey) FromPrivateKey(privKey crypto.PrivateKey) *AccountKey

FromPrivateKey sets the public key and signature algorithm based on the provided private key.

func (*AccountKey) SetHashAlgo

func (a *AccountKey) SetHashAlgo(hashAlgo crypto.HashAlgorithm) *AccountKey

SetHashAlgo sets the hash algorithm for this account key.

func (*AccountKey) SetPublicKey

func (a *AccountKey) SetPublicKey(pubKey crypto.PublicKey) *AccountKey

SetPublicKey sets the public key for this account key.

func (*AccountKey) SetSigAlgo

func (a *AccountKey) SetSigAlgo(sigAlgo crypto.SignatureAlgorithm) *AccountKey

SetSigAlgo sets the signature algorithm for this account key.

func (*AccountKey) SetWeight

func (a *AccountKey) SetWeight(weight int) *AccountKey

SetWeight sets the weight for this account key.

func (AccountKey) Validate

func (a AccountKey) Validate() error

Validate returns an error if this account key is invalid.

An account key can be invalid for the following reasons: - It specifies an incompatible signature/hash algorithm pairing - It specifies a valid key weight

type Address

type Address [AddressLength]byte

Address represents the 8 byte address of an account.

func BytesToAddress

func BytesToAddress(b []byte) Address

BytesToAddress returns Address with value b.

If b is larger than 8, b will be cropped from the left. If b is smaller than 8, b will be appended by zeroes at the front.

func HexToAddress

func HexToAddress(h string) Address

HexToAddress converts a hex string to an Address.

func ServiceAddress added in v0.4.0

func ServiceAddress(chain ChainID) Address

ServiceAddress is the first generated account address.

func (Address) Bytes

func (a Address) Bytes() []byte

Bytes returns the byte representation of the address.

func (Address) Hex

func (a Address) Hex() string

Hex returns the hex string representation of the address.

func (*Address) IsValid added in v0.4.0

func (a *Address) IsValid(chain ChainID) bool

IsValid returns true if a given address is a valid account address, and false otherwise.

This is an off-chain check that only tells whether the address format is valid. If the function returns true, this does not mean a Flow account with this address has been generated. Such a test would require an on-chain check.

func (Address) MarshalJSON

func (a Address) MarshalJSON() ([]byte, error)

func (Address) String

func (a Address) String() string

String returns the string representation of the address.

func (*Address) UnmarshalJSON

func (a *Address) UnmarshalJSON(data []byte) error

type AddressGenerator added in v0.4.0

type AddressGenerator struct {
	// contains filtered or unexported fields
}

An AddressGenerator uses a deterministic algorithm to generate Flow addresses.

func NewAddressGenerator added in v0.4.0

func NewAddressGenerator(chainID ChainID) *AddressGenerator

NewAddressGenerator creates a new address generator for the given chain ID, starting from the zero address state.

Addresses are generated for a specific network (Flow mainnet, testnet, etc).

Each addressing state is mapped to exactly one address, meaning there are as many addresses as states. State values are incremented from 0 to 2^k-1.

func (*AddressGenerator) Address added in v0.4.0

func (gen *AddressGenerator) Address() Address

Address generates an account address at the current addressing state.

func (*AddressGenerator) Next added in v0.4.0

func (gen *AddressGenerator) Next() *AddressGenerator

Next increments the addressing state.

State values are incremented from 0 to 2^k-1.

func (*AddressGenerator) NextAddress added in v0.4.0

func (gen *AddressGenerator) NextAddress() Address

NextAddress increments the addressing state and generates an account address.

func (*AddressGenerator) SetIndex added in v0.4.0

func (gen *AddressGenerator) SetIndex(i uint) *AddressGenerator

SetIndex fast-forwards or rewinds the addressing state to the given index.

type Block

type Block struct {
	BlockHeader
	BlockPayload
}

Block is a set of state mutations applied to the Flow blockchain.

type BlockHeader

type BlockHeader struct {
	ID        Identifier
	ParentID  Identifier
	Height    uint64
	Timestamp time.Time
}

BlockHeader is a summary of a full block.

type BlockPayload

type BlockPayload struct {
	CollectionGuarantees []*CollectionGuarantee
	Seals                []*BlockSeal
}

BlockPayload is the full contents of a block.

A payload contains the collection guarantees and seals for a block.

type BlockSeal

type BlockSeal struct {
	// The ID of the block this Seal refers to (which will be of lower height than this block)
	BlockID Identifier

	// The ID of the execution receipt generated by the Verifier nodes; the work of verifying a
	// block produces the same receipt among all verifying nodes
	ExecutionReceiptID Identifier

	ExecutionReceiptSignatures [][]byte
	ResultApprovalSignatures   [][]byte
}

BlockSeal is the attestation by verification nodes that the transactions in a previously executed block have been verified.

type ChainID added in v0.4.0

type ChainID string

A ChainID is a unique identifier for a specific Flow network instance.

Chain IDs are used used to prevent replay attacks and to support network-specific address generation.

const Emulator ChainID = "flow-emulator"

Emulator is the chain ID for the emulated node chain.

const Mainnet ChainID = "flow-mainnet"

Mainnet is the chain ID for the mainnet node chain.

const Testnet ChainID = "flow-testnet"

Testnet is the chain ID for the testnet node chain.

func (ChainID) String added in v0.4.0

func (id ChainID) String() string

type Collection

type Collection struct {
	TransactionIDs []Identifier
}

A Collection is a list of transactions bundled together for inclusion in a block.

func (Collection) Encode

func (c Collection) Encode() []byte

Encode returns the canonical RLP byte representation of this collection.

func (Collection) ID

func (c Collection) ID() Identifier

ID returns the canonical SHA3-256 hash of this collection.

type CollectionGuarantee

type CollectionGuarantee struct {
	CollectionID Identifier
}

A CollectionGuarantee is an attestation signed by the nodes that have guaranteed a collection.

type Event

type Event struct {
	// Type is the qualified event type.
	Type string
	// TransactionID is the ID of the transaction this event was emitted from.
	TransactionID Identifier
	// TransactionIndex is the index of the transaction this event was emitted from, within its containing block.
	TransactionIndex int
	// EventIndex is the index of the event within the transaction it was emitted from.
	EventIndex int
	// Value contains the event data.
	Value cadence.Event
}

func (Event) Encode

func (e Event) Encode() []byte

Encode returns the canonical RLP byte representation of this event.

func (Event) ID

func (e Event) ID() string

ID returns the canonical SHA3-256 hash of this event.

func (Event) String

func (e Event) String() string

String returns the string representation of this event.

type Identifier

type Identifier [32]byte

An Identifier is a 32-byte unique identifier for an entity.

func BytesToID

func BytesToID(b []byte) Identifier

BytesToID constructs an identifier from a byte slice.

func HashToID

func HashToID(hash []byte) Identifier

HashToID constructs an identifier from a 32-byte hash.

func HexToID added in v0.4.0

func HexToID(h string) Identifier

HexToID constructs an identifier from a hexadecimal string.

func (Identifier) Bytes

func (i Identifier) Bytes() []byte

Bytes returns the bytes representation of this identifier.

func (Identifier) Hex

func (i Identifier) Hex() string

Hex returns the hexadecimal string representation of this identifier.

func (Identifier) String

func (i Identifier) String() string

String returns the string representation of this identifier.

type ProposalKey

type ProposalKey struct {
	Address        Address
	KeyIndex       int
	SequenceNumber uint64
}

A ProposalKey is the key that specifies the proposal key and sequence number for a transaction.

type Transaction

type Transaction struct {
	// Script is the UTF-8 encoded Cadence source code that defines the execution logic for this transaction.
	Script []byte

	// Arguments is a list of Cadence values passed into this transaction.
	//
	// Each argument is encoded as JSON-CDC bytes.
	Arguments [][]byte

	// ReferenceBlockID is a reference to the block used to calculate the expiry of this transaction.
	//
	// A transaction is considered expired if it is submitted to Flow after refBlock + N, where N
	// is a constant defined by the network.
	//
	// For example, if a transaction references a block with height of X and the network limit is 10,
	// a block with height X+10 is the last block that is allowed to include this transaction.
	ReferenceBlockID Identifier

	// GasLimit is the maximum number of computational units that can be used to execute this transaction.
	GasLimit uint64

	// ProposalKey is the account key used to propose this transaction.
	//
	// A proposal key references a specific key on an account, along with an up-to-date
	// sequence number for that key. This sequence number is used to prevent replay attacks.
	//
	// You can find more information about sequence numbers here: https://docs.onflow.org/concepts/transaction-signing/#sequence-numbers
	ProposalKey ProposalKey

	// Payer is the account that pays the fee for this transaction.
	//
	// You can find more information about the payer role here: https://docs.onflow.org/concepts/transaction-signing/#signer-roles
	Payer Address

	// Authorizers is a list of the accounts that are authorizing this transaction to
	// mutate to their on-chain account state.
	//
	// You can find more information about the authorizer role here: https://docs.onflow.org/concepts/transaction-signing/#signer-roles
	Authorizers []Address

	// PayloadSignatures is a list of signatures generated by the proposer and authorizer roles.
	//
	// A payload signature is generated over the inner portion of the transaction (TransactionDomainTag + payload).
	//
	// You can find more information about transaction signatures here: https://docs.onflow.org/concepts/transaction-signing/#anatomy-of-a-transaction
	PayloadSignatures []TransactionSignature

	// EnvelopeSignatures is a list of signatures generated by the payer role.
	//
	// An envelope signature is generated over the outer portion of the transaction (TransactionDomainTag + payload + payloadSignatures).
	//
	// You can find more information about transaction signatures here: https://docs.onflow.org/concepts/transaction-signing/#anatomy-of-a-transaction
	EnvelopeSignatures []TransactionSignature
}

A Transaction is a full transaction object containing a payload and signatures.

Example
addresses := test.AddressGenerator()

// Mock user accounts

adrianLaptopKey := &flow.AccountKey{
	Index:          3,
	SequenceNumber: 42,
}

adrianPhoneKey := &flow.AccountKey{Index: 2}
addressA := addresses.New()

adrian := flow.Account{
	Address: addressA,
	Keys: []*flow.AccountKey{
		adrianLaptopKey,
		adrianPhoneKey,
	},
}

blaineHardwareKey := &flow.AccountKey{Index: 7}
addressB := addresses.New()

blaine := flow.Account{
	Address: addressB,
	Keys: []*flow.AccountKey{
		blaineHardwareKey,
	},
}

// Transaction preparation

tx := flow.NewTransaction().
	SetScript([]byte(`transaction { execute { log("Hello, World!") } }`)).
	SetReferenceBlockID(flow.Identifier{0x01, 0x02}).
	SetGasLimit(42).
	SetProposalKey(adrian.Address, adrianLaptopKey.Index, adrianLaptopKey.SequenceNumber).
	SetPayer(blaine.Address).
	AddAuthorizer(adrian.Address)

fmt.Printf("Transaction ID (before signing): %s\n\n", tx.ID())

// Signing

err := tx.SignPayload(adrian.Address, adrianLaptopKey.Index, test.MockSigner([]byte{1}))
if err != nil {
	panic(err)
}

err = tx.SignPayload(adrian.Address, adrianPhoneKey.Index, test.MockSigner([]byte{2}))
if err != nil {
	panic(err)
}

err = tx.SignEnvelope(blaine.Address, blaineHardwareKey.Index, test.MockSigner([]byte{3}))
if err != nil {
	panic(err)
}

fmt.Println("Payload signatures:")
for _, sig := range tx.PayloadSignatures {
	fmt.Printf(
		"Address: %s, Key Index: %d, Signature: %x\n",
		sig.Address,
		sig.KeyIndex,
		sig.Signature,
	)
}
fmt.Println()

fmt.Println("Envelope signatures:")
for _, sig := range tx.EnvelopeSignatures {
	fmt.Printf(
		"Address: %s, Key Index: %d, Signature: %x\n",
		sig.Address,
		sig.KeyIndex,
		sig.Signature,
	)
}
fmt.Println()

fmt.Printf("Transaction ID (after signing): %s\n", tx.ID())
Output:

Transaction ID (before signing): 8c362dd8b7553d48284cecc94d2ab545d513b29f930555632390fff5ca9772ee

Payload signatures:
Address: f8d6e0586b0a20c7, Key Index: 2, Signature: 02
Address: f8d6e0586b0a20c7, Key Index: 3, Signature: 01

Envelope signatures:
Address: ee82856bf20e2aa6, Key Index: 7, Signature: 03

Transaction ID (after signing): d1a2c58aebfce1050a32edf3568ec3b69cb8637ae090b5f7444ca6b2a8de8f8b

func DecodeTransaction added in v0.14.1

func DecodeTransaction(transactionMessage []byte) (*Transaction, error)

DecodeTransaction decodes the input bytes into a Transaction struct able to decode outputs from PayloadMessage(), EnvelopeMessage() and Encode() functions

func NewTransaction

func NewTransaction() *Transaction

NewTransaction initializes and returns an empty transaction.

func (*Transaction) AddArgument added in v0.4.0

func (t *Transaction) AddArgument(arg cadence.Value) error

AddArgument adds a Cadence argument to this transaction.

func (*Transaction) AddAuthorizer

func (t *Transaction) AddAuthorizer(address Address) *Transaction

AddAuthorizer adds an authorizer account to this transaction.

func (*Transaction) AddEnvelopeSignature

func (t *Transaction) AddEnvelopeSignature(address Address, keyIndex int, sig []byte) *Transaction

AddEnvelopeSignature adds an envelope signature to the transaction for the given address and key index.

func (*Transaction) AddPayloadSignature

func (t *Transaction) AddPayloadSignature(address Address, keyIndex int, sig []byte) *Transaction

AddPayloadSignature adds a payload signature to the transaction for the given address and key index.

func (*Transaction) AddRawArgument added in v0.7.0

func (t *Transaction) AddRawArgument(arg []byte) *Transaction

AddRawArgument adds a raw JSON-CDC encoded argument to this transaction.

func (*Transaction) Argument added in v0.7.0

func (t *Transaction) Argument(i int) (cadence.Value, error)

Argument returns the decoded argument at the given index.

func (*Transaction) Encode

func (t *Transaction) Encode() []byte

Encode serializes the full transaction data including the payload and all signatures.

func (*Transaction) EnvelopeMessage

func (t *Transaction) EnvelopeMessage() []byte

EnvelopeMessage returns the signable message for the transaction envelope.

This message is only signed by the payer account.

func (*Transaction) ID

func (t *Transaction) ID() Identifier

ID returns the canonical SHA3-256 hash of this transaction.

func (*Transaction) PayloadMessage

func (t *Transaction) PayloadMessage() []byte

func (*Transaction) SetGasLimit

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

SetGasLimit sets the gas limit for this transaction.

func (*Transaction) SetPayer

func (t *Transaction) SetPayer(address Address) *Transaction

SetPayer sets the payer account for this transaction.

func (*Transaction) SetProposalKey

func (t *Transaction) SetProposalKey(address Address, keyIndex int, sequenceNum uint64) *Transaction

SetProposalKey sets the proposal key and sequence number for this transaction.

The first two arguments specify the account key to be used, and the last argument is the sequence number being declared.

func (*Transaction) SetReferenceBlockID

func (t *Transaction) SetReferenceBlockID(blockID Identifier) *Transaction

SetReferenceBlockID sets the reference block ID for this transaction.

A transaction is considered expired if it is submitted to Flow after refBlock + N, where N is a constant defined by the network.

For example, if a transaction references a block with height of X and the network limit is 10, a block with height X+10 is the last block that is allowed to include this transaction.

func (*Transaction) SetScript

func (t *Transaction) SetScript(script []byte) *Transaction

SetScript sets the Cadence script for this transaction.

The script is the UTF-8 encoded Cadence source code.

func (*Transaction) SignEnvelope

func (t *Transaction) SignEnvelope(address Address, keyIndex int, signer crypto.Signer) error

SignEnvelope signs the full transaction (TransactionDomainTag + payload + payload signatures) with the specified account key.

The resulting signature is combined with the account address and key index before being added to the transaction.

This function returns an error if the signature cannot be generated.

func (*Transaction) SignPayload

func (t *Transaction) SignPayload(address Address, keyIndex int, signer crypto.Signer) error

SignPayload signs the transaction payload (TransactionDomainTag + payload) with the specified account key.

The resulting signature is combined with the account address and key index before being added to the transaction.

This function returns an error if the signature cannot be generated.

type TransactionResult

type TransactionResult struct {
	Status TransactionStatus
	Error  error
	Events []Event
}

type TransactionSignature

type TransactionSignature struct {
	Address     Address
	SignerIndex int
	KeyIndex    int
	Signature   []byte
}

A TransactionSignature is a signature associated with a specific account key.

type TransactionStatus

type TransactionStatus int

TransactionStatus represents the status of a transaction.

const (
	// TransactionStatusUnknown indicates that the transaction status is not known.
	TransactionStatusUnknown TransactionStatus = iota
	// TransactionStatusPending is the status of a pending transaction.
	TransactionStatusPending
	// TransactionStatusFinalized is the status of a finalized transaction.
	TransactionStatusFinalized
	// TransactionStatusExecuted is the status of an executed transaction.
	TransactionStatusExecuted
	// TransactionStatusSealed is the status of a sealed transaction.
	TransactionStatusSealed
	// TransactionStatusExpired is the status of an expired transaction.
	TransactionStatusExpired
)

func (TransactionStatus) String

func (s TransactionStatus) String() string

String returns the string representation of a transaction status.

Directories

Path Synopsis
Package client provides a Go client for the Flow Access gRPC API.
Package client provides a Go client for the Flow Access gRPC API.
cloudkms
Package cloudkms provides a Google Cloud Key Management Service (KMS) implementation of the crypto.Signer interface.
Package cloudkms provides a Google Cloud Key Management Service (KMS) implementation of the crypto.Signer interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL