Skip to content

Commit a65a8e1

Browse files
Implement some of the Revive RPCs (#317)
* [revive]: Implement important RPCs Signed-off-by: Alexandru Cihodaru <[email protected]> Co-authored-by: alindima <[email protected]>
1 parent 2d6f80b commit a65a8e1

File tree

15 files changed

+930
-92
lines changed

15 files changed

+930
-92
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/anvil-polkadot/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ parity-scale-codec = "3.7.5"
132132
subxt = "0.43.0"
133133
subxt-signer = "0.43.0"
134134
tokio-stream = "0.1.17"
135+
sqlx = "0.8.6"
135136

136137
[dev-dependencies]
137138
alloy-provider = { workspace = true, features = ["txpool-api"] }

crates/anvil-polkadot/src/api_server/error.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::substrate_node::mining_engine::MiningError;
22
use anvil_rpc::{error::RpcError, response::ResponseResult};
3+
use polkadot_sdk::pallet_revive_eth_rpc::{EthRpcError, client::ClientError};
34
use serde::Serialize;
45

56
#[derive(Debug, thiserror::Error)]
@@ -10,16 +11,30 @@ pub enum Error {
1011
RpcUnimplemented,
1112
#[error("Invalid params: {0}")]
1213
InvalidParams(String),
14+
#[error("Revive call failed: {0}")]
15+
ReviveRpc(#[from] EthRpcError),
16+
}
17+
impl From<subxt::Error> for Error {
18+
fn from(err: subxt::Error) -> Self {
19+
Self::ReviveRpc(EthRpcError::ClientError(err.into()))
20+
}
21+
}
22+
23+
impl From<ClientError> for Error {
24+
fn from(err: ClientError) -> Self {
25+
Self::ReviveRpc(EthRpcError::ClientError(err))
26+
}
1327
}
1428

1529
pub type Result<T> = std::result::Result<T, Error>;
1630

31+
/// Helper trait to easily convert results to rpc results
1732
pub(crate) trait ToRpcResponseResult {
1833
fn to_rpc_result(self) -> ResponseResult;
1934
}
2035

21-
/// Converts a serializable value into a `ResponseResult`
22-
pub fn to_rpc_result<T: Serialize>(val: T) -> ResponseResult {
36+
/// Converts a serializable value into a `ResponseResult`.
37+
fn to_rpc_result<T: Serialize>(val: T) -> ResponseResult {
2338
match serde_json::to_value(val) {
2439
Ok(success) => ResponseResult::Success(success),
2540
Err(err) => {
@@ -33,8 +48,31 @@ impl<T: Serialize> ToRpcResponseResult for Result<T> {
3348
fn to_rpc_result(self) -> ResponseResult {
3449
match self {
3550
Ok(val) => to_rpc_result(val),
36-
Err(Error::InvalidParams(msg)) => RpcError::invalid_params(msg).into(),
37-
Err(err) => RpcError::internal_error_with(err.to_string()).into(),
51+
Err(err) => match err {
52+
Error::Mining(mining_error) => match mining_error {
53+
MiningError::BlockProducing(error) => {
54+
RpcError::internal_error_with(format!("Failed to produce a block: {error}"))
55+
.into()
56+
}
57+
MiningError::MiningModeMismatch => {
58+
RpcError::invalid_params("Current mining mode can not answer this query.")
59+
.into()
60+
}
61+
MiningError::Timestamp => {
62+
RpcError::invalid_params("Current timestamp is newer.").into()
63+
}
64+
MiningError::ClosedChannel => {
65+
RpcError::internal_error_with("Communication channel was dropped.").into()
66+
}
67+
},
68+
Error::RpcUnimplemented => RpcError::internal_error_with("Not implemented").into(),
69+
Error::InvalidParams(error_message) => {
70+
RpcError::invalid_params(error_message).into()
71+
}
72+
Error::ReviveRpc(client_error) => {
73+
RpcError::internal_error_with(format!("{client_error}")).into()
74+
}
75+
},
3876
}
3977
}
4078
}

crates/anvil-polkadot/src/api_server/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use anvil_rpc::response::ResponseResult;
44
use futures::channel::{mpsc, oneshot};
55
use server::ApiServer;
66

7-
mod error;
7+
pub mod error;
8+
pub mod revive_conversions;
89
mod server;
910

1011
pub type ApiHandle = mpsc::Sender<ApiRequest>;
@@ -17,10 +18,13 @@ pub struct ApiRequest {
1718
pub fn spawn(substrate_service: &Service, logging_manager: LoggingManager) -> ApiHandle {
1819
let (api_handle, receiver) = mpsc::channel(100);
1920

20-
let api_server = ApiServer::new(substrate_service, receiver, logging_manager);
21-
22-
let spawn_handle = substrate_service.task_manager.spawn_essential_handle();
23-
spawn_handle.spawn("anvil-api-server", "anvil", api_server.run());
21+
let service = substrate_service.clone();
22+
substrate_service.spawn_handle.spawn("anvil-api-server", "anvil", async move {
23+
let api_server = ApiServer::new(service, receiver, logging_manager)
24+
.await
25+
.unwrap_or_else(|err| panic!("Failed to spawn the API server: {err}"));
26+
api_server.run().await;
27+
});
2428

2529
api_handle
2630
}
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
use alloy_eips::{BlockId, BlockNumberOrTag};
2+
use alloy_primitives::Address;
3+
use alloy_rpc_types::{AccessList, SignedAuthorization, TransactionRequest};
4+
use polkadot_sdk::{
5+
pallet_revive::evm::{
6+
AccessListEntry, AuthorizationListEntry, BlockNumberOrTagOrHash, BlockTag, Byte, Bytes,
7+
GenericTransaction, InputOrData,
8+
},
9+
sp_core,
10+
};
11+
use subxt::utils::{H160, H256};
12+
13+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14+
pub struct AlloyU256(alloy_primitives::U256);
15+
16+
impl From<polkadot_sdk::sp_core::U256> for AlloyU256 {
17+
fn from(value: polkadot_sdk::sp_core::U256) -> Self {
18+
let mut bytes = [0u8; 32];
19+
value.write_as_big_endian(&mut bytes);
20+
Self(alloy_primitives::U256::from_be_bytes(bytes))
21+
}
22+
}
23+
24+
impl AlloyU256 {
25+
pub fn inner(&self) -> alloy_primitives::U256 {
26+
self.0
27+
}
28+
}
29+
30+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31+
pub struct SubstrateU256(sp_core::U256);
32+
33+
impl From<alloy_primitives::U256> for SubstrateU256 {
34+
fn from(value: alloy_primitives::U256) -> Self {
35+
Self(sp_core::U256::from_big_endian(&value.to_be_bytes::<32>()))
36+
}
37+
}
38+
39+
impl SubstrateU256 {
40+
pub fn inner(&self) -> sp_core::U256 {
41+
self.0
42+
}
43+
}
44+
45+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46+
pub struct ReviveAddress(H160);
47+
48+
impl ReviveAddress {
49+
pub fn new(addr: H160) -> Self {
50+
Self(addr)
51+
}
52+
53+
pub fn inner(&self) -> H160 {
54+
self.0
55+
}
56+
}
57+
58+
impl From<Address> for ReviveAddress {
59+
fn from(addr: Address) -> Self {
60+
Self(H160::from_slice(addr.0.as_ref()))
61+
}
62+
}
63+
64+
impl From<ReviveAddress> for Address {
65+
fn from(value: ReviveAddress) -> Self {
66+
Self(alloy_primitives::U160::from_be_bytes(*value.0.as_fixed_bytes()).into())
67+
}
68+
}
69+
70+
#[derive(Debug, Clone)]
71+
pub struct ReviveBlockId(BlockNumberOrTagOrHash);
72+
73+
impl ReviveBlockId {
74+
pub fn inner(self) -> BlockNumberOrTagOrHash {
75+
self.0
76+
}
77+
}
78+
79+
impl From<Option<BlockId>> for ReviveBlockId {
80+
fn from(block_id: Option<BlockId>) -> Self {
81+
Self(block_id.map_or(
82+
BlockNumberOrTagOrHash::BlockTag(BlockTag::Latest),
83+
|b_id| match b_id {
84+
BlockId::Hash(rpc_hash) => BlockNumberOrTagOrHash::BlockHash(H256::from_slice(
85+
rpc_hash.block_hash.as_slice(),
86+
)),
87+
BlockId::Number(number_or_tag) => match number_or_tag {
88+
BlockNumberOrTag::Number(num) => BlockNumberOrTagOrHash::BlockNumber(
89+
polkadot_sdk::pallet_revive::U256::from(num),
90+
),
91+
BlockNumberOrTag::Latest => BlockNumberOrTagOrHash::BlockTag(BlockTag::Latest),
92+
BlockNumberOrTag::Earliest => {
93+
BlockNumberOrTagOrHash::BlockTag(BlockTag::Earliest)
94+
}
95+
BlockNumberOrTag::Pending => {
96+
BlockNumberOrTagOrHash::BlockTag(BlockTag::Pending)
97+
}
98+
BlockNumberOrTag::Safe => BlockNumberOrTagOrHash::BlockTag(BlockTag::Safe),
99+
BlockNumberOrTag::Finalized => {
100+
BlockNumberOrTagOrHash::BlockTag(BlockTag::Finalized)
101+
}
102+
},
103+
},
104+
))
105+
}
106+
}
107+
108+
#[derive(Debug, Clone)]
109+
pub struct ReviveAccessList(Vec<AccessListEntry>);
110+
111+
impl ReviveAccessList {
112+
pub fn inner(self) -> Vec<AccessListEntry> {
113+
self.0
114+
}
115+
}
116+
117+
impl From<AccessList> for ReviveAccessList {
118+
fn from(value: AccessList) -> Self {
119+
Self(
120+
value
121+
.0
122+
.into_iter()
123+
.map(|access_list_entry| AccessListEntry {
124+
address: ReviveAddress::from(access_list_entry.address).inner(),
125+
storage_keys: access_list_entry
126+
.storage_keys
127+
.into_iter()
128+
.map(|key| H256::from_slice(key.as_ref()))
129+
.collect(),
130+
})
131+
.collect(),
132+
)
133+
}
134+
}
135+
136+
#[derive(Debug, Clone)]
137+
pub struct ReviveAuthorizationListEntry(AuthorizationListEntry);
138+
139+
impl ReviveAuthorizationListEntry {
140+
pub fn inner(self) -> AuthorizationListEntry {
141+
self.0
142+
}
143+
}
144+
145+
impl From<SignedAuthorization> for ReviveAuthorizationListEntry {
146+
fn from(value: SignedAuthorization) -> Self {
147+
Self(AuthorizationListEntry {
148+
chain_id: SubstrateU256::from(value.inner().chain_id).inner(),
149+
address: ReviveAddress::from(value.inner().address).inner(),
150+
nonce: value.inner().nonce.into(),
151+
y_parity: value.y_parity().into(),
152+
r: SubstrateU256::from(value.r()).inner(),
153+
s: SubstrateU256::from(value.s()).inner(),
154+
})
155+
}
156+
}
157+
158+
#[derive(Debug, Clone)]
159+
pub struct ReviveBytes(Bytes);
160+
161+
impl From<alloy_primitives::Bytes> for ReviveBytes {
162+
fn from(value: alloy_primitives::Bytes) -> Self {
163+
Self(Bytes::from(value.to_vec()))
164+
}
165+
}
166+
167+
impl ReviveBytes {
168+
pub fn inner(self) -> Bytes {
169+
self.0
170+
}
171+
}
172+
173+
pub(crate) fn convert_to_generic_transaction(
174+
transaction_request: TransactionRequest,
175+
) -> GenericTransaction {
176+
GenericTransaction {
177+
access_list: transaction_request
178+
.access_list
179+
.map(|access_list| ReviveAccessList::from(access_list).inner()),
180+
authorization_list: transaction_request.authorization_list.map_or(
181+
Default::default(),
182+
|authorization_list| {
183+
authorization_list
184+
.into_iter()
185+
.map(|entry| ReviveAuthorizationListEntry::from(entry).inner())
186+
.collect()
187+
},
188+
),
189+
blob_versioned_hashes: transaction_request
190+
.blob_versioned_hashes
191+
.unwrap_or_default()
192+
.into_iter()
193+
.map(|b256| H256::from_slice(b256.as_ref()))
194+
.collect(),
195+
blobs: transaction_request
196+
.sidecar
197+
.unwrap_or_default()
198+
.blobs
199+
.into_iter()
200+
.map(|blob| Bytes::from(blob.0.to_vec()))
201+
.collect(),
202+
chain_id: transaction_request.chain_id.map(sp_core::U256::from),
203+
from: transaction_request.from.map(|addr| ReviveAddress::from(addr).inner()),
204+
gas: transaction_request.gas.map(sp_core::U256::from),
205+
gas_price: transaction_request.gas_price.map(sp_core::U256::from),
206+
input: InputOrData::from(
207+
ReviveBytes::from(transaction_request.input.into_input().unwrap_or_default()).inner(),
208+
),
209+
max_fee_per_blob_gas: transaction_request.max_fee_per_blob_gas.map(sp_core::U256::from),
210+
max_fee_per_gas: transaction_request.max_fee_per_gas.map(sp_core::U256::from),
211+
max_priority_fee_per_gas: transaction_request
212+
.max_priority_fee_per_gas
213+
.map(sp_core::U256::from),
214+
nonce: transaction_request.nonce.map(sp_core::U256::from),
215+
to: transaction_request
216+
.to
217+
.and_then(|tx_kind| tx_kind.into_to())
218+
.map(|addr| ReviveAddress::from(addr).inner()),
219+
r#type: transaction_request.transaction_type.map(Byte::from),
220+
value: transaction_request.value.map(|value| SubstrateU256::from(value).inner()),
221+
}
222+
}

0 commit comments

Comments
 (0)