Skip to content

Commit 6390873

Browse files
authored
BEP466 (#80)
1 parent c13880b commit 6390873

File tree

9 files changed

+96
-76
lines changed

9 files changed

+96
-76
lines changed

.github/workflows/ci.yaml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,19 @@ jobs:
4242
command: test
4343
args: --release --features=std --manifest-path light-client/Cargo.toml
4444
- uses: actions-rs/cargo@v1
45-
name: unit-test-dev-test
45+
name: unit-test-dev-test-min
4646
with:
4747
command: test
48-
args: --release --features=dev --manifest-path light-client/Cargo.toml --lib test::dev_test
48+
args: --release --features=dev --manifest-path light-client/Cargo.toml --lib test::dev_test_min
4949
env:
5050
MINIMUM_TIMESTAMP_SUPPORTED: 1731495592
5151
MINIMUM_HEIGHT_SUPPORTED: 100
52+
- uses: actions-rs/cargo@v1
53+
name: unit-test-dev-test-pascal
54+
with:
55+
command: test
56+
args: --release --features=dev --manifest-path light-client/Cargo.toml --lib test::dev_test_pascal
57+
env:
58+
MINIMUM_TIMESTAMP_SUPPORTED: 1
59+
MINIMUM_HEIGHT_SUPPORTED: 1
60+
PASCAL_TIMESTAMP: 1

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,14 @@ This is available in dev feature only.
2525

2626
```sh
2727
BSC_BLOCKS_PER_EPOCH=20 cargo build --features=dev
28-
```
28+
```
29+
30+
### Build Parameters
31+
32+
Parameters can be specified to check for acceptable headers at build time.
33+
34+
| Name | Description |
35+
| --- |-------------------------------------------------------------------------------------------------------------------------------------------------|
36+
| `MINIMUM_TIMESTAMP_SUPPORTED` | Timestamp of the lowest header this light client will accept |
37+
| `MINIMUM_HEIGHT_SUPPORTED` | Height of the lowest header this light client will accept |
38+
| `PASCAL_TIMESTAMP` | Timestamp of the first Pascal Hardfork header, used to check the header structure after Pascal Hardfork; if 0 is specified, no check is made. |

light-client/build.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@ fn main() {
2020
std::env::var("MINIMUM_TIMESTAMP_SUPPORTED").unwrap_or_else(|_| "0".to_string());
2121
let minimum_height_supported =
2222
std::env::var("MINIMUM_HEIGHT_SUPPORTED").unwrap_or_else(|_| "0".to_string());
23+
let pascal_timestamp =
24+
std::env::var("PASCAL_TIMESTAMP").unwrap_or_else(|_| "0".to_string());
2325
writeln!(
2426
file,
25-
"pub const MINIMUM_TIMESTAMP_SUPPORTED: u64 = {};\npub const MINIMUM_HEIGHT_SUPPORTED: u64 = {};",
27+
"pub const MINIMUM_TIMESTAMP_SUPPORTED: u64 = {};\npub const MINIMUM_HEIGHT_SUPPORTED: u64 = {};\npub const PASCAL_TIMESTAMP: u64 = {};",
2628
minimum_time_stamp_supported,
27-
minimum_height_supported
29+
minimum_height_supported,
30+
pascal_timestamp
2831
)
2932
.unwrap();
3033
}

light-client/src/client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ mod test {
606606
fn test_error_create_client() {
607607
let client_state = hex!("0a272f6962632e6c69676874636c69656e74732e7061726c69612e76312e436c69656e745374617465124d08381214151f3951fa218cac426edfe078fa9e5c6dcea5001a2000000000000000000000000000000000000000000000000000000000000000002205109b9ea90f2a040880a305320410c0843d").to_vec();
608608
let consensus_state = hex!("0a2a2f6962632e6c69676874636c69656e74732e7061726c69612e76312e436f6e73656e7375735374617465126c0a2056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42110de82d5a8061a209c59cf0b5717cb6e2bd8620b7f3481605c8abcd45636bdf45c86db06338f0c5e22207a1dede35f5c835fecdc768324928cd0d9d9161e8529e1ba1e60451f3a9d088a").to_vec();
609-
let client = ParliaLightClient::default();
609+
let client = ParliaLightClient;
610610
let mock_consensus_state = BTreeMap::new();
611611
let ctx = MockClientReader {
612612
client_state: None,
@@ -1156,7 +1156,7 @@ mod test {
11561156
}
11571157

11581158
#[cfg(feature = "dev")]
1159-
mod dev_test {
1159+
mod dev_test_min {
11601160
use crate::client::test::MockClientReader;
11611161
use crate::client::ParliaLightClient;
11621162
use crate::client_state::ClientState;

light-client/src/client_state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ mod test {
706706
}
707707
}
708708
#[cfg(feature = "dev")]
709-
mod dev_test {
709+
mod dev_test_min {
710710
use crate::client_state::ClientState;
711711
use crate::consensus_state::ConsensusState;
712712
use crate::errors::Error;

light-client/src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ pub enum Error {
9898
UnexpectedUntrustedValidatorsHashInEpoch(Height, Height, Hash, Hash),
9999
UnexpectedCurrentValidatorsHashInEpoch(Height, Height, Hash, Hash),
100100
UnexpectedUntrustedValidators(BlockNumber, BlockNumber),
101+
MissingRequestsHash(BlockNumber),
101102

102103
// Vote attestation
103104
UnexpectedTooManyHeadersToFinalize(BlockNumber, usize),
@@ -384,6 +385,9 @@ impl core::fmt::Display for Error {
384385
Error::UnexpectedRevisionHeight(e1) => {
385386
write!(f, "UnexpectedRevisionHeight : {}", e1)
386387
}
388+
Error::MissingRequestsHash(e1) => {
389+
write!(f, "MissingRequestsHash : {}", e1)
390+
}
387391
}
388392
}
389393
}

light-client/src/header/eth_header.rs

Lines changed: 60 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use parlia_ibc_proto::ibc::lightclients::parlia::v1::EthHeader as RawETHHeader;
1111

1212
use crate::errors::Error;
1313
use crate::header::epoch::Epoch;
14-
14+
use crate::header::hardfork::PASCAL_TIMESTAMP;
1515
use crate::header::vote_attestation::VoteAttestation;
1616
use crate::misc::{Address, BlockNumber, ChainId, Hash, RlpIterator, Validators};
1717

@@ -58,6 +58,7 @@ pub struct ETHHeader {
5858
pub blob_gas_used: Option<u64>,
5959
pub excess_blob_gas: Option<u64>,
6060
pub parent_beacon_root: Option<Vec<u8>>,
61+
pub requests_hash: Option<Vec<u8>>,
6162

6263
// calculated by RawETHHeader
6364
pub hash: Hash,
@@ -133,6 +134,11 @@ impl ETHHeader {
133134
stream.append_empty_data();
134135
}
135136
stream.append(parent_beacon_root);
137+
138+
// https://github.com/bnb-chain/bsc/blob/e2f2111a85fecabb4782099338aca21bf58bde09/core/types/block.go#L776
139+
if let Some(value) = &self.requests_hash {
140+
stream.append(value);
141+
}
136142
}
137143
}
138144
stream.finalize_unbounded_list();
@@ -378,6 +384,7 @@ impl TryFrom<RawETHHeader> for ETHHeader {
378384
let blob_gas_used: Option<u64> = rlp.try_next_as_val().map(Some).unwrap_or(None);
379385
let excess_blob_gas: Option<u64> = rlp.try_next_as_val().map(Some).unwrap_or(None);
380386
let parent_beacon_root: Option<Vec<u8>> = rlp.try_next_as_val().map(Some).unwrap_or(None);
387+
let requests_hash: Option<Vec<u8>> = rlp.try_next_as_val().map(Some).unwrap_or(None);
381388

382389
// Check that the extra-data contains the vanity, validators and signature
383390
let extra_size = extra_data.len();
@@ -415,72 +422,7 @@ impl TryFrom<RawETHHeader> for ETHHeader {
415422
return Err(Error::UnexpectedNonce(number));
416423
}
417424

418-
// create block hash
419-
let mut stream = RlpStream::new();
420-
stream.begin_unbounded_list();
421-
stream.append(&parent_hash);
422-
stream.append(&uncle_hash);
423-
stream.append(&coinbase);
424-
stream.append(&root.to_vec());
425-
stream.append(&tx_hash);
426-
stream.append(&receipt_hash);
427-
stream.append(&bloom);
428-
stream.append(&difficulty);
429-
stream.append(&number);
430-
stream.append(&gas_limit);
431-
stream.append(&gas_used);
432-
stream.append(&timestamp);
433-
stream.append(&extra_data);
434-
stream.append(&mix_digest);
435-
stream.append(&nonce);
436-
437-
if base_fee_per_gas.is_some()
438-
|| withdrawals_hash.is_some()
439-
|| blob_gas_used.is_some()
440-
|| excess_blob_gas.is_some()
441-
|| parent_beacon_root.is_some()
442-
{
443-
if let Some(v) = base_fee_per_gas {
444-
stream.append(&v);
445-
} else {
446-
stream.append_empty_data();
447-
}
448-
}
449-
if withdrawals_hash.is_some()
450-
|| blob_gas_used.is_some()
451-
|| excess_blob_gas.is_some()
452-
|| parent_beacon_root.is_some()
453-
{
454-
if let Some(v) = &withdrawals_hash {
455-
stream.append(v);
456-
} else {
457-
stream.append_empty_data();
458-
}
459-
}
460-
if blob_gas_used.is_some() || excess_blob_gas.is_some() || parent_beacon_root.is_some() {
461-
if let Some(v) = blob_gas_used {
462-
stream.append(&v);
463-
} else {
464-
stream.append_empty_data();
465-
}
466-
}
467-
if excess_blob_gas.is_some() || parent_beacon_root.is_some() {
468-
if let Some(v) = excess_blob_gas {
469-
stream.append(&v);
470-
} else {
471-
stream.append_empty_data();
472-
}
473-
}
474-
if parent_beacon_root.is_some() {
475-
if let Some(v) = &parent_beacon_root {
476-
stream.append(v);
477-
} else {
478-
stream.append_empty_data();
479-
}
480-
}
481-
stream.finalize_unbounded_list();
482-
let buffer_vec: Vec<u8> = stream.out().to_vec();
483-
let hash: Hash = keccak_256(&buffer_vec);
425+
let hash: Hash = keccak_256(value.header.as_slice());
484426

485427
let epoch = if number % BLOCKS_PER_EPOCH == 0 {
486428
let (validators, turn_length) = get_validator_bytes_and_turn_length(&extra_data)?;
@@ -489,6 +431,11 @@ impl TryFrom<RawETHHeader> for ETHHeader {
489431
None
490432
};
491433

434+
#[allow(clippy::absurd_extreme_comparisons)]
435+
if PASCAL_TIMESTAMP > 0 && timestamp >= PASCAL_TIMESTAMP && requests_hash.is_none() {
436+
return Err(Error::MissingRequestsHash(number));
437+
}
438+
492439
Ok(Self {
493440
parent_hash,
494441
uncle_hash,
@@ -510,6 +457,7 @@ impl TryFrom<RawETHHeader> for ETHHeader {
510457
withdrawals_hash,
511458
blob_gas_used,
512459
parent_beacon_root,
460+
requests_hash,
513461
hash,
514462
epoch,
515463
})
@@ -527,9 +475,11 @@ pub(crate) mod test {
527475
use rlp::RlpStream;
528476
use rstest::*;
529477

530-
use crate::fixture::{localnet, Network};
478+
use crate::fixture::{decode_header, localnet, Network};
531479
use crate::header::epoch::Epoch;
480+
532481
use alloc::boxed::Box;
482+
use hex_literal::hex;
533483
use parlia_ibc_proto::ibc::lightclients::parlia::v1::EthHeader as RawETHHeader;
534484

535485
fn to_raw(header: &ETHHeader) -> RawETHHeader {
@@ -871,4 +821,46 @@ pub(crate) mod test {
871821
err => unreachable!("{:?}", err),
872822
}
873823
}
824+
#[test]
825+
fn test_success_bep466_header() {
826+
let header = hex!("f90370a04a99d244666a287d9aaa1a81aa5bba573f156865369023eaa53a4ba8bb303ad1a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794e04db2de85453e0936b441c339a26d10cfa71b50a0d0a25a7c6b93d5d2e8f7e2075d2886fa62840f31c127b880b7cd503e2d364163a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000282071b8402625a008084678f4827b90111d883010503846765746888676f312e32332e35856c696e75780000002f5b9772f8ae0fb860959e5c417ecd8a5e5ddabd85485cf2cc4433f26beea076d77bbc6f461e4129881b8772bdae5fdd6ca927b571662ac5750d4abeca4f44a4406ab3254e0d98e6ee92b5b6396122853b45db2d18d24fb79e8397e253ca10a2a03b3b18e5961173b5f848820719a0e5ef3de482ecc3de5aea0efb17457d7edc5b1a39fc97c29cc5780b4665c9ca2082071aa04a99d244666a287d9aaa1a81aa5bba573f156865369023eaa53a4ba8bb303ad180aba9a203cbc9ac6e2eabbc44b15f7c526ec5f9d570a0addc005d5958d8415f760794e65762057ff9956dce68034d30cca6d9cc2ac3eb35f699d47c74931c470a01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").to_vec();
827+
let header = decode_header(header);
828+
let chain_id = localnet().network();
829+
830+
let prev_epoch = hex!("f90484a0cdbf04705a1f6ed4989217c1e89f4c0ab22b3122df2f48c09e2fef3d0aa4b5b4a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b2e42bc54d19116d2348ac83461e2e0915d508ada08b3fad7b45691957d1bf905d2601a14e12d48d1da89205d22b4eb582af803e3da0629579638c8423e2836b6ad04eed7a7dcda123a3f4b6d2ab488121fac9df6c10a03cd1ebc99cd975182c58de47be968c97658cff4c465e20654185f408a851403cb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028207088402625a008229a884678f47eeb90223d883010503846765746888676f312e32332e35856c696e75780000002f5b9772048fdaaa7e6631e438625ca25c857a3727ea28e565b5ad484c80ff8ed9a2aff68923f36e8975c377abd0c62a8a66ac0d2519b3eb4c14951312006c9e8b3829dc68cab6bcf0a7876ea32e7a748c697d01345145485561305b24958ec28bac0db09ee3e6cfc1769fd72b493a6c44118598abb600bec65e66aafd23acd46e0d1e0bda9d8101dbbdbf369fd9a13701eafb76870cb220843b8c6476824bfa15ad21d1bf47e3df7d8d99b105a24ebca95a84b035e6af22880b9eaf1d6a4a233920a57ecf09f8a6b89d7f5ca3cfe6484fe04db2de85453e0936b441c339a26d10cfa71b50b611e87c256a23edc8b7e55558abe1a7ff94262bacb53d600e657270ee6af9172c5a31c24498a162147dd7e1bfdcef9107f8ae0fb860a70e55ed7260c28c69880ca12370872c2059f0540ca88c1cb7a6ba772ed6e7f62a5e11c31e117ea483a4c6b46cf213681092f5273512ad15e030f52c3485838801a5ae99ece187028adbf6f543b34bd4a48199dc9b58ea47b16d06049a370a65f848820706a0ab18ec6cce429c9918cb4f354ffda5c0119871589de4829c9871ee7eddbce0ed820707a0cdbf04705a1f6ed4989217c1e89f4c0ab22b3122df2f48c09e2fef3d0aa4b5b48099019414f8ca7f80176785458468355225878402b80bbe64de4de083cbd909163b1c8dd0564e07516e6bbd0ec64381847f8f3d94d75992fd04243b538ba9348d01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").to_vec();
831+
let prev_epoch = decode_header(prev_epoch);
832+
833+
header
834+
.verify_seal(&prev_epoch.epoch.unwrap(), &chain_id)
835+
.unwrap();
836+
assert!(&header.requests_hash.is_some());
837+
assert_eq!(32, header.requests_hash.unwrap().len());
838+
}
839+
840+
#[cfg(feature = "dev")]
841+
mod dev_test_pascal {
842+
use crate::errors::Error;
843+
use crate::fixture::{decode_header, localnet};
844+
use crate::header::eth_header::ETHHeader;
845+
use hex_literal::hex;
846+
use parlia_ibc_proto::ibc::lightclients::parlia::v1::EthHeader;
847+
848+
#[test]
849+
fn test_error_missing_request_hash() {
850+
// number = 401
851+
let raw_header = localnet().epoch_header_plus_1_rlp();
852+
let raw_header = EthHeader { header: raw_header };
853+
let result = ETHHeader::try_from(raw_header).unwrap_err();
854+
match result {
855+
Error::MissingRequestsHash(_) => {}
856+
_ => unreachable!(),
857+
}
858+
}
859+
860+
#[test]
861+
fn test_success_after_bep466() {
862+
let header = hex!("f90370a04a99d244666a287d9aaa1a81aa5bba573f156865369023eaa53a4ba8bb303ad1a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794e04db2de85453e0936b441c339a26d10cfa71b50a0d0a25a7c6b93d5d2e8f7e2075d2886fa62840f31c127b880b7cd503e2d364163a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000282071b8402625a008084678f4827b90111d883010503846765746888676f312e32332e35856c696e75780000002f5b9772f8ae0fb860959e5c417ecd8a5e5ddabd85485cf2cc4433f26beea076d77bbc6f461e4129881b8772bdae5fdd6ca927b571662ac5750d4abeca4f44a4406ab3254e0d98e6ee92b5b6396122853b45db2d18d24fb79e8397e253ca10a2a03b3b18e5961173b5f848820719a0e5ef3de482ecc3de5aea0efb17457d7edc5b1a39fc97c29cc5780b4665c9ca2082071aa04a99d244666a287d9aaa1a81aa5bba573f156865369023eaa53a4ba8bb303ad180aba9a203cbc9ac6e2eabbc44b15f7c526ec5f9d570a0addc005d5958d8415f760794e65762057ff9956dce68034d30cca6d9cc2ac3eb35f699d47c74931c470a01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").to_vec();
863+
decode_header(header);
864+
}
865+
}
874866
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub const MINIMUM_TIMESTAMP_SUPPORTED: u64 = 0;
22
pub const MINIMUM_HEIGHT_SUPPORTED: u64 = 0;
3+
pub const PASCAL_TIMESTAMP: u64 = 0;

light-client/src/header/vote_attestation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ mod test {
242242
blob_gas_used: None,
243243
excess_blob_gas: None,
244244
parent_beacon_root: None,
245+
requests_hash: None,
245246
hash: [0u8; 32],
246247
epoch: None,
247248
};

0 commit comments

Comments
 (0)