Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mesh reconciliation tests support #1036

Merged
merged 26 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1251e85
Enable historical balances for Mesh
lrubasze Nov 19, 2024
ea3fc65
Support fee payments
lrubasze Nov 19, 2024
020d4c0
Support only FeePayment type
lrubasze Nov 20, 2024
0465299
Check if history enabled in runtime
lrubasze Nov 22, 2024
bc0abcf
Add mesh-cli configs for stokenet and mainnet
lrubasze Nov 22, 2024
694a2a4
Add Mesh API readme
lrubasze Nov 26, 2024
d62e0b7
Remove TODO from Mesh API metrics
lrubasze Nov 26, 2024
d5b2a9e
Parse operations for mempool transactions
lrubasze Nov 27, 2024
2f80d02
Update CI
lrubasze Nov 28, 2024
9684fe5
Cleanup
lrubasze Nov 28, 2024
b043d27
Update Readme
lrubasze Nov 28, 2024
0ac415f
Remove TODOs
lrubasze Nov 28, 2024
323538d
Fix MeshApiMempoolEndpointsTest
lrubasze Nov 29, 2024
8df5dd3
Add numeric conversion tests
lrubasze Nov 29, 2024
50fdd19
Update Mesh readme
lrubasze Dec 9, 2024
1950e4e
Assume successful operations only
lrubasze Dec 9, 2024
3f20511
Update some comments
lrubasze Dec 9, 2024
5b0d1bf
Rename error
lrubasze Dec 9, 2024
486f539
Tune InvalidTransaction messages
lrubasze Dec 9, 2024
0e5f5fb
Add Mesh API bind address in testnet node setup
lrubasze Dec 10, 2024
ac6660e
Add Mesh instructions for docker
lrubasze Dec 10, 2024
5fca792
Replace dyn Trait objects with impl Trait for better performance
lrubasze Dec 10, 2024
95b0ed7
Use ActualStateManagerDatabase in Mesh API
lrubasze Dec 10, 2024
26e8eb2
Revert "Use ActualStateManagerDatabase in Mesh API"
lrubasze Dec 10, 2024
0d2b11b
Enable Mesh API in testnet-node
lrubasze Dec 10, 2024
8de4789
Address some comments
lrubasze Dec 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,17 +255,19 @@ jobs:
env:
# This is to skip keygen step
RADIXDLT_NODE_KEY: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY=
run: ./gradlew :core:run --info &
run: |
echo "db.historical_substate_values.enable=true" >> core/default.config
./gradlew :core:run --info &
- name: Wait for 2 minutes
run: sleep 2m
- name: Install mesh-cli
run: curl -sSfL https://raw.githubusercontent.com/coinbase/mesh-cli/master/scripts/install.sh | sh -s
- name: Run Data API tests
run: ./bin/rosetta-cli check:data --configuration-file core-rust/mesh-api-server/mesh-cli-configs/default.json
run: ./bin/rosetta-cli --configuration-file core-rust/mesh-api-server/mesh-cli-configs/localnet.json check:data
- name: Run Construction API tests
run: ./bin/rosetta-cli check:construction --configuration-file core-rust/mesh-api-server/mesh-cli-configs/default.json
run: ./bin/rosetta-cli --configuration-file core-rust/mesh-api-server/mesh-cli-configs/localnet.json check:construction
- name: Run Coinbase-spec tests
run: ./bin/rosetta-cli check:spec --configuration-file core-rust/mesh-api-server/mesh-cli-configs/default.json
run: ./bin/rosetta-cli --configuration-file core-rust/mesh-api-server/mesh-cli-configs/localnet.json check:spec
cross-xwin:
name: Cross compile to Windows
runs-on: ubuntu-latest
Expand Down
278 changes: 278 additions & 0 deletions core-rust/mesh-api-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
# Mesh API Implementation for Radix

## Mesh API information

