emulator

package module
v0.14.0-beta2 Latest Latest
Warning

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

Go to latest
Published: Jan 14, 2021 License: Apache-2.0 Imports: 23 Imported by: 11

README

Flow Emulator

The Flow Emulator is a lightweight tool that emulates the behaviour of the real Flow network.

The emulator exposes a gRPC server that implements the Flow Observation API, which is designed to have near feature parity with the real network API.

Running the emulator with the Flow CLI

The emulator is bundled with the Flow CLI, a command-line interface for working with Flow.

Installation

Follow these steps to install the Flow CLI.

Starting the server

You can start the emulator with the Flow CLI:

flow emulator start --init

This command has several useful flags:

  • -v Enable verbose logging (this is useful for debugging)
  • -p Port to listen on (default: 3569)
  • -i Time interval between blocks (default: 5s)
  • --persist Enable persistent storage (uses Badger key-value DB)
  • --dbpath Path to store database (default: "./flowdb")
Using the emulator in a project

You can start the emulator in your project context by running the above command in the same directory as flow.json. This will configure the emulator with your project's service account, meaning you can use it to sign and submit transactions.

Running the emulator with Docker

Docker builds for the emulator are automatically built and pushed to gcr.io/dl-flow/emulator, tagged by commit and semantic version. You can also build the image locally.

Configuration

In addition to using command-line flags, the emulator can also be configured with environment variables, which can be passed into the Docker image.

Here's a sample configuration:

FLOW_VERBOSE=true
FLOW_PORT=3596
FLOW_INTERVAL=5s
FLOW_PERSIST=true
FLOW_DBPATH=./path/to/db

Here's how to run the emulator Docker image on port 9001 in verbose mode:

docker run -e FLOW_PORT=9001 -e FLOW_VERBOSE=true gcr.io/dl-flow/emulator

The full list of configurable variables is specified by the Config struct.

The environment variable names are the upper-case struct fields names, prefixed with FLOW_.

Accounts

The emulator uses a flow.json configuration file to store persistent configuration, including account keys. In order to start, at least one key (called the service key) must be configured. This key is used by default when creating other accounts.

Because Docker does not persist files by default, this file will be re-generated each time the emulator image restarts. For situations where it is important that the emulator always uses the same service key (ie. unit tests) you can specify a hex-encoded public key as an environment variable.

docker run -e FLOW_SERVICEPUBLICKEY=<hex-encoded key> gcr.io/dl-flow/emulator

To generate a service key, use the keys generate command in the Flow CLI.

flow keys generate

Building

To build the container locally, use make docker-build from the root of this repository.

Images are automatically built and pushed to gcr.io/dl-flow/emulator via Team City on any push to master, i.e. Pull Request merge

Deployment

The emulator is currently being deployed via Team City All commands relating to the deployment process live in the Makefile in this directory

The deployment has a persistent volume and should keep state persistent. The deployment file for the Ingress/Service/Deployment combo, and the Persistent Volume Claim are located in the k8s folder.

Accessing the deployment
Web Address

This is only available from the office currently

It should be available publicly via https://grpc.emulator.staging.withflow.org/

Port Forwarding

If you have direct access to the cluster, you can use kubectl to access the emulator

export EMULATOR_POD_NAME=$(kubectl get pod -n flow -l app=flow-emulator -o jsonpath="{.items[0].metadata.name}")
kubectl port-forward -n flow $EMULATOR_POD_NAME 3569:3569
From a Kubernetes Pod

If you are in the same namespace (flow), you can simply access the service via it's service name, e.g. flow-emulator-v1. If you are in a different namespace, you will need to use a Service without selectors e.g.

kind: Service
apiVersion: v1
metadata:
  name: flow-emulator-v1
  namespace: YOUR_NAMESPACE
spec:
  type: ExternalName
  externalName: flow-emulator-v1.flow.svc.cluster.local
  ports:
      protocol: TCP
      port: 3569
      targetPort: 3569
Creating your own deployment

Our current deployment settings are available in the k8s sub directory, if you'd like to setup the emulator in your own Kubernetes cluster. We are using the Traefik Ingress controller, but if that is not needed for your purposes, that can be removed, along with any corresponding annotations in the deployment file.

If not using Kubernetes, you can run the Docker container independently. Make sure to run the Docker container with the gRPC port exposed (default is 3569). Metrics are also available on port 8080 on the /metrics endpoint.

