Baseledger core consensus client for running a validator, full or seed node.
⚠️ WARNING: this code has not been audited and is not ready for use in production. The Baseledger mainnet is scheduled to launch in Q1 2022.
This package depends on a modified version of Tendermint v0.34.11 which requires a Vault for storing private key material. We also compile the Baseledger Application Blockchain Interface (ABCI) and tendermint core dependencies together within a single binary for ease-of-use, cross-platform portability and optimal performance.
prvd
CLIBaseledger was created by Unibright and Provide and is under active development.
In the spirit of developing a proof of concept implementation to experiment with network validation in tendermint (including staking and delegation), native opcodes and a community block explorer, the team built the "lakewood" testnet. This testnet was created using Cosmos SDK.
The "peachtree" testnet was created from scratch using tendermint for BFT consensus and the Provide stack for subscribing to events emitted by the Baseledger governance and staking contracts, broadcasting baseline proofs to the network and otherwise interacting with the Baseline Protocol. As a result of this design, baseledger-core
can be built as a single container and added to existing deployments of the Provide stack for increased security. baseledger-core
can also run standalone (i.e., outside the context of a Provide stack). Baseledger nodes running outside the context of a Provide stack are not restricted from operating as validator, full or seed nodes. Organizations implementing the baseline pattern in commercial multiparty workflows benefit from running a local Baseledger node because it provides additional security to the cryptographic commitments (proofs) stored within the Provide stack without sacrificing any privacy guarantees inherent to baselining.
The Baseledger mainnet is currently scheduled to launch in Q1 2022. More information will be made available in Q4 2021 about the governance council and how you can apply to become a validator on the mainnet to earn block rewards in UBT.
The following are the minimum hardware requirements recommended for running a Baseledger validator or null node:
git clone git@github.com:baseledger/baseledger-core.git
make build
Using the Provide CLI, you can easily setup a secure vault instance to secure your Baseledger keys. Baseledger currently supports Ed25519 keys for peer-to-peer authorization and validator keys.
If you have not previously created a Provide user, first create one:
prvd users create
Next, authenticate using those credentials and create a vault and Ed25519 key:
prvd authenticate
prvd vaults init --name 'Baseledger Vault'
prvd vaults keys init
# follow the prompts; control-c to bypass selecting an application and organization
✔ Baseledger
✔ asymmetric
✔ sign/verify
Name: Baseledger node key
Description: My first baseledger node key
✔ Ed25519
You will see the UUID of the created vault key.
You will also need to authorize a refresh token for the user or organization that is the owner of the vault by running the following:
prvd api_tokens init [--organization <org uuid>] --offline-access
Note the refresh token, vault id and vault key id. Each of these values will be used to run a validator or full node.
You can use the following command to run a full
node on the Baseledger "peachtree" testnet:
VAULT_REFRESH_TOKEN=<your refresh token> \
VAULT_ID=<vault id> \
VAULT_KEY_ID=<vault key id> \
BASELEDGER_MODE=full \
LOG_LEVEL=debug \
BASELEDGER_LOG_LEVEL='main:info,*:error' \
BASELEDGER_GENESIS_URL=http://genesis.peachtree.baseledger.provide.network:1337/genesis \
BASELEDGER_PERSISTENT_PEERS=187b285fcf8bff3f08f5e61cfe05b713a4d32356@genesis.peachtree.baseledger.provide.network:33333 \
BASELEDGER_PEER_ALIAS=<your alias> \
./.bin/node
Running a validator node requires the user to be a depositor on the configured staking contract.
See the staking contract deposit()
method described below.
You can use the following command to run a validator
node on the Baseledger "peachtree" testnet:
VAULT_REFRESH_TOKEN=<your refresh token> \
VAULT_ID=<vault id> \
VAULT_KEY_ID=<vault key id> \
BASELEDGER_MODE=validator \
LOG_LEVEL=debug \
BASELEDGER_LOG_LEVEL='main:info,*:error' \
BASELEDGER_GENESIS_URL=http://genesis.peachtree.baseledger.provide.network:1337/genesis \
BASELEDGER_PERSISTENT_PEERS=187b285fcf8bff3f08f5e61cfe05b713a4d32356@genesis.peachtree.baseledger.provide.network:33333 \
BASELEDGER_PEER_ALIAS=<your alias> \
./.bin/node
A governance contract architecture is being developed which will, among other things, make the staking and other future contracts upgradable by way of the governance council.
We have taken a minimalistic approach to the Baseledger node implementation using tendermint. A critical part of the architecture is maintaining a highly fault-tolerant bridge between a configured Ethereum network (e.g., mainnet, ropsten, kovan, etc.) and the Baseledger network (e.g., mainnet or peachtree etc).
Just as crypto exchanges await a number of block confirmations before making deposited assets available for use, there are a number of block confirmations which must occur on the EVM-based network which hosts the Baseledger governance and staking contracts prior to any bridged changes taking effect on the Baseledger network.
For example, if a staking contract withdraw()
transaction affects the withdrawal of 100%
of the amount on deposit, the validator will cease to participate in block rewards effective
after the number of block confirmations. The number of L1 confirmations required prior to the
Baseledger network recognizing any associated updates (e.g., changes to the validator set) is
determined based on which EVM-based network is hosting the staking and token contracts:
Network | Block Confirmations |
---|---|
mainnet | 30 |
ropsten | 3 |
rinkeby | not supported at this time |
kovan | not supported at this time |
goerli | not supported at this time |
A staking contract, initialized with a reference to the UBT token contract address, is deployed on the following Ethereum networks:
Network | Symbol | Token Contract Address | Staking Contract Address |
---|---|---|---|
mainnet | UBT | 0x8400D94A5cb0fa0D041a3788e395285d61c9ee5e |
-- |
ropsten | UBTR | 0xa9a466b8f415bcc5883934eda70016f8b23ea776 |
0x0B5FC75192F8EE3B4795AB44b3B455aB3d97A6dF |
rinkeby | -- | -- | -- |
kovan | -- | -- | -- |
goerli | -- | -- | -- |
A faucet is being added to Provide Payments to make it easy to request UBT on supported testnets via the CLI.
The core purpose of the staking contract is to enable deposits and withdrawals of UBT on the Ethereum mainnet, or "test UBT" (such as UBTR, on the Ropsten testnet).
deposit(address beneficiary, bytes32 validator, uint256 amount) external
Become a depositor to the configured staking contract or increase an existing position.
Prior to making your first deposit into the staking contract from any address, or if a subsequent amount you wish to deposit exceeds the value of the remaining approved tokens,
you must call approve(address spender, uint25¸amount)
on the token contract to allow it to transfer UBT on your behalf when you call deposit()
.
The following example contract call to the UBTR token contract (0xa9a466b8f415bcc5883934eda70016f8b23ea776
) approves the staking contract (0x0B5FC75192F8EE3B4795AB44b3B455aB3d97A6dF
), enabling you to deposit up to 250,000 UBTR:
Function: approve(address spender, uint256 amount)
MethodID: 0x095ea7b3
[0]: 0000000000000000000000000b5fc75192f8ee3b4795ab44b3b455ab3d97a6df
[1]: 000000000000000000000000000000000000000000000000000016bcc41e9000
Call the deposit()
method. The following example contract call to the staking contract on the "peachtree" testnet (0x0B5FC75192F8EE3B4795AB44b3B455aB3d97A6dF
) results in 25,000 UBTR transferred and placed on deposit for benefit of sender.
Function: deposit(address beneficiary, bytes32 validator, uint256 amount) ***
MethodID: 0xeb2243f8
[0]: 000000000000000000000000bee25e36774dc2baeb14342f1e821d5f765e2739
[1]: eacbbc154c8373d7cb9134ed2a2fa2a4bdaf8bfef27b91299b8dce4042bd0000
[2]: 00000000000000000000000000000000000000000000000000000246139ca800
This method emits a Deposit(address addr, address beneficiary, bytes32 validator, uint256 amount)
event from the EVM/mainnet contract when a validator deposit succeeds, either by
way of governance approval or, in primitive/testnet setups, implicit approval.
Staking contract source can be found here. Example transaction on Ropsten can be found here.
withdraw(uint256 amount) external
Initiate the withdrawal of a portion, or all, of a previously deposited stake from the
configured staking contract; the following example contract call to the staking contract on the "peachtree: testnet (0x0B5FC75192F8EE3B4795AB44b3B455aB3d97A6dF
) results in 10,000 UBTR being withdrawn from our depositor account on the staking contract and returned.
Function: withdraw(uint256 value) ***
MethodID: 0x2e1a7d4d
[0]: 000000000000000000000000000000000000000000000000000000e8d4a51000
This method emits a Withdraw(address addr, bytes32 validator, uint256 amount)
event from the EVM/mainnet contract when a validator withdrawal succeeds, either by
way of governance approval or, in primitive/testnet setups, implicit approval.
Staking contract source can be found here. Example transaction on Ropsten can be found here.
An abstract proxy staking mechanism is being developed to add composable delegation functionality to the staking contract (see relevant placeholder in the source code here). Validators will be able to create competitive proxy staking offerings and implementations.
💡 This is a great idea for a hackathon project at the upcoming EthAtlanta hackathon, happening October 1-3.
Additional documentation forthcoming.
An entropy beacon is exposed via RPC by the /baseline/entropy/fetch
query. Every n
blocks, where n
is configurable for each Baseledger network, randomness is injected into the Baseledger block headers. This entropy can be used by callers to effectively seed MPC ceremonies which can be trusted even when none of the parties are honest. A verifiable random function, deployed as a smart contract on the public blockchain, is consumed every n
blocks, with the result injected into the header. The following VRF consumer contracts are deployed:
Network | VRF Consumer Contract Address | Block Interval |
---|---|---|
mainnet | -- | -- |
ropsten | -- | -- |
rinkeby | -- | -- |
kovan | -- | -- |
goerli | -- | -- |