Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
4975: Changing Transaction::V1 json serialization r=zajko a=zajko

TransactionV1Payload::fields from now will be serialized as a human-readable JSON. Uptill now it was a map of <u16, Bytes>, currently it will be serialized as <String, serde_json::Value>. An example Transaction::V1 json representation will look like:

```json
{
  "Version1": {
    "hash": "5e8d4e9ad52a4aad34515fc4a8620166e37de362054b7916ea5d01c671217101",
    "payload": {
      "initiator_addr": {
        "PublicKey": "0126c6506b6e200c8a5501571bbed5de32c44b979a8f1fb36f36f585d823562935"
      },
      "timestamp": "2020-08-07T01:31:28.867Z",
      "ttl": "5m 1s 253ms",
      "chain_name": "cjain-1",
      "pricing_mode": {
        "Fixed": {
          "additional_computation_factor": 0,
          "gas_price_tolerance": 5
        }
      },
      "fields": {
        "args": {
          "Named": [
            [
              "xyz",
              {
                "bytes": "0d0000001af81d860f238f832b8f8e648c",
                "cl_type": {
                  "List": "U8"
                }
              }
            ]
          ]
        },
        "entry_point": "AddBid",
        "scheduling": {
          "FutureEra": 195120
        },
        "target": "Native"
      }
    },
    "approvals": [
      {
        "signer": "0126c6506b6e200c8a5501571bbed5de32c44b979a8f1fb36f36f585d823562935",
        "signature": "015d5c48f6dbc44ba6ca7202fc5bc9cf9861586f1762343fe29812bac0b96b63b89f4daa97ff37423e75a127cef163bcd9f6fcbe94e3743160814b12a8407fa107"
      }
    ]
  }
}

```

Co-authored-by: Jakub Zajkowski <[email protected]>
  • Loading branch information
casperlabs-bors-ng[bot] and Jakub Zajkowski authored Nov 23, 2024
2 parents 194e50b + f68c7ac commit ef376e6
Show file tree
Hide file tree
Showing 10 changed files with 416 additions and 149 deletions.
16 changes: 8 additions & 8 deletions Cargo.lock

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

52 changes: 31 additions & 21 deletions node/src/types/transaction/meta_transaction/meta_transaction_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ const ARGS_MAP_KEY: u16 = 0;
const TARGET_MAP_KEY: u16 = 1;
const ENTRY_POINT_MAP_KEY: u16 = 2;
const SCHEDULING_MAP_KEY: u16 = 3;
const TRANSFERRED_VALUE_MAP_KEY: u16 = 4;
const SEED_MAP_KEY: u16 = 5;
const EXPECTED_NUMBER_OF_FIELDS: usize = 6;
const EXPECTED_NUMBER_OF_FIELDS: usize = 4;

#[derive(Clone, Debug, Serialize, DataSize)]
pub struct MetaTransactionV1 {
Expand All @@ -37,8 +35,6 @@ pub struct MetaTransactionV1 {
approvals: BTreeSet<Approval>,
serialized_length: usize,
payload_hash: Digest,
transferred_value: u64,
seed: Option<[u8; 32]>,
has_valid_hash: Result<(), InvalidTransactionV1>,
#[serde(skip)]
#[data_size(skip)]
Expand All @@ -64,14 +60,6 @@ impl MetaTransactionV1 {
v1.deserialize_field(SCHEDULING_MAP_KEY).map_err(|error| {
InvalidTransaction::V1(InvalidTransactionV1::CouldNotDeserializeField { error })
})?;
let transferred_value =
v1.deserialize_field(TRANSFERRED_VALUE_MAP_KEY)
.map_err(|error| {
InvalidTransaction::V1(InvalidTransactionV1::CouldNotDeserializeField { error })
})?;
let seed = v1.deserialize_field(SEED_MAP_KEY).map_err(|error| {
InvalidTransaction::V1(InvalidTransactionV1::CouldNotDeserializeField { error })
})?;

if v1.number_of_fields() != EXPECTED_NUMBER_OF_FIELDS {
return Err(InvalidTransaction::V1(
Expand Down Expand Up @@ -108,8 +96,6 @@ impl MetaTransactionV1 {
serialized_length,
payload_hash,
approvals,
transferred_value,
seed,
has_valid_hash,
))
}
Expand Down Expand Up @@ -149,8 +135,6 @@ impl MetaTransactionV1 {
serialized_length: usize,
payload_hash: Digest,
approvals: BTreeSet<Approval>,
transferred_value: u64,
seed: Option<[u8; 32]>,
has_valid_hash: Result<(), InvalidTransactionV1>,
) -> Self {
Self {
Expand All @@ -169,8 +153,6 @@ impl MetaTransactionV1 {
serialized_length,
payload_hash,
has_valid_hash,
transferred_value,
seed,
is_verified: OnceCell::new(),
}
}
Expand Down Expand Up @@ -654,12 +636,40 @@ impl MetaTransactionV1 {

/// Returns the seed of the transaction.
pub(crate) fn seed(&self) -> Option<[u8; 32]> {
self.seed
match &self.target {
TransactionTarget::Native => None,
TransactionTarget::Stored {
id: _,
runtime: _,
transferred_value: _,
} => None,
TransactionTarget::Session {
is_install_upgrade: _,
runtime: _,
module_bytes: _,
transferred_value: _,
seed,
} => *seed,
}
}

/// Returns the transferred value of the transaction.
pub fn transferred_value(&self) -> u64 {
self.transferred_value
match &self.target {
TransactionTarget::Native => 0,
TransactionTarget::Stored {
id: _,
runtime: _,
transferred_value,
} => *transferred_value,
TransactionTarget::Session {
is_install_upgrade: _,
runtime: _,
module_bytes: _,
transferred_value,
seed: _,
} => *transferred_value,
}
}
}

Expand Down
9 changes: 3 additions & 6 deletions resources/test/sse_data_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1577,11 +1577,10 @@
},
"uniqueItems": true
}
},
"additionalProperties": false
}
},
"TransactionV1Payload": {
"description": "A unit of work sent by a client to the network, which when executed can cause global state to be altered.",
"description": "Internal payload of the transaction. The actual data over which the signing is done.",
"type": "object",
"required": [
"chain_name",
Expand Down Expand Up @@ -1609,9 +1608,7 @@
},
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/Bytes"
}
"additionalProperties": true
}
},
"additionalProperties": false
Expand Down
2 changes: 1 addition & 1 deletion types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ proptest = { version = "1.0.0", optional = true }
proptest-derive = { version = "0.3.0", optional = true }
rand = { version = "0.8.3", default-features = false, features = ["small_rng"] }
rand_pcg = { version = "0.3.0", optional = true }
schemars = { version = "0.8.16", features = ["preserve_order"], optional = true }
schemars = { version = "0.8.21", features = ["preserve_order"], optional = true }
serde-map-to-array = "1.1.0"
serde = { version = "1", default-features = false, features = ["alloc", "derive"] }
serde_bytes = { version = "0.11.5", default-features = false, features = ["alloc"] }
Expand Down
33 changes: 5 additions & 28 deletions types/src/cl_value.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
use alloc::vec::Vec;
use alloc::{string::String, vec::Vec};
use core::fmt::{self, Display, Formatter};