To gain persistence for data on the emulator, you will have to provision a volume for the docker container. We've done this through Persistent Volumes on Kubernetes, but a mounted volume would suffice. The mount point can be set with the FLOW_DBPATH environment variable. We suggest a volume of at least 10GB (100GB for a long-term deployment).

Make sure the emulator also has access to the same flow.json file, or always launch it with the same service key, as mentioned above.

docker run -e FLOW_SERVICEPUBLICKEY=<hex-encoded key> -e FLOW_DBPATH="/flowdb" -v "$(pwd)/flowdb":"/flowdb"  -p 3569:3569 gcr.io/dl-flow/emulator

Development

Run a development version of emulator server:

make run

Run all unit tests in this repository:

make test

Documentation

Overview

Package emulator provides an emulated version of the Flow blockchain that can be used for development purposes.

This package can be used as a library or as a standalone application.

When used as a library, this package provides tools to write programmatic tests for Flow applications.

When used as a standalone application, this package implements the Flow Access API and is fully-compatible with Flow gRPC client libraries.

Index

Constants

View Source
const DefaultServiceKeyHashAlgo = sdkcrypto.SHA3_256
View Source
const DefaultServiceKeySigAlgo = sdkcrypto.ECDSA_P256

Variables

This section is empty.

Functions

This section is empty.

Types

type AccountNotFoundError

type AccountNotFoundError struct {
	Address flowgo.Address
}

An AccountNotFoundError indicates that an account could not be found.

func (*AccountNotFoundError) Error

func (e *AccountNotFoundError) Error() string

type BlockNotFoundByHeightError

type BlockNotFoundByHeightError struct {
	Height uint64
}

A BlockNotFoundByHeightError indicates that a block could not be found at the specified height.

func (*BlockNotFoundByHeightError) Error

type BlockNotFoundByIDError

type BlockNotFoundByIDError struct {
	ID flow.Identifier
}

A BlockNotFoundByIDError indicates that a block with the specified ID could not be found.

func (*BlockNotFoundByIDError) Error

func (e *BlockNotFoundByIDError) Error() string

type BlockNotFoundError

type BlockNotFoundError interface {
	// contains filtered or unexported methods
}

A BlockNotFoundError indicates that a block could not be found.

type Blockchain

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

Blockchain emulates the functionality of the Flow blockchain.

func NewBlockchain

func NewBlockchain(opts ...Option) (*Blockchain, error)

NewBlockchain instantiates a new emulated blockchain with the provided options.

func (*Blockchain) AddTransaction

func (b *Blockchain) AddTransaction(tx sdk.Transaction) error

AddTransaction validates a transaction and adds it to the current pending block.

func (*Blockchain) CommitBlock

func (b *Blockchain) CommitBlock() (*flowgo.Block, error)

CommitBlock seals the current pending block and saves it to storage.

This function clears the pending transaction pool and resets the pending block.

func (*Blockchain) CreateAccount

func (b *Blockchain) CreateAccount(publicKeys []*sdk.AccountKey, contracts []templates.Contract) (sdk.Address, error)

CreateAccount submits a transaction to create a new account with the given account keys and contracts. The transaction is paid by the service account.

func (*Blockchain) ExecuteAndCommitBlock

func (b *Blockchain) ExecuteAndCommitBlock() (*flowgo.Block, []*types.TransactionResult, error)

ExecuteAndCommitBlock is a utility that combines ExecuteBlock with CommitBlock.

func (*Blockchain) ExecuteBlock

func (b *Blockchain) ExecuteBlock() ([]*types.TransactionResult, error)

ExecuteBlock executes the remaining transactions in pending block.

func (*Blockchain) ExecuteNextTransaction

func (b *Blockchain) ExecuteNextTransaction() (*types.TransactionResult, error)

ExecuteNextTransaction executes the next indexed transaction in pending block.

func (*Blockchain) ExecuteScript

func (b *Blockchain) ExecuteScript(script []byte, arguments [][]byte) (*types.ScriptResult, error)

ExecuteScript executes a read-only script against the world state and returns the result.

func (*Blockchain) ExecuteScriptAtBlock

func (b *Blockchain) ExecuteScriptAtBlock(script []byte, arguments [][]byte, blockHeight uint64) (*types.ScriptResult, error)

func (*Blockchain) GetAccount

func (b *Blockchain) GetAccount(address sdk.Address) (*sdk.Account, error)

GetAccount returns the account for the given address.

func (*Blockchain) GetAccountAtBlock

