Skip to content

Commit

Permalink
JSON serialize numbers as decimals (#1506)
Browse files Browse the repository at this point in the history
Adds two functions to be used with `(de)serialize_with`. This avoids
having to define a macro, the downside is that it makes it possible to
specify `serialize_with` without `deserialize_with`.

- Changes the serialization of ChainID and FeeAmount.
- Updates reference types. Apparently `chain_config.json` was not sorted
  before.
- Add test to check if a roundtrip works.
- Add test well as a test to check that bincode serialization is not
  affected by the customization.

Close #1496
Close #1497
  • Loading branch information
sveitser authored May 27, 2024
2 parents 39a5f44 + 6813ee7 commit daf5023
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 18 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ async-std = { version = "1.12.0", features = ["attributes", "tokio1"] }
async-trait = "0.1"
base64 = "0.22"
base64-bytes = "0.1"
bincode = "1.3.3"
blake3 = "1.5"
clap = { version = "4.4", features = ["derive", "env", "string"] }
cld = "0.5"
Expand Down
8 changes: 4 additions & 4 deletions data/chain_config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"chain_id": "0x8a19",
"max_block_size": 10240,
"base_fee": "0x0",
"base_fee": "0",
"chain_id": "35353",
"fee_contract": "0x0000000000000000000000000000000000000000",
"fee_recipient": "0x0000000000000000000000000000000000000000"
"fee_recipient": "0x0000000000000000000000000000000000000000",
"max_block_size": 10240
}
2 changes: 1 addition & 1 deletion data/fee_info.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"account": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"amount": "0x0"
"amount": "0"
}
6 changes: 3 additions & 3 deletions data/header.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"chain_config": {
"chain_config": {
"Left": {
"base_fee": "0x0",
"chain_id": "0x8a19",
"base_fee": "0",
"chain_id": "35353",
"fee_contract": "0x0000000000000000000000000000000000000000",
"fee_recipient": "0x0000000000000000000000000000000000000000",
"max_block_size": 10240
Expand All @@ -19,7 +19,7 @@
},
"fee_info": {
"account": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"amount": "0x0"
"amount": "0"
},
"fee_merkle_tree_root": "MERKLE_COMM~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAKA",
"height": 42,
Expand Down
8 changes: 4 additions & 4 deletions data/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"chain_config": {
"chain_config": {
"Left": {
"base_fee": "0x0",
"chain_id": "0x8a19",
"base_fee": "0",
"chain_id": "35353",
"fee_contract": null,
"fee_recipient": "0x0000000000000000000000000000000000000000",
"max_block_size": 10240
Expand All @@ -23,7 +23,7 @@
},
"fee_info": {
"account": "0x0000000000000000000000000000000000000000",
"amount": "0x0"
"amount": "0"
},
"fee_merkle_tree_root": "MERKLE_COMM~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAKA",
"height": 0,
Expand Down Expand Up @@ -424,4 +424,4 @@
},
"sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U"
}
]
]
3 changes: 2 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@
spell-checking = {
enable = true;
description = "Spell checking";
entry = "typos";
# --force-exclude to exclude excluded files if they are passed as arguments
entry = "typos --force-exclude";
pass_filenames = true;
# Add excludes to the .typos.toml file instead
};
Expand Down
2 changes: 1 addition & 1 deletion sequencer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async-std = { workspace = true }
async-trait = { workspace = true }
base64 = { workspace = true }
base64-bytes = { workspace = true }
bincode = "1.3.3"
bincode = { workspace = true }
blake3 = { workspace = true }
bytesize = { workspace = true }

Expand Down
10 changes: 8 additions & 2 deletions sequencer/src/chain_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ use committable::{Commitment, Committable};
use derive_more::{From, Into};
use ethers::types::{Address, U256};
use itertools::Either;
use sequencer_utils::impl_to_fixed_bytes;
use sequencer_utils::{deserialize_from_decimal, impl_to_fixed_bytes, serialize_as_decimal};
use serde::{Deserialize, Serialize};
use std::str::FromStr;

