Skip to content

Commit 1b0bbd7

Browse files
committed
chore: sync upstream changes from circle-chain-reth
Cherry-picked from circle-chain-reth public-repo branch: - crates/quake/src/infra/remote.rs: fix shell quoting in pssh command - crates/quake/terraform/cc-data.yaml: fix shell variable escaping in pssh.sh - scripts/scenarios/nightly-chaos-testing.sh: remove --seed from quake commands - crates/malachite-app/src/handlers/restream_proposal.rs: refactor block lookup - docs/installation.md: add OS-specific build dependency instructions - deployments/blockscout.yaml: add Blockscout block explorer config - deployments/monitoring/config-blockscout/backend.env: add Blockscout backend env
1 parent 85c37ec commit 1b0bbd7

7 files changed

Lines changed: 171 additions & 118 deletions

File tree

crates/malachite-app/src/handlers/restream_proposal.rs

Lines changed: 35 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ use crate::store::repositories::UndecidedBlocksRepository;
3232
/// Handles the `RestreamProposal` message from the consensus engine.
3333
///
3434
/// This is called when the consensus engine requests to restream a proposal for a specific height and round.
35-
/// If a valid round is provided, the application first fetches the block from the valid round,
36-
/// updates its round to the new round, and stores it. Then, it fetches the
37-
/// block for the specified height and round, streams the proposal parts, and sends them over the network.
35+
/// The block is looked up by height and block hash (ignoring round), so it will be found
36+
/// regardless of which round it was originally stored under. The block's round and valid_round
37+
/// are updated to match the current proposal context before restreaming.
3838
///
3939
/// ## Errors
4040
/// - If no block is found for the specified height and round
@@ -107,18 +107,17 @@ async fn get_block_to_restream(
107107
valid_round: Round,
108108
block_hash: BlockHash,
109109
) -> eyre::Result<Option<ConsensusBlock>> {
110-
if valid_round.is_defined()
111-
&& let Some(mut block) = undecided_blocks
112-
.get(height, valid_round, block_hash)
113-
.await
114-
.wrap_err_with(|| {
115-
format!(
116-
"Failed to fetch block from valid round for restreaming it \
117-
(height={height}, valid_round={valid_round}, block_hash={block_hash})"
118-
)
119-
})?
120-
{
121-
// Update the block for the new round and store it
110+
let block = undecided_blocks
111+
.get_first(height, block_hash)
112+
.await
113+
.wrap_err_with(|| {
114+
format!(
115+
"Failed to fetch block for restreaming \
116+
(height={height}, round={round}, block_hash={block_hash})"
117+
)
118+
})?;
119+
120+
if let Some(mut block) = block {
122121
block.round = round;
123122
block.valid_round = valid_round;
124123

@@ -127,24 +126,14 @@ async fn get_block_to_restream(
127126
.await
128127
.wrap_err_with(|| {
129128
format!(
130-
"Failed to store updated undecided block from valid round before restreaming it \
131-
(height={height}, valid_round={valid_round}, block_hash={block_hash})"
132-
)
133-
})?;
134-
135-
Ok(Some(block))
136-
} else {
137-
let block_to_restream = undecided_blocks
138-
.get(height, round, block_hash)
139-
.await
140-
.wrap_err_with(|| {
141-
format!(
142-
"Failed to fetch block from round for restreaming it \
129+
"Failed to store updated block before restreaming \
143130
(height={height}, round={round}, block_hash={block_hash})"
144131
)
145132
})?;
146133

147-
Ok(block_to_restream)
134+
Ok(Some(block))
135+
} else {
136+
Ok(None)
148137
}
149138
}
150139

@@ -179,25 +168,22 @@ mod tests {
179168
}
180169

181170
#[tokio::test]
182-
async fn get_block_from_valid_round_and_store_update() {
171+
async fn get_block_found_and_updated() {
183172
let mut mock_repo = MockUndecidedBlocksRepository::new();
184173

185174
let height = Height::new(10);
186-
let round = Round::new(5); // The new round we are proposing in
187-
let valid_round = Round::new(3); // The previous round where we saw the block
175+
let round = Round::new(5);
176+
let valid_round = Round::new(3);
188177
let block_hash = BlockHash::default();
189178

190-
// Original block proposed in round 3
191-
let original_block = create_dummy_block(height, valid_round, Round::Nil);
179+
let original_block = create_dummy_block(height, Round::new(0), Round::Nil);
192180

193-
// Expectation: Fetch from valid_round (3)
194181
mock_repo
195-
.expect_get()
196-
.with(eq(height), eq(valid_round), eq(block_hash))
182+
.expect_get_first()
183+
.with(eq(height), eq(block_hash))
197184
.times(1)
198-
.returning(move |_, _, _| Ok(Some(original_block.clone())));
185+
.returning(move |_, _| Ok(Some(original_block.clone())));
199186

200-
// Expectation: Store the block updated with the NEW round (5) and valid_round (3)
201187
mock_repo
202188
.expect_store()
203189
.withf(move |b| b.round == round && b.valid_round == valid_round)
@@ -207,79 +193,30 @@ mod tests {
207193
let result =
208194
get_block_to_restream(&mock_repo, height, round, valid_round, block_hash).await;
209195

210-
assert!(result.is_ok());
211-
let block = result.unwrap();
212-
assert!(block.is_some());
213-
214-
let b = block.unwrap();
215-
assert_eq!(b.round, round); // Ensure returned block has updated round
216-
assert_eq!(b.valid_round, valid_round);
217-
}
218-
219-
#[tokio::test]
220-
async fn get_block_no_valid_round_fetch_current() {
221-
let mut mock_repo = MockUndecidedBlocksRepository::new();
222-
223-
let height = Height::new(10);
224-
let round = Round::new(5);
225-
let valid_round = Round::Nil; // No valid round
226-
let block_hash = BlockHash::default();
227-
228-
// A block proposed for the first time at round 5, no valid round
229-
let current_block = create_dummy_block(height, round, valid_round);
230-
231-
// Expectation: we are restreaming this block because we received it at round 5.
232-
mock_repo
233-
.expect_get()
234-
.with(eq(height), eq(round), eq(block_hash))
235-
.times(1)
236-
.returning(move |_, _, _| Ok(Some(current_block.clone())));
237-
238-
// Expectation: Store should NOT be called
239-
mock_repo.expect_store().times(0);
240-
241-
let result =
242-
get_block_to_restream(&mock_repo, height, round, valid_round, block_hash).await;
243-
244-
assert!(result.is_ok());
245-
assert_eq!(result.unwrap().unwrap().round, round);
196+
let block = result.unwrap().expect("block should be found");
197+
assert_eq!(block.round, round);
198+
assert_eq!(block.valid_round, valid_round);
246199
}
247200

248201
#[tokio::test]
249-
async fn fallback_when_valid_round_block_missing() {
202+
async fn get_block_not_found() {
250203
let mut mock_repo = MockUndecidedBlocksRepository::new();
251204

252205
let height = Height::new(10);
253206
let round = Round::new(5);
254207
let valid_round = Round::new(3);
255208
let block_hash = BlockHash::default();
256209

257-
let block_at_current = create_dummy_block(height, round, valid_round);
258-
259-
// 1. First fetch at valid_round returns None
260-
// The proposed value can be valid for the proposer but not for us.
261-
mock_repo
262-
.expect_get()
263-
.with(eq(height), eq(valid_round), eq(block_hash))
264-
.times(1)
265-
.returning(|_, _, _| Ok(None));
266-
267-
// 2. Fallback: fetch at current round
268-
// Since it was restreamed by the proposer, we have it as current's round value.
269210
mock_repo
270-
.expect_get()
271-
.with(eq(height), eq(round), eq(block_hash))
211+
.expect_get_first()
212+
.with(eq(height), eq(block_hash))
272213
.times(1)
273-
.returning(move |_, _, _| Ok(Some(block_at_current.clone())));
274-
275-
// Store should NOT be called in the fallback path
276-
mock_repo.expect_store().times(0);
214+
.returning(|_, _| Ok(None));
277215

278216
let result =
279217
get_block_to_restream(&mock_repo, height, round, valid_round, block_hash).await;
280218

281-
assert!(result.is_ok());
282-
assert!(result.unwrap().is_some());
219+
assert!(result.unwrap().is_none());
283220
}
284221

285222
#[tokio::test]
@@ -290,8 +227,8 @@ mod tests {
290227
let valid_round = Round::Nil;
291228

292229
mock_repo
293-
.expect_get()
294-
.returning(|_, _, _| Err(std::io::Error::other("DB connection failed")));
230+
.expect_get_first()
231+
.returning(|_, _| Err(std::io::Error::other("DB connection failed")));
295232

296233
let result =
297234
get_block_to_restream(&mock_repo, height, round, valid_round, BlockHash::default())

crates/quake/src/infra/remote.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl RemoteInfra {
215215
.map(|node| self.node_private_ip(node).map(String::as_str))
216216
.collect::<Result<Vec<_>>>()?;
217217

218-
let pssh_cmd = format!("./pssh.sh \"{cmd}\" {}", node_ips.join(" "));
218+
let pssh_cmd = format!("./pssh.sh '{cmd}' {}", node_ips.join(" "));
219219
self.ssh_cc(&pssh_cmd, false)
220220
.wrap_err_with(|| format!("Failed to run '{cmd}' on {nodes:?}"))
221221
}

crates/quake/terraform/cc-data.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,23 @@ write_files:
3939
# Usage: pssh.sh "command" ip1 ip2 ip3 ...
4040
# Executes command on all IPs in parallel, fails if any command fails.
4141
set -euo pipefail
42-
CMD="$$1"
42+
CMD="$1"
4343
shift
4444
SSH_OPTS="-o StrictHostKeyChecking=no -o LogLevel=ERROR"
4545
USER="${username}"
46-
TMPDIR=$$(mktemp -d)
47-
trap "rm -rf $$TMPDIR" EXIT
46+
TMPDIR=$(mktemp -d)
47+
trap "rm -rf $TMPDIR" EXIT
4848
i=0
49-
for IP in "$$@"; do
50-
(ssh $$SSH_OPTS $$USER@$$IP "$$CMD"; echo $$? > "$$TMPDIR/$$i") &
51-
((i++))
49+
for IP in "$@"; do
50+
(ssh $SSH_OPTS $USER@$IP "$CMD"; echo $? > "$TMPDIR/$i") &
51+
i="$((i+1))"
5252
done
5353
wait
5454
FAILED=0
55-
for f in "$$TMPDIR"/*; do
56-
[ -f "$$f" ] && [ "$$(cat "$$f")" != "0" ] && FAILED=1
55+
for f in "$TMPDIR"/*; do
56+
[ -f "$f" ] && [ "$(cat "$f")" != "0" ] && FAILED=1
5757
done
58-
exit $$FAILED
58+
exit $FAILED
5959
runcmd:
6060
# Set up 4 GiB swap to prevent hard OOM kills (dd instead of fallocate for XFS compatibility)
6161
- dd if=/dev/zero of=/swapfile bs=1M count=4096

deployments/blockscout.yaml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
version: '3.9'
2+
3+
name: blockscout
4+
5+
services:
6+
proxy:
7+
image: nginx
8+
container_name: proxy
9+
extra_hosts:
10+
- 'host.docker.internal:host-gateway'
11+
volumes:
12+
- "../deployments/monitoring/config-blockscout/proxy:/etc/nginx/templates:ro"
13+
environment:
14+
BACK_PROXY_PASS: ${BACK_PROXY_PASS:-http://backend:4000}
15+
FRONT_PROXY_PASS: ${FRONT_PROXY_PASS:-http://frontend:3000}
16+
ports:
17+
- target: 80
18+
published: 80
19+
20+
frontend:
21+
image: ghcr.io/blockscout/frontend:${BLOCKSCOUT_FRONTEND_TAG:-latest}
22+
pull_policy: always
23+
restart: always
24+
container_name: 'frontend'
25+
volumes:
26+
- ../deployments/monitoring/config-blockscout/frontend/.curlrc:/home/nextjs/.curlrc:ro
27+
env_file:
28+
- ../deployments/monitoring/config-blockscout/frontend/frontend.env
29+
30+
backend:
31+
image: ghcr.io/blockscout/${BLOCKSCOUT_REPO:-blockscout}:${BLOCKSCOUT_TAG:-latest}
32+
pull_policy: always
33+
restart: always
34+
stop_grace_period: 5m
35+
container_name: 'backend'
36+
command: sh -c "bin/blockscout eval \"Elixir.Explorer.ReleaseTasks.create_and_migrate()\" && bin/blockscout start"
37+
extra_hosts:
38+
- 'host.docker.internal:host-gateway'
39+
env_file:
40+
- ../deployments/monitoring/config-blockscout/backend.env
41+
volumes:
42+
- ../deployments/volumes/blockscout/logs/:/app/logs/
43+
- ../deployments/volumes/blockscout/dets/:/app/dets/
44+
45+
db-init:
46+
image: postgres:17
47+
entrypoint:
48+
- sh
49+
- -c
50+
- |
51+
chown -R 2000:2000 /var/lib/postgresql/data
52+
53+
db:
54+
image: postgres:17
55+
user: 2000:2000
56+
shm_size: 256m
57+
restart: always
58+
container_name: 'db'
59+
command: postgres -c 'max_connections=200' -c 'client_connection_check_interval=60000'
60+
environment:
61+
POSTGRES_DB: 'blockscout'
62+
POSTGRES_USER: 'blockscout'
63+
POSTGRES_HOST_AUTH_METHOD: 'trust'
64+
ports:
65+
- target: 5432
66+
published: 7432
67+
healthcheck:
68+
test: ["CMD-SHELL", "pg_isready -U blockscout -d blockscout"]
69+
interval: 10s
70+
timeout: 5s
71+
retries: 5
72+
start_period: 10s
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
ETHEREUM_JSONRPC_VARIANT=geth
2+
DATABASE_URL=postgresql://blockscout:@db:5432/blockscout
3+
ETHEREUM_JSONRPC_TRANSPORT=http
4+
ETHEREUM_JSONRPC_DISABLE_ARCHIVE_BALANCES=false
5+
SECRET_KEY_BASE=0000000000000000000000000000000000000000000000000000000000000000
6+
PORT=4000
7+
COIN_NAME=
8+
COIN=
9+
DISABLE_MARKET=true
10+
POOL_SIZE=80
11+
POOL_SIZE_API=10
12+
ECTO_USE_SSL=false
13+
HEART_BEAT_TIMEOUT=30
14+
RELEASE_LINK=
15+
ADMIN_PANEL_ENABLED=false
16+
API_V1_READ_METHODS_DISABLED=false
17+
API_V1_WRITE_METHODS_DISABLED=false
18+
TXS_STATS_DAYS_TO_COMPILE_AT_INIT=10
19+
COIN_BALANCE_HISTORY_DAYS=90
20+
RE_CAPTCHA_DISABLED=false
21+
MICROSERVICE_SC_VERIFIER_TYPE=eth_bytecode_db
22+
MICROSERVICE_VISUALIZE_SOL2UML_ENABLED=true
23+
MICROSERVICE_VISUALIZE_SOL2UML_URL=http://visualizer:8050/
24+
MICROSERVICE_SIG_PROVIDER_ENABLED=true
25+
MICROSERVICE_SIG_PROVIDER_URL=http://sig-provider:8050/
26+
MICROSERVICE_ACCOUNT_ABSTRACTION_URL=http://user-ops-indexer:8050/
27+
DECODE_NOT_A_CONTRACT_CALLS=true
28+
ACCOUNT_CLOAK_KEY=
29+
ACCOUNT_ENABLED=false
30+
ACCOUNT_REDIS_URL=redis://redis-db:6379
31+
NFT_MEDIA_HANDLER_ENABLED=true
32+
NFT_MEDIA_HANDLER_REMOTE_DISPATCHER_NODE_MODE_ENABLED=true
33+
RELEASE_NODE=producer@172.18.0.4
34+
RELEASE_DISTRIBUTION=name
35+
RELEASE_COOKIE=secret_cookie

docs/installation.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ https://github.com/circlefin/arc-node repository:
2727
git clone https://github.com/circlefin/arc-node.git
2828
cd arc-node
2929
git checkout $VERSION
30-
git submodule update --init --recursive
3130
```
3231

3332
`$VERSION` is a tag for a released version.
@@ -43,9 +42,17 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
4342
source ~/.cargo/env
4443
```
4544

45+
With Rust installed, install the dependencies for your operating system:
46+
47+
- **Ubuntu:** `sudo apt-get install libclang-dev pkg-config build-essential`
48+
- **macOS:** `brew install llvm pkg-config`
49+
- **Windows:** `choco install llvm` or `winget install LLVM.LLVM`
50+
51+
These are needed to build bindings for Arc node execution's database.
52+
4653
**3. Build and install:**
4754

48-
The following commands produce three Arc node binaries:
55+
The following commands produce three Arc node binaries:
4956
`arc-node-execution`, `arc-node-consensus`, and `arc-snapshots`:
5057

5158
```sh
@@ -67,4 +74,3 @@ arc-snapshots --version
6774
arc-node-execution --version
6875
arc-node-consensus --version
6976
```
70-

0 commit comments

Comments
 (0)