- [Mesh API Homepage](https://docs.cdp.coinbase.com/mesh/docs/welcome)
- [Mesh API Specification](https://github.com/coinbase/mesh-specifications)
- [Mesh API CLI Test Tool](https://github.com/coinbase/mesh-cli)

## Supported Features

| Feature | Status |
| ---------------------------- | ----------------------------------------------------------------------|
| Data API | Feature-complete, with some quirks |
| - `/network/list` | Complete |
| - `/network/status` | Complete |
| - `/network/options` | Complete |
| - `/block` | Feature-complete (exposes only balance-changing operations) |
| - `/block/transaction` | Feature-complete (exposes only balance-changing operations) |
| - `/account/balance` | Complete (historical balances available if explicitly enabled) |
| - `/mempool` | Complete (transactions are not held for a meaningful duration) |
| - `/mempool/transaction` | Complete (basic operations supported) |
| Construction API | Complete |
| - `/construction/derive` | Complete |
| - `/construction/preprocess` | Complete |
| - `/construction/metadata` | Complete |
| - `/construction/payloads` | Complete (supports Withdraw and Deposit operations only) |
| - `/construction/combine` | Complete |
| - `/construction/parse` | Complete (basic operations supported) |
| - `/construction/hash` | Complete |
| - `/construction/submit` | Complete |

## Additional Considerations

### Accounts

The current implementation has the following constraints:
- **Supports only account components**: Returns block operations or balances exclusively for accounts. Other components (e.g., smart contracts, lockers) are ignored.
- **Supports only Withdraw, Deposit, and FeePayment operations**: Minting and burning are skipped.

These constraints simplify the implementation without causing Mesh CLI tests to fail. If non-account components must be supported, the following may be required:
- Adding support for Minting and Burning operations.
- Providing explicit support for non-account components in balance fetching (or using `dump_component_state()`, which is resource-intensive).
- Exempting some addresses.

### Operations

Currently, a very specific parser is used to extract operations from given instructions (endpoints: `/mempool/transaction` and `/construction/parse`).
It works only with the instructions constructed by Mesh.
`Withdraw` and `Deposit` are the direct result of the instructions being used, while a `FeePayment` is added at commit time.

Technically, it would be possible to use transaction previews, receipts, and balance change summaries to extract operations.
But we don't do it for following reasons:
- both endpoint methods should work offline
- both endpoint methods should be static (not affected by current state of the network)
- this approach is deemed too resource-heavy

## Configuration

### Server settings
There are 3 configuration settings for a node's Mesh API server, which can:
- enable/disable Mesh API server launch (disabled by default),
- override the default port (3337),
- override the default bind address (127.0.0.1).

#### Node running bare-metal
```plaintext
api.mesh.enabled=<true/false>
api.mesh.port=<port number>
api.mesh.bind_address=<ip address>
```
#### Node running in Docker
Set below environmental variables

```plaintext
RADIXDLT_MESH_API_ENABLED=<true/false>
RADIXDLT_MESH_API_PORT=<port number>
RADIXDLT_MESH_API_BIND_ADDRESS=<ip address>
```

### Enable historical balances for reconciliation tests
In order to proceed with reconciliation tests historical balances shall be enabled.
There are 2 useful settings:
- enable/disable historical substate values (disabled by default),
- adjust the state version history length to keep (60000 by default).

#### Node running bare-metal
```plaintext
db.historical_substate_values.enable=<true/false>
state_hash_tree.state_version_history_length=<history_length_to_keep>
```

#### Node running in Docker
```
RADIXDLT_DB_HISTORICAL_SUBSTATE_VALUES_ENABLE=<true/false>
RADIXDLT_STATE_HASH_TREE_STATE_VERSION_HISTORY_LENGTH=<history_length_to_keep>
```

### Base URL

```plaintext
http://<bind_address>:<port>/mesh
```

**Example**: Fetching account balance
```plaintext
http://localhost:3337/mesh/account/balance
```

## Testing

### Mesh CLI

#### Steps:
1. [Terminal 1] Download the `rosetta-cli` prebuilt binary:
```bash
curl -sSfL https://raw.githubusercontent.com/coinbase/mesh-cli/master/scripts/install.sh | sh -s

alias mesh-cli='./bin/rosetta-cli --configuration-file <root-of-babylon-node-repo>/core-rust/mesh-api-server/mesh-cli-configs/localnet.json'
```
**Note:** As of November 2024, there are issues with the prebuilt MacOS binary. Use the workaround below:
```bash
git clone [email protected]:coinbase/mesh-cli
cd mesh-cli
git checkout bbbd759
alias mesh-cli='go run main.go --configuration-file <root-of-babylon-node-repo>/core-rust/mesh-api-server/mesh-cli-configs/localnet.json'
```

2. [Terminal 2] Launch the node:

- Node running bare-metal
- Change working directory to the root of the `babylon-node` repository
- Enable Mesh API server in `core/default.config`
```plaintext
api.mesh.enabled=true
```
- Optionally setup Mesh port and bind address
```
api.mesh.port=3337
api.mesh.bind_address=
```
- For reconciliation tests enable historical balances and optionally set state history length
```
db.historical_substate_values.enable=true
state_hash_tree.state_version_history_length=60000
```

- Start the node
```bash
RADIXDLT_NODE_KEY=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY= ./gradlew :core:run --info
```

- Node running in Docker

- Manual setup for production or testnet

Follow these steps to setup a node - [Manual Setup with Docker](https://docs.radixdlt.com/v1/docs/node-setup-docker).

Before launching a node set Mesh environment variables (mentioned in previous section) in `radix-fullnode-compose.yml` in `core` section:
- Enable Mesh API server:
```yaml
RADIXDLT_MESH_API_ENABLED: 'true'
```
- Optionally setup Mesh port and bind address
```yaml
RADIXDLT_MESH_API_PORT: 3337
RADIXDLT_MESH_API_BIND_ADDRESS: '0.0.0.0'
```
- For reconciliation tests enable historical balances and optionally set state history length
```yaml
RADIXDLT_DB_HISTORICAL_SUBSTATE_VALUES_ENABLE: 'true'
RADIXDLT_STATE_HASH_TREE_STATE_VERSION_HISTORY_LENGTH: 60000
```

- Simple setup for testnet

Follow these steps to setup a node - [Simple testnet setup](https://github.com/radixdlt/babylon-node/tree/develop/testnet-node).

Before launching a node set Mesh environment variables (mentioned in previous section) in `radix-node.env`:
- Enable Mesh API server:
```plaintext
RADIXDLT_MESH_API_ENABLED=true
```
- Optionally setup Mesh port and bind address
```plaintext
RADIXDLT_MESH_API_PORT=3337
RADIXDLT_MESH_API_BIND_ADDRESS=0.0.0.0
```
- For reconciliation tests enable historical balances and optionally set state history length
```plaintext
RADIXDLT_DB_HISTORICAL_SUBSTATE_VALUES_ENABLE=true
RADIXDLT_STATE_HASH_TREE_STATE_VERSION_HISTORY_LENGTH=60000
```

3. [Terminal 1] Run Mesh API tests:
```bash
mesh-cli check:data
mesh-cli check:construction
mesh-cli check:spec
```

#### Reconciliation Tests

If whole ledger shall be reconciled for eg. `mainnet` or `stokenet`, then make sure to:
- Set a future `state_version` in the `data.end_conditions.index` field of the `mesh-cli` config file.
- Launch the node with an empty database.
- Start `mesh-cli` as soon as possible to avoid pruning historical balances.

### Unit Tests

- **Java:**
```bash
./gradlew :core:test --tests '*MeshApiMempoolEndpointsTest*'
```
- **Rust:** (To Be Determined)

## Abstractions

### NetworkIdentifier

Fields:
- `blockchain`: "radix"
- `network`: Network variant (e.g., `mainnet`, `stokenet`, `localnet`).
- `sub_network_identifier`: Not set.

### Block

Represents a single transaction.

### BlockIdentifier

Fields:
- `index`: State version.
- `hash`: Hex-encoded string of 32 bytes composed of:
- `transaction_tree_hash` (bytes[0..12]).
- `receipt_tree_hash` (bytes[0..12]).
- `state_version` (bytes[0..8]).

### TransactionIdentifier

- **User transaction:** Bech32-encoded `transaction_intent_hash` (e.g., `txid_tdx_2_1nvm90npmkjcltvpy38nr373pt38ctptgg9y0g3wemhtjxyjmau7s32hd0n`).
- **Non-user transaction:** Bech32-encoded `ledger_transaction_hash` (e.g., `ledgertransaction_tdx_2_1s45u3f6xrh4tf4040aqt9fql3wqlhvwwwfpaz4rsru3pr88f3anstnds7s`).

### AccountIdentifier

Fields:
- `address`: Bech32-encoded Global Entity Address.
- `sub_account`: Not set.
- `metadata`: Not set.

### Currency

Fields:
- `symbol`: Bech32-encoded Resource Address.
- `decimals`: Resource divisibility.
- `metadata`: Not set.

### Amount

Fields:
- `value`: Currency amount.
- `currency`: Resource information.
- `metadata`: Not set.

### Operation

Fields:
- `operation_identifier`: Index of the operation within a transaction.
- `related_operations`: Not set.
- `type`:
- `Withdraw`: Withdraw assets from an account (always success, failed operations are filtered out).
- `Deposit`: Deposit assets to an account (always success, failed operations are filtered out).
- `FeePayment`: Withdraw assets to cover transaction fees (always success, even if the transaction fails).
- `status`: Operation status.
- `account`: Account transferring the resources.
- `amount`: Amount of currency transferred.
- `coin_change`: Not set.
- `metadata`: Not set.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"network": "localnet"
},
"online_url": "http://127.0.0.1:3337/mesh",
"data_directory": "test-data",
"data_directory": "test-data/localnet",
"http_timeout": 10,
"max_retries": 5,
"retry_elapsed_time": 0,
Expand Down Expand Up @@ -40,14 +40,15 @@
"pruning_block_disabled": false,
"pruning_balance_disabled": false,
"initial_balance_fetch_disabled": false,
"historical_balance_disabled": false,
"end_conditions": {
"tip": true,
"index": 10000
}
},
"construction": {
"offline_url": "http://localhost:3337/mesh",
"constructor_dsl_file": "workflows.ros",
"constructor_dsl_file": "localnet.ros",
"prefunded_accounts": [
{
"account_identifier": {
Expand Down
59 changes: 59 additions & 0 deletions core-rust/mesh-api-server/mesh-cli-configs/mainnet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"network": {
"blockchain": "radix",
"network": "mainnet"
},
"online_url": "http://127.0.0.1:3337/mesh",
"data_directory": "test-data/mainnet",
"http_timeout": 10,
"max_retries": 5,
"retry_elapsed_time": 0,
"max_online_connections": 120,
"max_sync_concurrency": 64,
"tip_delay": 300,
"max_reorg_depth": 100,
"log_configuration": false,
"compression_disabled": false,
"l0_in_memory_enabled": false,
"all_in_memory_enabled": false,
"error_stack_trace_disabled": false,
"coin_supported": false,
"data": {
"active_reconciliation_concurrency": 16,
"inactive_reconciliation_concurrency": 4,
"inactive_reconciliation_frequency": 250,
"log_blocks": false,
"log_transactions": false,
"log_balance_changes": false,
"log_reconciliations": false,
"ignore_reconciliation_error": false,
"exempt_accounts": "",
"bootstrap_balances": "",
"interesting_accounts": "",
"reconciliation_disabled": false,
"reconciliation_drain_disabled": false,
"inactive_discrepancy_search_disabled": false,
"balance_tracking_disabled": false,
"coin_tracking_disabled": false,
"status_port": 9090,
"results_output_file": "",
"pruning_block_disabled": false,
"pruning_balance_disabled": false,
"initial_balance_fetch_disabled": false,
"historical_balance_disabled": false,
"end_conditions": {
"index": 104281038
}
},
"construction": {
"offline_url": "http://localhost:3337/mesh",
"constructor_dsl_file": "mainnet.ros",
"stale_depth": 1000,
"broadcast_limit": 1000,
"end_conditions": {
"radix_workflow": 1
}
},
"perf": null,
"sign": null
}
Loading
Loading