#[cfg(feature = "json-schema")]
use crate::checksummed_hex;
use crate::{
bytesrepr::{self, Bytes, FromBytes, ToBytes, U32_SERIALIZED_LENGTH},
CLType, CLTyped,
checksummed_hex, CLType, CLTyped,
};
#[cfg(feature = "datasize")]
use datasize::DataSize;
#[cfg(feature = "json-schema")]
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
#[cfg(feature = "json-schema")]
use serde::de::Error as SerdeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "json-schema")]
use serde_json::Value;

Expand Down Expand Up @@ -219,20 +215,20 @@ impl JsonSchema for CLValue {
#[serde(deny_unknown_fields)]
#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
#[cfg_attr(feature = "json-schema", schemars(rename = "CLValue"))]
#[cfg(feature = "json-schema")]
struct CLValueJson {
cl_type: CLType,
bytes: String,
#[cfg(feature = "json-schema")]
parsed: Option<Value>,
}

#[cfg(feature = "json-schema")]
impl Serialize for CLValue {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
CLValueJson {
cl_type: self.cl_type.clone(),
bytes: base16::encode_lower(&self.bytes),
#[cfg(feature = "json-schema")]
parsed: jsonrepr::cl_value_to_json(self),
}
.serialize(serializer)
Expand All @@ -242,14 +238,6 @@ impl Serialize for CLValue {
}
}

#[cfg(not(feature = "json-schema"))]
impl Serialize for CLValue {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
(&self.cl_type, &self.bytes).serialize(serializer)
}
}

#[cfg(feature = "json-schema")]
impl<'de> Deserialize<'de> for CLValue {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let (cl_type, bytes) = if deserializer.is_human_readable() {
Expand All @@ -268,17 +256,6 @@ impl<'de> Deserialize<'de> for CLValue {
}
}

#[cfg(not(feature = "json-schema"))]
impl<'de> Deserialize<'de> for CLValue {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let (cl_type, bytes) = <(CLType, Vec<u8>)>::deserialize(deserializer)?;
Ok(CLValue {
cl_type,
bytes: bytes.into(),
})
}
}

#[cfg(test)]
mod tests {
use alloc::string::ToString;
Expand Down
12 changes: 10 additions & 2 deletions types/src/gens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,14 @@ pub fn transaction_scheduling_arb() -> impl Strategy<Value = TransactionScheduli
]
}

pub fn json_compliant_transaction_scheduling_arb() -> impl Strategy<Value = TransactionScheduling> {
prop_oneof![
Just(TransactionScheduling::Standard),
era_id_arb().prop_map(TransactionScheduling::FutureEra),
timestamp_arb().prop_map(TransactionScheduling::FutureTimestamp),
]
}

pub fn transaction_invocation_target_arb() -> impl Strategy<Value = TransactionInvocationTarget> {
prop_oneof![
addressable_entity_hash_arb().prop_map(TransactionInvocationTarget::new_invocable_entity),
Expand Down Expand Up @@ -1171,7 +1179,7 @@ pub fn initiator_addr_arb() -> impl Strategy<Value = InitiatorAddr> {

pub fn timestamp_arb() -> impl Strategy<Value = Timestamp> {
//The weird u64 value is the max milliseconds that are bofeore year 10000. 5 digit years are
// not rfc3339 compliant and will cause an error
// not rfc3339 compliant and will cause an error when trying to serialize to json.
prop_oneof![Just(0_u64), Just(1_u64), Just(253_402_300_799_999_u64)].prop_map(Timestamp::from)
}

Expand All @@ -1183,7 +1191,7 @@ pub fn legal_v1_transaction_arb() -> impl Strategy<Value = TransactionV1> {
pricing_mode_arb(),
secret_key_arb_no_system(),
transaction_args_arb(),
transaction_scheduling_arb(),
json_compliant_transaction_scheduling_arb(),
legal_target_entry_point_calls_arb(),
)
.prop_map(
Expand Down
Loading

0 comments on commit ef376e6

Please sign in to comment.