func (b *Blockchain) GetAccountAtBlock(address sdk.Address, blockHeight uint64) (*sdk.Account, error)

TODO: Implement

func (*Blockchain) GetBlockByHeight

func (b *Blockchain) GetBlockByHeight(height uint64) (*flowgo.Block, error)

GetBlockByHeight gets a block by height.

func (*Blockchain) GetBlockByID

func (b *Blockchain) GetBlockByID(id sdk.Identifier) (*flowgo.Block, error)

GetBlockByID gets a block by ID.

func (*Blockchain) GetCollection

func (b *Blockchain) GetCollection(colID sdk.Identifier) (*sdk.Collection, error)

func (*Blockchain) GetEventsByHeight

func (b *Blockchain) GetEventsByHeight(blockHeight uint64, eventType string) ([]sdk.Event, error)

GetEventsByHeight returns the events in the block at the given height, optionally filtered by type.

func (*Blockchain) GetLatestBlock

func (b *Blockchain) GetLatestBlock() (*flowgo.Block, error)

GetLatestBlock gets the latest sealed block.

func (*Blockchain) GetTransaction

func (b *Blockchain) GetTransaction(id sdk.Identifier) (*sdk.Transaction, error)

GetTransaction gets an existing transaction by ID.

The function first looks in the pending block, then the current blockchain state.

func (*Blockchain) GetTransactionResult

func (b *Blockchain) GetTransactionResult(ID sdk.Identifier) (*sdk.TransactionResult, error)

func (*Blockchain) PendingBlockID

func (b *Blockchain) PendingBlockID() flowgo.Identifier

PendingBlockID returns the ID of the pending block.

func (*Blockchain) PendingBlockTimestamp

func (b *Blockchain) PendingBlockTimestamp() time.Time

PendingBlockTimestamp returns the Timestamp of the pending block.

func (*Blockchain) ResetPendingBlock

func (b *Blockchain) ResetPendingBlock() error

ResetPendingBlock clears the transactions in pending block.

func (*Blockchain) ServiceKey

func (b *Blockchain) ServiceKey() ServiceKey

ServiceKey returns the service private key for this blockchain.

type CollectionNotFoundError

type CollectionNotFoundError struct {
	ID flow.Identifier
}

A CollectionNotFoundError indicates that a collection could not be found.

func (*CollectionNotFoundError) Error

func (e *CollectionNotFoundError) Error() string

type DuplicateTransactionError

type DuplicateTransactionError struct {
	TxID flowgo.Identifier
}

A DuplicateTransactionError indicates that a transaction has already been submitted.

func (*DuplicateTransactionError) Error

func (e *DuplicateTransactionError) Error() string

type ExecutionError

type ExecutionError struct {
	Code    int
	Message string
}

An ExecutionError occurs when a transaction fails to execute.

func (*ExecutionError) Error

func (e *ExecutionError) Error() string

type ExpiredTransactionError

type ExpiredTransactionError struct {
	RefHeight, FinalHeight uint64
}

ExpiredTransactionError indicates that a transaction has expired.

func (*ExpiredTransactionError) Error

func (e *ExpiredTransactionError) Error() string

type IncompleteTransactionError

type IncompleteTransactionError struct {
	MissingFields []string
}

IncompleteTransactionError indicates that a transaction is missing one or more required fields.

func (*IncompleteTransactionError) Error

type IndexedTransactionResult

type IndexedTransactionResult struct {
	Transaction *fvm.TransactionProcedure
	Index       uint32
}

type InvalidStateVersionError

type InvalidStateVersionError struct {
	Version crypto.Hash
}

An InvalidStateVersionError indicates that a state version hash provided is invalid.

func (*InvalidStateVersionError) Error

func (e *InvalidStateVersionError) Error() string

type InvalidTransactionGasLimitError

type InvalidTransactionGasLimitError struct {
	Maximum uint64
	Actual  uint64
}

InvalidTransactionGasLimitError indicates that a transaction specifies a gas limit that exceeds the maximum.

func (*InvalidTransactionGasLimitError) Error

type InvalidTransactionScriptError

type InvalidTransactionScriptError struct {
	ParserErr error
}

InvalidTransactionScriptError indicates that a transaction contains an invalid Cadence script.

func (*InvalidTransactionScriptError) Error

func (*InvalidTransactionScriptError) Unwrap

type NotFoundError

type NotFoundError interface {
	// contains filtered or unexported methods
}

