Skip to content

Commit

Permalink
Add astar support.
Browse files Browse the repository at this point in the history
  • Loading branch information
dvc94ch committed Jun 21, 2023
1 parent 66d7df6 commit a4d195e
Show file tree
Hide file tree
Showing 19 changed files with 1,471 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
[workspace]
members = [
"chains/astar/config",
"chains/astar/server",
"chains/astar/tx",
"chains/bitcoin/config",
"chains/bitcoin/server",
"chains/ethereum/config",
Expand Down
5 changes: 5 additions & 0 deletions build_connectors.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ cargo build -p rosetta-server-polkadot --target x86_64-unknown-linux-musl --rele
mkdir -p target/release/polkadot/bin
cp target/x86_64-unknown-linux-musl/release/rosetta-server-polkadot target/release/polkadot/bin
docker build target/release/polkadot -f chains/polkadot/Dockerfile -t analoglabs/connector-polkadot

cargo build -p rosetta-server-astar --target x86_64-unknown-linux-musl --release
mkdir -p target/release/astar/bin
cp target/x86_64-unknown-linux-musl/release/rosetta-server-astar target/release/astar/bin
docker build target/release/astar -f chains/astar/Dockerfile -t analoglabs/connector-astar
3 changes: 3 additions & 0 deletions chains/astar/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM scratch
COPY bin/rosetta-server-astar rosetta-server-astar
ENTRYPOINT ["/rosetta-server-astar"]
12 changes: 12 additions & 0 deletions chains/astar/config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "rosetta-config-astar"
version = "0.2.5"
edition = "2021"
description = "Polkadot configuration."
repository = "https://github.com/analog-labs/chain-connectors"
license = "MIT"

[dependencies]
anyhow = "1.0.69"
rosetta-core = { version = "0.2.5", path = "../../../rosetta-core" }
serde = { version = "1.0.153", features = ["derive"] }
66 changes: 66 additions & 0 deletions chains/astar/config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use anyhow::Result;
use rosetta_core::crypto::address::{AddressFormat, Ss58AddressFormatRegistry};
use rosetta_core::crypto::Algorithm;
use rosetta_core::BlockchainConfig;
use serde::{Deserialize, Serialize};
use std::sync::Arc;

pub fn config(network: &str) -> Result<BlockchainConfig> {
let (network, kusama) = match network {
"dev" => ("dev", false),
_ => anyhow::bail!("unsupported network"),
};
Ok(BlockchainConfig {
blockchain: "astar",
network,
algorithm: Algorithm::Sr25519,
address_format: AddressFormat::Ss58(
if kusama {
Ss58AddressFormatRegistry::PolkadotAccount
} else {
Ss58AddressFormatRegistry::KusamaAccount
}
.into(),
),
coin: 1,
bip44: false,
utxo: false,
currency_unit: "planck",
currency_symbol: "ASTR",
currency_decimals: 18,
node_port: 9944,
node_image: "staketechnologies/astar-collator:latest",
node_command: Arc::new(|network, port| {
vec![
"astar-collator".into(),
format!("--chain={network}"),
"--rpc-cors=all".into(),
"--ws-external".into(),
format!("--ws-port={port}"),
"--alice".into(),
"--tmp".into(),
]
}),
node_additional_ports: &[],
connector_port: 8083,
testnet: network == "dev",
})
}

#[derive(Clone, Deserialize, Serialize)]
pub struct AstarMetadataParams {
pub pallet_name: String,
pub call_name: String,
pub call_args: Vec<u8>,
}

#[derive(Deserialize, Serialize)]
pub struct AstarMetadata {
pub nonce: u32,
pub spec_version: u32,
pub transaction_version: u32,
pub genesis_hash: [u8; 32],
pub pallet_index: u8,
pub call_index: u8,
pub call_hash: [u8; 32],
}
25 changes: 25 additions & 0 deletions chains/astar/server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "rosetta-server-astar"
version = "0.2.5"
edition = "2021"
description = "Astar rosetta server."
repository = "https://github.com/analog-labs/chain-connectors"
license = "MIT"

[dependencies]
anyhow = "1.0.69"
async-std = { version = "1.12.0", features = ["tokio1"] }
async-trait = "0.1.66"
hex = "0.4.3"
parity-scale-codec = "3.4.0"
rosetta-config-astar = { version = "0.2.5", path = "../config" }
rosetta-server = { version = "0.2.5", path = "../../../rosetta-server" }
scale-info = "2.3.1"
serde = { version = "1.0.153", features = ["derive"] }
serde_json = "1.0.94"
sp-keyring = "18.0.0"
subxt = "0.27.1"
tokio = { version = "1.26.0", features = ["rt-multi-thread", "macros"] }

[dev-dependencies]
rosetta-server = { version = "0.2.5", path = "../../../rosetta-server", features = ["tests"] }
167 changes: 167 additions & 0 deletions chains/astar/server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# __Rosetta Server for Substrate Chains__

This Project contains `BlockchainClient` implementation of substrate chains.

Methods implemented are:
* `config`
* `genesis_block`
* `node_version`
* `current_block`
* `balance`
* `faucet`
* `metadata`
* `submit`
* `block`
* `block_transaction`
* `call`


### `config`:

This method returns `BlockchainConfig` which contains the configuration specific details for polkadot chain.

### `genesis_block`:

Returns genesis block identifier.

### `node_version`:

Returns node client version.

### `current_block`:

Fetches current block using RPC and returns its identifier.

### `balance`:

Fetches account balance from on chain and returns it. It takes two arguments:
`address`: Address of account we want to fetch balance of.
`block`: block identifier of block at which we want to fetch balance of account.

### `block`:

This function takes `PartialBlockIdentifier` which contains a block index or hash and returns block transaction and operations happened in that transaction.

### `block_transaction`:

This function takes:
`block`: Which is a block identifier of block from which we want to fetch transaction from.
`tx`: Transaction identifier of transaction we want to fetch.
And returns a specific transaction and its operations within specified block.

### `faucet`:

This method is used to fund an account with some amount of tokens in testnet. It takes two arguments:
`address`: Address of account we want to fund.
`amount`: Amount of tokens we want to fund.

### `metadata`:

This call is used to fetch nonce of account, It takes two arguments:
`public_key`: This is the public key of sender.
`options`: This is Params needed to create metadata. For polkadot chain it takes
`pallet_name`: name of pallet.
`call_name`: function of pallet.
`call_args`: parameters of pallet.

It returns `PolkadotMetadata` which includes `nonce`, `runtime specs`, `genesis hash` and pallet related information.

### `submit`:

It takes transaction bytes which is signed transaction bytes and it Submits signed transaction to chain and return its transaction id.


### `call`:

To fetch Storage or any Constant from a Substrate chain, you can use the `Call` function. This method takes a `CallRequest` as input and returns a json `Value` as output. The `CallRequest` contains the following fields:
* `NetworkIdentifier` - The network to make the call on.
* `Method` - A string contains `-` seperated the name of pallet, function of pallet and type of query e.g. `Storage`, `Constant`.
* `Parameters` - A Array containing the parameters required for that pallet function.

### __Passing paramters__
`Enums` and `Struct` are passed in paramter as array values
lets say we have an enum:
```Rust
enum TestEnum {
A,
B(u32),
C,
}
```
and we want to pass `TestEnum::A` as parameter then we pass `["A", ""]` as parameter.
Second value in array is for the paramter of enum variant. In this case its will be empty since enum does not contain any paramter.
if we want to pass `TestEnum::B(10)` as parameter then we pass `["B", 10]` as parameter.
Here we passed 10 as a Json Number in array.

Now lets take a look if a function call requires a some complex enum like:
```Rust
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)]
pub enum MultiAddress<AccountId, AccountIndex> {
/// It's an account ID (pubkey).
Id(AccountId),
/// It's an account index.
Index(#[codec(compact)] AccountIndex),
/// It's some arbitrary raw bytes.
Raw(Vec<u8>),
/// It's a 32 byte representation.
Address32([u8; 32]),
/// Its a 20 byte representation.
Address20([u8; 20]),
}
```
we need to pass Id variant of this enum now this variant takes a parameter which is `AccountId` type. Type of `AccountId` is

```Rust
type AccountId = AccountId32;
```
where `AccountId32` is a struct with 32 byte vector.

```Rust
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)]
pub struct AccountId32(pub [u8; 32]);
```

So we need to pass `AccountId32` as a parameter. We can pass it as `[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]` which is a 32 byte array. and complete enum param will look like this

```Json
{
"params": [
["Id", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
]
}

```

Similarly if we want to pass a `Struct` in parameters then we pass it as array of values as well.
let's say we have a struct:

```Rust
struct TestStruct {
a: u32,
b: u32,
c: u32,
}
```
and we want to pass `TestStruct { a: 1, b: 2, c: 3 }` as parameter then we pass `[1, 2, 3]` as parameter array.
So passing those both as a paramter list should look like this
```Json
{
"method": "pallet_name-storage_name-query_type",
"params": [
["A", ""], //representing TestEnum::A
[1, 2, 3] //representing TestStruct { a: 1, b: 2, c: 3 }
]
}
```

Other primitive types are passed as they are. e.g.
```Json
{
"method": "pallet_name-storage_name-query_type",
"params": [
1, //representing u32
"test", //representing String
false, //representing bool
]
}
```
Loading

0 comments on commit a4d195e

Please sign in to comment.