#[derive(Default, Hash, Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, From, Into)]
pub struct ChainId(U256);
pub struct ChainId(
#[serde(
serialize_with = "serialize_as_decimal",
deserialize_with = "deserialize_from_decimal"
)]
U256,
);

impl_to_fixed_bytes!(ChainId, U256);

Expand Down
10 changes: 8 additions & 2 deletions sequencer/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use jf_merkle_tree::{
};
use jf_vid::VidScheme;
use num_traits::CheckedSub;
use sequencer_utils::impl_to_fixed_bytes;
use sequencer_utils::{deserialize_from_decimal, impl_to_fixed_bytes, serialize_as_decimal};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use std::time::Duration;
Expand Down Expand Up @@ -936,7 +936,13 @@ impl Committable for FeeInfo {
Into,
)]
#[display(fmt = "{_0}")]
pub struct FeeAmount(U256);
pub struct FeeAmount(
#[serde(
serialize_with = "serialize_as_decimal",
deserialize_with = "deserialize_from_decimal"
)]
U256,
);

impl_to_fixed_bytes!(FeeAmount, U256);

Expand Down
4 changes: 4 additions & 0 deletions utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ ethers = { workspace = true }
futures = { workspace = true }
hotshot-contract-adapter ={ path = "../contracts/rust/adapter" }
portpicker = { workspace = true }
serde = { workspace = true }
serde_json = "^1.0.113"
surf = "2.3.2"
tempfile = "3.9.0"
tracing = "0.1.37"
url = "2.3.1"

[dev-dependencies]
bincode = { workspace = true }
62 changes: 62 additions & 0 deletions utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use ethers::{
signers::{coins_bip39::English, Signer as _},
types::U256,
};
use serde::{Deserialize as _, Serialize as _};
use std::path::{Path, PathBuf};
use std::time::Duration;
use std::{
Expand Down Expand Up @@ -348,6 +349,31 @@ macro_rules! impl_to_fixed_bytes {
};
}

/// Serialize a U256 type as a decimal string for human readable serialization
pub fn serialize_as_decimal<S>(value: &U256, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
serializer.serialize_str(&value.to_string())
} else {
value.serialize(serializer)
}
}

/// Deserialize a U256 type from a decimal string for human readable serialization
pub fn deserialize_from_decimal<'de, D>(deserializer: D) -> Result<U256, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
let s = String::deserialize(deserializer)?;
U256::from_dec_str(&s).map_err(serde::de::Error::custom)
} else {
U256::deserialize(deserializer)
}
}

/// send a transaction and wait for confirmation before returning the tx receipt and block included.
pub async fn contract_send<M: Middleware, T: Detokenize, E>(
call: &ContractCall<M, T>,
Expand Down Expand Up @@ -440,6 +466,8 @@ async fn wait_for_transaction_to_be_mined<P: JsonRpcClient>(
mod test {
use super::*;
use committable::RawCommitmentBuilder;
use serde::{Deserialize, Serialize};
use serde_json::Value;

struct TestCommittable;

Expand All @@ -456,4 +484,38 @@ mod test {
u256_to_commitment(commitment_to_u256(TestCommittable.commit())).unwrap()
);
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct AsDecimal(
#[serde(
serialize_with = "serialize_as_decimal",
deserialize_with = "deserialize_from_decimal"
)]
U256,
);

#[test]
fn test_serde_json_as_decimal() {
let value = AsDecimal(U256::from(123));
let serialized = serde_json::to_string(&value).unwrap();

// The value is serialized as decimal string
let json_value: Value = serde_json::from_str(&serialized).unwrap();
assert_eq!(json_value.as_str().unwrap(), "123");

// Deserialization produces the original value
let deserialized: AsDecimal = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized, value);
}

#[test]
fn test_serde_bincode_unchanged() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct AsDefault(U256);
let custom = AsDecimal(U256::from(123));
let default = AsDefault(U256::from(123));
assert_eq!(
bincode::serialize(&custom).unwrap(),
bincode::serialize(&default).unwrap(),
);
}
}

0 comments on commit daf5023

Please sign in to comment.