A NotFoundError indicates that an entity could not be found.

type Option

type Option func(*config)

Option is a function applying a change to the emulator config.

func WithGenesisTokenSupply

func WithGenesisTokenSupply(supply cadence.UFix64) Option

WithGenesisTokenSupply sets the genesis token supply.

func WithScriptGasLimit

func WithScriptGasLimit(limit uint64) Option

WithScriptGasLimit sets the gas limit for scripts.

This limit does not affect transactions, which declare their own limit. Use WithTransactionMaxGasLimit to set the maximum gas limit for transactions.

func WithServicePublicKey

func WithServicePublicKey(
	servicePublicKey sdkcrypto.PublicKey,
	sigAlgo sdkcrypto.SignatureAlgorithm,
	hashAlgo sdkcrypto.HashAlgorithm,
) Option

WithServicePublicKey sets the service key from a public key.

func WithSimpleAddresses

func WithSimpleAddresses() Option

WithSimpleAddresses enables simple addresses, which are sequential starting with 0x01.

func WithStore

func WithStore(store storage.Store) Option

WithStore sets the persistent storage provider.

func WithTransactionExpiry

func WithTransactionExpiry(expiry uint) Option

WithTransactionExpiry sets the transaction expiry measured in blocks.

If set to zero, transaction expiry is disabled and the reference block ID field is not required.

func WithTransactionMaxGasLimit added in v0.12.4

func WithTransactionMaxGasLimit(maxLimit uint64) Option

WithTransactionMaxGasLimit sets the maximum gas limit for transactions.

Individual transactions will still be bounded by the limit they declare. This function sets the maximum limit that any transaction can declare.

This limit does not affect script executions. Use WithScriptGasLimit to set the gas limit for script executions.

type PendingBlockCommitBeforeExecutionError

type PendingBlockCommitBeforeExecutionError struct {
	BlockID flowgo.Identifier
}

A PendingBlockCommitBeforeExecutionError indicates that the current pending block has not been executed (cannot commit).

func (*PendingBlockCommitBeforeExecutionError) Error

type PendingBlockMidExecutionError

type PendingBlockMidExecutionError struct {
	BlockID flowgo.Identifier
}

A PendingBlockMidExecutionError indicates that the current pending block is mid-execution.

func (*PendingBlockMidExecutionError) Error

type PendingBlockTransactionsExhaustedError

type PendingBlockTransactionsExhaustedError struct {
	BlockID flowgo.Identifier
}

A PendingBlockTransactionsExhaustedError indicates that the current pending block has finished executing (no more transactions to execute).

func (*PendingBlockTransactionsExhaustedError) Error

type ServiceKey

type ServiceKey struct {
	Index          int
	Address        sdk.Address
	SequenceNumber uint64
	PrivateKey     *sdkcrypto.PrivateKey
	PublicKey      *sdkcrypto.PublicKey
	HashAlgo       sdkcrypto.HashAlgorithm
	SigAlgo        sdkcrypto.SignatureAlgorithm
	Weight         int
}

func DefaultServiceKey

func DefaultServiceKey() ServiceKey

func GenerateDefaultServiceKey

func GenerateDefaultServiceKey(
	sigAlgo sdkcrypto.SignatureAlgorithm,
	hashAlgo sdkcrypto.HashAlgorithm,
) ServiceKey

func (ServiceKey) AccountKey

func (s ServiceKey) AccountKey() *sdk.AccountKey

func (ServiceKey) Signer

func (s ServiceKey) Signer() sdkcrypto.Signer

type StorageError

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

A StorageError indicates that an error occurred in the storage provider.

func (*StorageError) Error

func (e *StorageError) Error() string

func (*StorageError) Unwrap

func (e *StorageError) Unwrap() error

type TransactionNotFoundError

type TransactionNotFoundError struct {
	ID flowgo.Identifier
}

A TransactionNotFoundError indicates that a transaction could not be found.

func (*TransactionNotFoundError) Error

func (e *TransactionNotFoundError) Error() string

type TransactionValidationError

type TransactionValidationError interface {
	// contains filtered or unexported methods
}

A TransactionValidationError indicates that a submitted transaction is invalid.

Directories

Path Synopsis
cmd
sdk
backend/mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
Package storage defines the interface and implementations for interacting with persistent chain state.
Package storage defines the interface and implementations for interacting with persistent chain state.
mocks
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.
utils

Jump to

Keyboard shortcuts

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