mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-25 13:09:30 +00:00
Have the Router track its deployment block
Prevents a consensus split where some nodes would drop transfers if their node didn't think the Router was deployed, and some would handle them.
This commit is contained in:
parent
294462641e
commit
7e4c59a0a3
3 changed files with 38 additions and 4 deletions
|
@ -7,6 +7,9 @@ import "Schnorr.sol";
|
||||||
|
|
||||||
// _ is used as a prefix for internal functions and smart-contract-scoped variables
|
// _ is used as a prefix for internal functions and smart-contract-scoped variables
|
||||||
contract Router {
|
contract Router {
|
||||||
|
// The block at which this contract was deployed.
|
||||||
|
uint256 private _deploymentBlock;
|
||||||
|
|
||||||
// Nonce is incremented for each command executed, preventing replays
|
// Nonce is incremented for each command executed, preventing replays
|
||||||
uint256 private _nonce;
|
uint256 private _nonce;
|
||||||
|
|
||||||
|
@ -63,6 +66,8 @@ contract Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(bytes32 initialSeraiKey) _updateSeraiKeyAtEndOfFn(0, initialSeraiKey) {
|
constructor(bytes32 initialSeraiKey) _updateSeraiKeyAtEndOfFn(0, initialSeraiKey) {
|
||||||
|
_deploymentBlock = block.number;
|
||||||
|
|
||||||
// We consumed nonce 0 when setting the initial Serai key
|
// We consumed nonce 0 when setting the initial Serai key
|
||||||
_nonce = 1;
|
_nonce = 1;
|
||||||
// Nonces are incremented by 1 upon account creation, prior to any code execution, per EIP-161
|
// Nonces are incremented by 1 upon account creation, prior to any code execution, per EIP-161
|
||||||
|
@ -230,6 +235,10 @@ contract Router {
|
||||||
return _nonce;
|
return _nonce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deploymentBlock() external view returns (uint256) {
|
||||||
|
return _deploymentBlock;
|
||||||
|
}
|
||||||
|
|
||||||
function smartContractNonce() external view returns (uint256) {
|
function smartContractNonce() external view returns (uint256) {
|
||||||
return _smartContractNonce;
|
return _smartContractNonce;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use alloy_consensus::TxLegacy;
|
||||||
|
|
||||||
use alloy_sol_types::{SolValue, SolConstructor, SolCall, SolEvent};
|
use alloy_sol_types::{SolValue, SolConstructor, SolCall, SolEvent};
|
||||||
|
|
||||||
use alloy_rpc_types_eth::Filter;
|
use alloy_rpc_types_eth::{TransactionInput, TransactionRequest, Filter};
|
||||||
use alloy_transport::{TransportErrorKind, RpcError};
|
use alloy_transport::{TransportErrorKind, RpcError};
|
||||||
use alloy_simple_request_transport::SimpleRequest;
|
use alloy_simple_request_transport::SimpleRequest;
|
||||||
use alloy_provider::{Provider, RootProvider};
|
use alloy_provider::{Provider, RootProvider};
|
||||||
|
@ -296,6 +296,23 @@ impl Router {
|
||||||
self.1
|
self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch the block this contract was deployed at.
|
||||||
|
pub async fn deployment_block(&self) -> Result<u64, RpcError<TransportErrorKind>> {
|
||||||
|
let call = TransactionRequest::default()
|
||||||
|
.to(self.address())
|
||||||
|
.input(TransactionInput::new(abi::deploymentBlockCall::new(()).abi_encode().into()));
|
||||||
|
let bytes = self.0.call(&call).await?;
|
||||||
|
let deployment_block = abi::deploymentBlockCall::abi_decode_returns(&bytes, true)
|
||||||
|
.map_err(|e| {
|
||||||
|
TransportErrorKind::Custom(
|
||||||
|
format!("node returned a non-u256 for function returning u256: {e:?}").into(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
._0;
|
||||||
|
|
||||||
|
Ok(deployment_block.try_into().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the message to be signed in order to update the key for Serai.
|
/// Get the message to be signed in order to update the key for Serai.
|
||||||
pub fn update_serai_key_message(chain_id: U256, nonce: u64, key: &PublicKey) -> Vec<u8> {
|
pub fn update_serai_key_message(chain_id: U256, nonce: u64, key: &PublicKey) -> Vec<u8> {
|
||||||
(
|
(
|
||||||
|
@ -420,7 +437,7 @@ impl Router {
|
||||||
*/
|
*/
|
||||||
if let Some(matched) = Erc20::match_top_level_transfer(&self.0, tx_hash, self.1).await? {
|
if let Some(matched) = Erc20::match_top_level_transfer(&self.0, tx_hash, self.1).await? {
|
||||||
// Mark this log index as used so it isn't used again
|
// Mark this log index as used so it isn't used again
|
||||||
transfer_check.insert(matched.log_index);
|
transfer_check.insert(matched.id.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a matching transfer log
|
// Find a matching transfer log
|
||||||
|
|
|
@ -156,10 +156,12 @@ impl<D: Db> ScannerFeed for Rpc<D> {
|
||||||
// The Router wasn't deployed yet so we cannot have any on-chain interactions
|
// The Router wasn't deployed yet so we cannot have any on-chain interactions
|
||||||
// If the Router has been deployed by the block we've synced to, it won't have any events
|
// If the Router has been deployed by the block we've synced to, it won't have any events
|
||||||
// for these blocks anways, so this doesn't risk a consensus split
|
// for these blocks anways, so this doesn't risk a consensus split
|
||||||
// TODO: This does as we can have top-level transfers to the router before it's deployed
|
|
||||||
return Ok(FullEpoch { epoch, instructions, executed });
|
return Ok(FullEpoch { epoch, instructions, executed });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let router_deployment_block = router.deployment_block().await?;
|
||||||
|
|
||||||
|
// TODO: Use a LocalSet and handle all these in parallel
|
||||||
let mut to_check = epoch.end_hash;
|
let mut to_check = epoch.end_hash;
|
||||||
while to_check != epoch.prior_end_hash {
|
while to_check != epoch.prior_end_hash {
|
||||||
let to_check_block = self
|
let to_check_block = self
|
||||||
|
@ -177,6 +179,12 @@ impl<D: Db> ScannerFeed for Rpc<D> {
|
||||||
})?
|
})?
|
||||||
.header;
|
.header;
|
||||||
|
|
||||||
|
// If this is before the Router was deployed, move on
|
||||||
|
if to_check_block.number < router_deployment_block {
|
||||||
|
// This is sa
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
instructions.append(
|
instructions.append(
|
||||||
&mut router.in_instructions(to_check_block.number, &HashSet::from(TOKENS)).await?,
|
&mut router.in_instructions(to_check_block.number, &HashSet::from(TOKENS)).await?,
|
||||||
);
|
);
|
||||||
|
@ -187,7 +195,7 @@ impl<D: Db> ScannerFeed for Rpc<D> {
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
instructions.push(EthereumInInstruction {
|
instructions.push(EthereumInInstruction {
|
||||||
id: (id, u64::MAX),
|
id,
|
||||||
from,
|
from,
|
||||||
coin: EthereumCoin::Erc20(token),
|
coin: EthereumCoin::Erc20(token),
|
||||||
amount,
|
amount,
|
||||||
|
|
Loading…
Reference in a new issue