Decodes, packs, encodes, proves, stores and uploads block-replicas (can be block-results, block-specimens, or any other pre-defined block types), which are primarily "block-specimens" produced by EVM or non-EVM byte code based blockchains.
These block-replicas are produced by go-ethereum nodes / websocket block data sources modified with block-specimen producers(BSP) streamed into a redis channel. The agent first decodes them from their native RLP encoding, repacks them into segments of bigger chunks containing more than one block's worth of data, creates a proof transaction on the proof-chain smart contract (also called cqt-virtnet) with a sha-256 checksum of the data contained in the object, and finally persists them into storage (local and IPFS).
Production of Block Specimen forms the core of the network’s data objects specification. These objects are created with the aid of three main pieces of open-source software provided by Covalent for the network’s decentralized stack.
-
Block Specimen Producer (BSP Geth) - Operator run & deployed
-
BSP Agent - Operator run & deployed
-
BSP Proof-chain - Covalent operated & pre-deployed
Please refer to these instructions for running the BSP with the bsp-agent (BSP Agent).
Please refer to this whitepaper to understand more about its function.
Block Replicas are created by the BSP here and fed into Redis streams.
These objects are extracted and read into the following struct by the agent. There are two types of block-replica objects currently -
For Ethereum -
type BlockReplica struct {
Type string
NetworkId uint64
Hash common.Hash
TotalDifficulty *big.Int
Header *Header
Transactions []*Transaction
Uncles []*Header
Receipts []*Receipt
Senders []common.Address
State *StateSpecimen
}
For Elrond -
type ElrondBlockReplica struct {
Block *Block
Transactions []*ElrondTransaction
SCResults []*SCResult
Receipts []*ElrondReceipt
Logs []*Log
StateChanges []*AccountBalanceUpdate
}
The "State" is comprised of all state information related to accounts ever touched for a given block.
For Ethereum -
type StateSpecimen struct {
AccountRead []*accountRead
StorageRead []*storageRead
CodeRead []*codeRead
}
type accountRead struct {
Address common.Address
Nonce uint64
Balance *big.Int
CodeHash common.Hash
}
type storageRead struct {
Account common.Address
SlotKey common.Hash
Value common.Hash
}
type codeRead struct {
Hash common.Hash
Code []byte
}
For Elrond -
type AccountBalanceUpdate struct {
Address []byte
Balance []byte
Nonce int64
}
An Ethereum (moonbeam) private key (for a public address that is pre-whitelisted and added as an operator on the covalent network staking contract) allows block-specimen producers (operators) to make proof transactions to the proof-chain contract and is required by the bsp-agent. Other env vars are optional depending on your redis, eth account configuration. Add the following to your .envrc
at the root dir with final relative path ~/bsp-agent/.envrc
.
An Ethereum (moonbeam) RPC URL specifies the ethereum client connection string used to make transactions to on proof-chain contract, the respective credentials to be able to write to the contract should be provided in the .envrc file as follows. An IPFS Service token should be provided which relates to the JWT token for accessing file uploads on IPFS as a node service - Pinata & account service token for Web3.Storage. These two services are supported for file uploads.
export MB_RPC_URL=http://127.0.0.1:7545
export MB_PRIVATE_KEY=****************************************************************
export IPFS_SERVICE_TOKEN=*****
export REDIS_PWD=your-redis-password #optional
export MB_KEYSTORE_PATH=path/to/keystore/file.json #optional
export MB_KEYSTORE_PWD=password/to/access/keystore/file.json #optional
Please brew install direnv
add the following to you bash -
eval "$(direnv hook bash)" # bash users - add the following line to your ~/.bashrc
eval "$(direnv hook zsh)" # zsh users - add the following line to your ~/.zshrc
And enable the vars with direnv allow .
For which you should see something like -
direnv: loading ~/Documents/covalent/bsp-agent/.envrc
direnv: export +MB_PRIVATE_KEY +MB_RPC_URL +IPFS_SERVICE_TOKEN
The remaining environment configuration is set up with flags provided to the bsp-agent during runtime.
Clone the covalenthq/bsp-agent
repo and checkout main
In order to store the block-specimen binary files please create a directory with sufficient storage (each specimen file is 0.5 to 1 MBs) depending on your block-specimen creation throughput.
git clone git@github.com:covalenthq/bsp-agent.git
cd bsp-agent
git checkout main
mkdir -p /scratch/node/block-ethereum/
Run the agent for (ethereum mainnet block-specimens) directly using the following -
go run ./cmd/bspagent/*.go \
--redis-url="redis://username:@localhost:6379/0?topic=replication-1#replicate-1" \
--avro-codec-path="./codec/block-ethereum.avsc" \
--binary-file-path="/scratch/node/block-ethereum/" \
--block-divisor=3 \
--proof-chain-address="0x8243AF52B91649547DC80814670Dd1683F360E4c" \
--consumer-timeout=10000000 \
--log-folder ./logs/ \
--ipfs-pinner-server="http://127.0.0.1:3000/""
Or update the Makefile with the correct --proof-chain-address
and run with the following.
make run-agent-eth
the size of each uploaded object (AVRO compression containing as many as specified block specimens in a single uploaded object)
--redis-url
- this flag tells the BSP agent where to find the BSP messages, the stream topic key replication
and the consumer group name with the field after "#" that in this case is replicate
, additionally one can provide a password to the redis instance here but we recommend that by adding the line below to the .envrc
export REDIS_PWD=your-redis-pwd
--avro-codec-path
- tells the BSP agent, the relative path to the AVRO .avsc files in the repo, since the agent ships with the corresponding .avsc files this remains fixed unless stated otherwise explicitly with another codec
--binary-file-path
- tells the BSP agent if local copies of the block-replica objects being created are to be stored in a given local directory. Please make sure the path (& directory) pre-exists before passing this flag
--block-divisor
- allows the operator to configure the number of block specimens being created, the block number divisible only by this number will be extracted, packed, encoded, uploaded and proofed.
--proof-chain-address
- specifies the address of the proof-chain contract that has been deployed for the CQT network (local ethereum network for this workflow).
--consumer-timeout
- specifies in how many seconds the BSP agent stops waiting for new messages from the redis pending queue for decode, pack, encode, proof, store and upload.
--log-folder
- specifies the location (folder) where the log files have to be placed. In case of error (like permission errors), the logs are not recorded in files.
--ipfs-pinner-server
- specifies the http server for ipfs-pinner which interacts with ipfs to upload/download files.
--metrics
- enable metrics collection and reporting
--metrics.addr
- Enable stand-alone metrics HTTP server listening interface (default: "127.0.0.1")
--metrics.port
- Metrics HTTP server listening port (default: 6061)
Please install docker and docker-compose.
Employ docker-compose
to get all the necessary services along with the BSP agent to also get running along with the following, from root. Add a .env.dev file (if needed) to accomodate the env vars. The other services are -
- redis-srv (Open source (BSD licensed), in-memory data structure store)
- redis-commander-web (Redis web management tool written in node.js)
- ganache-cli (Ethereum blockchain & client)
- proof-chain (Validation (proofing) smart-contracts)
cd bsp-agent
docker-compose -f "docker-compose.yml" --env-file .env.dev up --build --remove-orphans --force-recreate --exit-code-from consumer
The docker image for this service can be found here
Run only the bsp-agent with the following, though this will not work if the other services in the docker-compose.yml file aren't also initialized.
docker pull ghcr.io/covalenthq/bsp-agent:latest
docker run ghcr.io/covalenthq/bsp-agent:latest --env-file .env.dev
There are two lua scripts in /scripts
for usage with the redis-cli
.
-
redis-count.lua - This allows for counting of total stream messages within bounds.
-- call with params [stream-key] , [first-stream-id] [last-stream-id] -- get to the ids with XINFO STREAM [stream-key]
> redis-cli --eval redis-count.lua replication , "1637349819851-0" "1637349831400-35"
> (integer) 6280
-
redis-trim.lua - This allows for removing messages from the stream within bounds.
-- call with params [stream-key] , [number-of-elements-to-trim-from-start] -- get to the ids with XINFO STREAM [stream-key]
> redis-cli --eval redis-trim.lua replication , 5
> (integer) 5
To view pretty print the results from the creation of avro encoded block-replica files
go run extractor.go \
--binary-file-path="../bin/block-ethereum/" \
--codec-path="../codec/block-ethereum.avsc" \
--indent-json=0
Please make sure that the --binary-file-path and --avro-codec-path matches the ones given while running the agent above. --indent-json (0,1,2) can be used to pretty print and inspect the AVRO json objects.
similar to extractor.go, but outputs the specimen, result and block_replica in separate json files. It works with the ethereum block codec version 0.3. Whereas, extractor.go works with codec version 0.2 only. Ideally both scripts should be able to handle the different versions.
go run extractor2.go --binary-file-path="/Users/sudeep/repos/bsp-agent/data/block-ethereum/" --codec-path "../../codec/block-ethereum.avsc" --indent-json 0 --end-block-number 15185258 --start-block-number 15185258 --chain-id "1" --output-file-path "./"