Skip to content
This repository has been archived by the owner on Aug 1, 2023. It is now read-only.

Commit

Permalink
Memorize forward blocks when a reorg happens (#377)
Browse files Browse the repository at this point in the history
* Memorize forward blocks when a reorg happens

* Bump spec version and update README
  • Loading branch information
jflatow authored Jun 23, 2021
1 parent c321984 commit f01c57d
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 28 deletions.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,18 +241,36 @@ The goal is to not break things on release.
Releases should be cut from the `develop` (default) branch on [Github](https://github.com/compound-finance/gateway).
For now, here's the manual process we follow for cutting releases:

### Bump Spec Version

First increment the spec version in `runtime/src/lib.rs`.

### Build Release Artifacts

First build the release artifacts using the included script:
Build the release artifacts using the included script:

```
$ scripts/build_release.sh <MILESTONE TAG>
```

Where `<MILESTONE TAG>` should be a sequentially increasing counter beginning with `m`, e.g. `m7`, `m8`, `m9`.
Where `<MILESTONE TAG>` should be a sequentially increasing counter beginning with `m`, followed by the spec version, e.g. `m7`, `m8`, `m9`.

### Update Chain Spec

Note: this is *only* necessary if you are deploying a new chain, the chain spec is defined at genesis.

The WASM blob in the chain spec should be updated via:

```
$ CHAIN_BIN=target/<MILESTONE TAG>/gateway-<PLATFORM> chains/build_spec.js -s -c testnet
```

Where `<PLATFORM>` is your local platform used to name the binary build.

### Upload Release Artifacts

The changes above should be committed to the `develop` branch and included in the version that is tagged in the repository below.

Draft a [new release on GitHub](https://github.com/compound-finance/gateway/releases/new).
Tag it with the appropriate milestone tag.
Title it in a style similar to other releases, describing its purpose.
Expand Down
12 changes: 4 additions & 8 deletions pallets/cash/src/chains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,19 +475,15 @@ impl ChainReorg {
}
}

pub fn reverse_blocks(&self) -> impl Iterator<Item = ChainBlock> + '_ {
pub fn reverse_blocks(&self) -> ChainBlocks {
match self {
ChainReorg::Eth { reverse_blocks, .. } => {
reverse_blocks.iter().map(|b| ChainBlock::Eth(b.clone()))
}
ChainReorg::Eth { reverse_blocks, .. } => ChainBlocks::Eth(reverse_blocks.to_vec()),
}
}

pub fn forward_blocks(&self) -> impl Iterator<Item = ChainBlock> + '_ {
pub fn forward_blocks(&self) -> ChainBlocks {
match self {
ChainReorg::Eth { forward_blocks, .. } => {
forward_blocks.iter().map(|b| ChainBlock::Eth(b.clone()))
}
ChainReorg::Eth { forward_blocks, .. } => ChainBlocks::Eth(forward_blocks.to_vec()),
}
}

Expand Down
51 changes: 35 additions & 16 deletions pallets/cash/src/internal/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub fn track_chain_events_on<T: Config>(chain_id: ChainId) -> Result<(), Reason>
let pending_reorgs = PendingChainReorgs::get(chain_id);
let reorg = formulate_reorg::<T>(chain_id, &last_block, &true_block)?;
if !reorg.is_already_signed(&me.substrate_id, pending_reorgs) {
memorize_chain_blocks::<T>(&reorg.forward_blocks())?;
submit_chain_reorg::<T>(&reorg)
} else {
debug!("Worker already submitted... waiting");
Expand Down Expand Up @@ -456,7 +457,7 @@ pub fn receive_chain_reorg<T: Config>(
// if we have enough support, perform actual reorg
// for each block going backwards
// remove events from queue, or unapply them if already applied
for block in tally.reorg.reverse_blocks() {
for block in tally.reorg.reverse_blocks().blocks() {
for event in block.events() {
// Note: this could be made significantly more efficient
// at the cost of significant complexity
Expand All @@ -470,7 +471,7 @@ pub fn receive_chain_reorg<T: Config>(

// for each block going forwards
// add events to event queue, advance the block, and process a round of events
for block in tally.reorg.forward_blocks() {
for block in tally.reorg.forward_blocks().blocks() {
event_queue.push(&block);
last_block = block.clone();
ingress_queue::<T>(&last_block, &mut event_queue)?;
Expand All @@ -495,10 +496,10 @@ mod tests {
use crate::tests::*;
use ethereum_client::EthereumBlock;

fn gen_blocks(start_block: u64, end_block: u64, pad: u8) -> Vec<EthereumBlock> {
fn gen_blocks(start_block: u64, until_block: u64, pad: u8) -> Vec<EthereumBlock> {
let mut hash = [0u8; 32];
let mut v: Vec<ethereum_client::EthereumBlock> = vec![];
for i in start_block..end_block {
for i in start_block..until_block {
let parent_hash = hash;
let mut hashvec = i.to_le_bytes().to_vec();
hashvec.extend_from_slice(&[pad; 24]);
Expand All @@ -514,17 +515,41 @@ mod tests {
}

#[test]
fn test_formulate_reorg() {
const STARPORT_ADDR: [u8; 20] = [0x77; 20];
fn test_track_chain_events_on_eth_reorg_and_back() {
let old_chain: Vec<EthereumBlock> = gen_blocks(0, 10, 0);
let new_chain: Vec<EthereumBlock> = gen_blocks(1, 10, 1);
let common_ancestor_block = old_chain[0].clone();
let last_block = old_chain.last().unwrap().clone();
let true_block = new_chain.last().unwrap().clone();

let mut fetched_blocks = new_chain[0..9].iter().rev().cloned().collect::<Vec<_>>();
fetched_blocks.extend(old_chain[1..10].iter().rev().cloned());
let calls = gen_mock_calls(&fetched_blocks, ETH_STARPORT_ADDR);
let (mut t, _, _) = new_test_ext_with_http_calls(calls);

t.execute_with(|| {
initialize_storage_with_blocks(vec![ChainBlock::Eth(common_ancestor_block)]);

LastProcessedBlock::insert(ChainId::Eth, ChainBlock::Eth(last_block));
memorize_chain_blocks::<Test>(&ChainBlocks::Eth(old_chain.clone())).unwrap();
track_chain_events_on::<Test>(ChainId::Eth).unwrap();

LastProcessedBlock::insert(ChainId::Eth, ChainBlock::Eth(true_block));
track_chain_events_on::<Test>(ChainId::Eth).unwrap();
});
}

#[test]
fn test_formulate_reorg() {
let old_chain: Vec<EthereumBlock> = gen_blocks(0, 10, 0);
let new_chain: Vec<EthereumBlock> = gen_blocks(1, 10, 1);
let common_ancestor_block = old_chain[0].clone();
let last_block = old_chain.last().unwrap().clone();
let true_block = new_chain.last().unwrap().clone();

// new_chain blocks -> 1...9, excluding true block -> 1...8 -> indices 0..8
let fetched_blocks = new_chain[0..8].iter().rev().cloned().collect::<Vec<_>>();
let calls = gen_mock_calls(&fetched_blocks, STARPORT_ADDR);
let calls = gen_mock_calls(&fetched_blocks, ETH_STARPORT_ADDR);
let (mut t, _, _) = new_test_ext_with_http_calls(calls);

t.execute_with(|| {
Expand Down Expand Up @@ -561,16 +586,14 @@ mod tests {

#[test]
fn test_formulate_reorg_height_mismatch() {
const STARPORT_ADDR: [u8; 20] = [0x77; 20];

let old_chain: Vec<EthereumBlock> = gen_blocks(0, 10, 0);
let new_chain: Vec<EthereumBlock> = gen_blocks(1, 9, 1);
let common_ancestor_block = old_chain[0].clone();
let last_block = old_chain.last().unwrap().clone();
let true_block = new_chain.last().unwrap().clone();

let fetched_blocks = vec![];
let calls = gen_mock_calls(&fetched_blocks, STARPORT_ADDR);
let calls = gen_mock_calls(&fetched_blocks, ETH_STARPORT_ADDR);
let (mut t, _, _) = new_test_ext_with_http_calls(calls);

t.execute_with(|| {
Expand All @@ -589,16 +612,14 @@ mod tests {

#[test]
fn test_formulate_reorg_missing_data() {
const STARPORT_ADDR: [u8; 20] = [0x77; 20];

let old_chain: Vec<EthereumBlock> = gen_blocks(0, 10, 0);
let new_chain: Vec<EthereumBlock> = gen_blocks(1, 10, 1);
let common_ancestor_block = old_chain[0].clone();
let last_block = old_chain.last().unwrap().clone();
let true_block = new_chain.last().unwrap().clone();

let fetched_blocks = new_chain[7..8].iter().rev().cloned().collect::<Vec<_>>();
let calls = gen_mock_calls(&fetched_blocks, STARPORT_ADDR);
let calls = gen_mock_calls(&fetched_blocks, ETH_STARPORT_ADDR);
let (mut t, _, _) = new_test_ext_with_http_calls(calls);

t.execute_with(|| {
Expand All @@ -617,15 +638,13 @@ mod tests {

#[test]
fn test_formulate_reorg_before_first() {
const STARPORT_ADDR: [u8; 20] = [0x77; 20];

let old_chain: Vec<EthereumBlock> = gen_blocks(0, 10, 0);
let new_chain: Vec<EthereumBlock> = gen_blocks(0, 10, 1);
let last_block = old_chain.last().unwrap().clone();
let true_block = new_chain.last().unwrap().clone();

let fetched_blocks = new_chain[0..9].iter().rev().cloned().collect::<Vec<_>>();
let calls = gen_mock_calls(&fetched_blocks, STARPORT_ADDR);
let calls = gen_mock_calls(&fetched_blocks, ETH_STARPORT_ADDR);
let (mut t, _, _) = new_test_ext_with_http_calls(calls);

t.execute_with(|| {
Expand Down
4 changes: 3 additions & 1 deletion pallets/cash/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ use test_env_log::test;

pub type SysEvent = frame_system::Event<Test>;

pub const ETH_STARPORT_ADDR: [u8; 20] = [0x77; 20];

#[macro_export]
macro_rules! bal {
($string:expr, $units:expr) => {
Expand Down Expand Up @@ -161,7 +163,7 @@ pub fn initialize_storage_with_blocks(genesis_blocks: Vec<ChainBlock>) {
]);

CashModule::initialize_validators(vec![val_a(), val_b()]);
CashModule::initialize_starports(vec![ChainAccount::Eth([0x77; 20])]);
CashModule::initialize_starports(vec![ChainStarport::Eth(ETH_STARPORT_ADDR)]);
CashModule::initialize_genesis_blocks(genesis_blocks);
}

Expand Down
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("gateway"),
impl_name: create_runtime_str!("gateway"),
authoring_version: 1,
spec_version: 13,
spec_version: 14,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down

0 comments on commit f01c57d

Please sign in to comment.