From 9cef6a581469fbe98a7f0da4f5ee55b4b6fbe6da Mon Sep 17 00:00:00 2001 From: Kirk Baird Date: Mon, 18 Mar 2019 18:11:46 +1100 Subject: [PATCH] Finish implementing Darrens migrate-ssz-little-endian and add wrapper to check for ssz underflow --- .../db/src/stores/beacon_block_store.rs | 6 +- .../db/src/stores/beacon_state_store.rs | 6 +- beacon_node/db/src/stores/validator_store.rs | 6 +- beacon_node/src/rpc/validator.rs | 4 +- eth2/types/src/test_utils/macros.rs | 4 +- eth2/utils/bls/src/aggregate_signature.rs | 4 +- eth2/utils/bls/src/public_key.rs | 5 +- eth2/utils/bls/src/secret_key.rs | 8 +- eth2/utils/bls/src/signature.rs | 9 +- eth2/utils/boolean-bitfield/src/lib.rs | 13 +-- eth2/utils/ssz/src/decode.rs | 20 +++-- eth2/utils/ssz/src/encode.rs | 2 +- eth2/utils/ssz/src/impl_decode.rs | 88 +++++++++++++------ eth2/utils/ssz/src/impl_encode.rs | 4 +- eth2/utils/ssz/src/lib.rs | 2 +- .../beacon_block_grpc_client.rs | 6 +- 16 files changed, 114 insertions(+), 73 deletions(-) diff --git a/beacon_node/db/src/stores/beacon_block_store.rs b/beacon_node/db/src/stores/beacon_block_store.rs index 92d296c373..f22c629e08 100644 --- a/beacon_node/db/src/stores/beacon_block_store.rs +++ b/beacon_node/db/src/stores/beacon_block_store.rs @@ -1,6 +1,6 @@ use super::BLOCKS_DB_COLUMN as DB_COLUMN; use super::{ClientDB, DBError}; -use ssz::Decodable; +use ssz::decode; use std::sync::Arc; use types::{readers::BeaconBlockReader, BeaconBlock, Hash256, Slot}; @@ -30,7 +30,7 @@ impl BeaconBlockStore { match self.get(&hash)? { None => Ok(None), Some(ssz) => { - let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError { + let block = decode::(&ssz).map_err(|_| DBError { message: "Bad BeaconBlock SSZ.".to_string(), })?; Ok(Some(block)) @@ -47,7 +47,7 @@ impl BeaconBlockStore { match self.get(&hash)? { None => Ok(None), Some(ssz) => { - let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError { + let block = decode::(&ssz).map_err(|_| DBError { message: "Bad BeaconBlock SSZ.".to_string(), })?; Ok(Some(block)) diff --git a/beacon_node/db/src/stores/beacon_state_store.rs b/beacon_node/db/src/stores/beacon_state_store.rs index ed22696cb2..581405feb3 100644 --- a/beacon_node/db/src/stores/beacon_state_store.rs +++ b/beacon_node/db/src/stores/beacon_state_store.rs @@ -1,6 +1,6 @@ use super::STATES_DB_COLUMN as DB_COLUMN; use super::{ClientDB, DBError}; -use ssz::Decodable; +use ssz::decode; use std::sync::Arc; use types::{readers::BeaconStateReader, BeaconState, Hash256}; @@ -23,7 +23,7 @@ impl BeaconStateStore { match self.get(&hash)? { None => Ok(None), Some(ssz) => { - let (state, _) = BeaconState::ssz_decode(&ssz, 0).map_err(|_| DBError { + let state = decode::(&ssz).map_err(|_| DBError { message: "Bad State SSZ.".to_string(), })?; Ok(Some(state)) @@ -40,7 +40,7 @@ impl BeaconStateStore { match self.get(&hash)? { None => Ok(None), Some(ssz) => { - let (state, _) = BeaconState::ssz_decode(&ssz, 0).map_err(|_| DBError { + let state = decode::(&ssz).map_err(|_| DBError { message: "Bad State SSZ.".to_string(), })?; Ok(Some(state)) diff --git a/beacon_node/db/src/stores/validator_store.rs b/beacon_node/db/src/stores/validator_store.rs index 02e90dc5c5..7d9c24546f 100644 --- a/beacon_node/db/src/stores/validator_store.rs +++ b/beacon_node/db/src/stores/validator_store.rs @@ -4,7 +4,7 @@ use self::bytes::{BufMut, BytesMut}; use super::VALIDATOR_DB_COLUMN as DB_COLUMN; use super::{ClientDB, DBError}; use bls::PublicKey; -use ssz::{ssz_encode, Decodable}; +use ssz::{decode, ssz_encode}; use std::sync::Arc; #[derive(Debug, PartialEq)] @@ -69,8 +69,8 @@ impl ValidatorStore { let val = self.db.get(DB_COLUMN, &key[..])?; match val { None => Ok(None), - Some(val) => match PublicKey::ssz_decode(&val, 0) { - Ok((key, _)) => Ok(Some(key)), + Some(val) => match decode::(&val) { + Ok(key) => Ok(Some(key)), Err(_) => Err(ValidatorStoreError::DecodeError), }, } diff --git a/beacon_node/src/rpc/validator.rs b/beacon_node/src/rpc/validator.rs index f894deca6b..2af78ffc95 100644 --- a/beacon_node/src/rpc/validator.rs +++ b/beacon_node/src/rpc/validator.rs @@ -6,7 +6,7 @@ use protos::services::{ }; use protos::services_grpc::ValidatorService; use slog::{debug, Logger}; -use ssz::Decodable; +use ssz::decode; #[derive(Clone)] pub struct ValidatorServiceInstance { @@ -20,7 +20,7 @@ impl ValidatorService for ValidatorServiceInstance { req: PublicKeyRequest, sink: UnarySink, ) { - if let Ok((public_key, _)) = PublicKey::ssz_decode(req.get_public_key(), 0) { + if let Ok(public_key) = decode::(req.get_public_key()) { debug!(self.log, "RPC request"; "endpoint" => "ValidatorIndex", "public_key" => public_key.concatenated_hex_id()); let mut resp = IndexResponse::new(); diff --git a/eth2/types/src/test_utils/macros.rs b/eth2/types/src/test_utils/macros.rs index f5b2fd87cb..ab86351a0c 100644 --- a/eth2/types/src/test_utils/macros.rs +++ b/eth2/types/src/test_utils/macros.rs @@ -5,13 +5,13 @@ macro_rules! ssz_tests { #[test] pub fn test_ssz_round_trip() { use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; - use ssz::{ssz_encode, Decodable}; + use ssz::{decode, ssz_encode}; let mut rng = XorShiftRng::from_seed([42; 16]); let original = $type::random_for_test(&mut rng); let bytes = ssz_encode(&original); - let (decoded, _) = $type::ssz_decode(&bytes, 0).unwrap(); + let decoded: $type = decode(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/aggregate_signature.rs b/eth2/utils/bls/src/aggregate_signature.rs index 9c5ed03750..7f6fc39c60 100644 --- a/eth2/utils/bls/src/aggregate_signature.rs +++ b/eth2/utils/bls/src/aggregate_signature.rs @@ -96,7 +96,7 @@ impl TreeHash for AggregateSignature { mod tests { use super::super::{Keypair, Signature}; use super::*; - use ssz::ssz_encode; + use ssz::{decode, ssz_encode}; #[test] pub fn test_ssz_round_trip() { @@ -106,7 +106,7 @@ mod tests { original.add(&Signature::new(&[42, 42], 0, &keypair.sk)); let bytes = ssz_encode(&original); - let (decoded, _) = AggregateSignature::ssz_decode(&bytes, 0).unwrap(); + let decoded = decode::(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/bls/src/public_key.rs b/eth2/utils/bls/src/public_key.rs index c85760bbf0..97db38161f 100644 --- a/eth2/utils/bls/src/public_key.rs +++ b/eth2/utils/bls/src/public_key.rs @@ -5,7 +5,8 @@ use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use ssz::{ - decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, + decode, decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, + TreeHash, }; use std::default; use std::hash::{Hash, Hasher}; @@ -91,7 +92,7 @@ impl<'de> Deserialize<'de> for PublicKey { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let (pubkey, _) = <_>::ssz_decode(&bytes[..], 0) + let pubkey = decode::(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(pubkey) } diff --git a/eth2/utils/bls/src/secret_key.rs b/eth2/utils/bls/src/secret_key.rs index a3914310a1..8299e1cfe4 100644 --- a/eth2/utils/bls/src/secret_key.rs +++ b/eth2/utils/bls/src/secret_key.rs @@ -3,7 +3,9 @@ use bls_aggregates::{DecodeError as BlsDecodeError, SecretKey as RawSecretKey}; use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; -use ssz::{decode_ssz_list, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz::{ + decode, decode_ssz_list, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, +}; /// A single BLS signature. /// @@ -59,9 +61,9 @@ impl<'de> Deserialize<'de> for SecretKey { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let (pubkey, _) = <_>::ssz_decode(&bytes[..], 0) + let secret_key = decode::(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; - Ok(pubkey) + Ok(secret_key) } } diff --git a/eth2/utils/bls/src/signature.rs b/eth2/utils/bls/src/signature.rs index 47598bc66d..6b7a743d77 100644 --- a/eth2/utils/bls/src/signature.rs +++ b/eth2/utils/bls/src/signature.rs @@ -5,7 +5,8 @@ use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use ssz::{ - decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, + decode, decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, + TreeHash, }; /// A single BLS signature. @@ -99,9 +100,9 @@ impl<'de> Deserialize<'de> for Signature { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let (pubkey, _) = <_>::ssz_decode(&bytes[..], 0) + let signature = decode::(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; - Ok(pubkey) + Ok(signature) } } @@ -118,7 +119,7 @@ mod tests { let original = Signature::new(&[42, 42], 0, &keypair.sk); let bytes = ssz_encode(&original); - let (decoded, _) = Signature::ssz_decode(&bytes, 0).unwrap(); + let decoded = decode::(&bytes).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index 4dec380ad0..0a02a98f3d 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -4,6 +4,7 @@ extern crate ssz; use bit_vec::BitVec; use serde::ser::{Serialize, Serializer}; +use ssz::{Decodable, Encodable}; use std::cmp; use std::default; @@ -141,14 +142,14 @@ impl std::ops::BitAnd for BooleanBitfield { } } -impl ssz::Encodable for BooleanBitfield { +impl Encodable for BooleanBitfield { // ssz_append encodes Self according to the `ssz` spec. fn ssz_append(&self, s: &mut ssz::SszStream) { s.append_vec(&self.to_bytes()) } } -impl ssz::Decodable for BooleanBitfield { +impl Decodable for BooleanBitfield { fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), ssz::DecodeError> { let len = ssz::decode::decode_length(bytes, index, ssz::LENGTH_BYTES)?; if (ssz::LENGTH_BYTES + len) > bytes.len() { @@ -195,7 +196,7 @@ impl ssz::TreeHash for BooleanBitfield { #[cfg(test)] mod tests { use super::*; - use ssz::{ssz_encode, Decodable, SszStream}; + use ssz::{decode, ssz_encode, SszStream}; #[test] fn test_new_bitfield() { @@ -385,12 +386,12 @@ mod tests { #[test] fn test_ssz_decode() { let encoded = vec![2, 0, 0, 0, 225, 192]; - let (field, _): (BooleanBitfield, usize) = ssz::decode_ssz(&encoded, 0).unwrap(); + let field = decode::(&encoded).unwrap(); let expected = create_test_bitfield(); assert_eq!(field, expected); let encoded = vec![3, 0, 0, 0, 255, 255, 3]; - let (field, _): (BooleanBitfield, usize) = ssz::decode_ssz(&encoded, 0).unwrap(); + let field = decode::(&encoded).unwrap(); let expected = BooleanBitfield::from_bytes(&[255, 255, 3]); assert_eq!(field, expected); } @@ -399,7 +400,7 @@ mod tests { fn test_ssz_round_trip() { let original = BooleanBitfield::from_bytes(&vec![18; 12][..]); let ssz = ssz_encode(&original); - let (decoded, _) = BooleanBitfield::ssz_decode(&ssz, 0).unwrap(); + let decoded = decode::(&ssz).unwrap(); assert_eq!(original, decoded); } diff --git a/eth2/utils/ssz/src/decode.rs b/eth2/utils/ssz/src/decode.rs index 7b01d62815..efc8c38db8 100644 --- a/eth2/utils/ssz/src/decode.rs +++ b/eth2/utils/ssz/src/decode.rs @@ -13,16 +13,22 @@ pub trait Decodable: Sized { /// Decode the given bytes for the given type /// -/// The single ssz encoded value will be decoded as the given type at the -/// given index. -pub fn decode_ssz(ssz_bytes: &[u8], index: usize) -> Result<(T, usize), DecodeError> +/// The single ssz encoded value/container/list will be decoded as the given type, +/// by recursively calling `ssz_decode`. +pub fn decode(ssz_bytes: &[u8]) -> Result<(T), DecodeError> where T: Decodable, { - if index >= ssz_bytes.len() { - return Err(DecodeError::TooShort); + let (decoded, i): (T, usize) = match T::ssz_decode(ssz_bytes, 0) { + Err(e) => return Err(e), + Ok(v) => v, + }; + + if i < ssz_bytes.len() { + return Err(DecodeError::TooLong); } - T::ssz_decode(ssz_bytes, index) + + Ok(decoded) } /// Decode a vector (list) of encoded bytes. @@ -82,7 +88,7 @@ pub fn decode_length( .take(index + length_bytes) .skip(index) { - let offset = (length_bytes - (length_bytes - (i - index))) * 8; + let offset = (i - index) * 8; len |= (*byte as usize) << offset; } Ok(len) diff --git a/eth2/utils/ssz/src/encode.rs b/eth2/utils/ssz/src/encode.rs index 3de83c7305..e1484c4c4f 100644 --- a/eth2/utils/ssz/src/encode.rs +++ b/eth2/utils/ssz/src/encode.rs @@ -76,7 +76,7 @@ pub fn encode_length(len: usize, length_bytes: usize) -> Vec { assert!((len as usize) < 2usize.pow(length_bytes as u32 * 8)); let mut header: Vec = vec![0; length_bytes]; for (i, header_byte) in header.iter_mut().enumerate() { - let offset = (length_bytes - (length_bytes - i)) * 8; + let offset = i * 8; *header_byte = ((len >> offset) & 0xff) as u8; } header diff --git a/eth2/utils/ssz/src/impl_decode.rs b/eth2/utils/ssz/src/impl_decode.rs index 7af6a7ab29..6aebf9182d 100644 --- a/eth2/utils/ssz/src/impl_decode.rs +++ b/eth2/utils/ssz/src/impl_decode.rs @@ -12,7 +12,7 @@ macro_rules! impl_decodable_for_uint { let end_bytes = index + max_bytes; let mut result: $type = 0; for (i, byte) in bytes.iter().enumerate().take(end_bytes).skip(index) { - let offset = (end_bytes - (end_bytes - (i - index))) * 8; + let offset = (i - index) * 8; result |= ($type::from(*byte)) << offset; } Ok((result, end_bytes)) @@ -46,7 +46,7 @@ impl Decodable for bool { } else { let result = match bytes[index] { 0b0000_0000 => false, - 0b1000_0000 => true, + 0b0000_0001 => true, _ => return Err(DecodeError::Invalid), }; Ok((result, index + 1)) @@ -85,7 +85,7 @@ where #[cfg(test)] mod tests { - use super::super::{decode_ssz, DecodeError}; + use super::super::{decode, DecodeError}; use super::*; #[test] @@ -119,131 +119,161 @@ mod tests { fn test_ssz_decode_u16() { let ssz = vec![0, 0]; - let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(result, 0); assert_eq!(index, 2); let ssz = vec![16, 0]; - let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(result, 16); assert_eq!(index, 2); let ssz = vec![0, 1]; - let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(result, 256); assert_eq!(index, 2); let ssz = vec![255, 255]; - let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 2); assert_eq!(result, 65535); let ssz = vec![1]; - let result: Result<(u16, usize), DecodeError> = decode_ssz(&ssz, 0); + let result: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } #[test] fn test_ssz_decode_u32() { let ssz = vec![0, 0, 0, 0]; - let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(result, 0); assert_eq!(index, 4); let ssz = vec![0, 1, 0, 0]; - let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 4); assert_eq!(result, 256); let ssz = vec![255, 255, 255, 0, 1, 0, 0]; - let (result, index): (u32, usize) = decode_ssz(&ssz, 3).unwrap(); + let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); assert_eq!(index, 7); assert_eq!(result, 256); let ssz = vec![0, 1, 200, 0]; - let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 4); assert_eq!(result, 13107456); let ssz = vec![255, 255, 255, 255]; - let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 4); assert_eq!(result, 4294967295); let ssz = vec![1, 0, 0]; - let result: Result<(u32, usize), DecodeError> = decode_ssz(&ssz, 0); + let result: Result<(u32, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } #[test] fn test_ssz_decode_u64() { let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; - let (result, index): (u64, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 8); assert_eq!(result, 0); let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; - let (result, index): (u64, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 8); assert_eq!(result, 18446744073709551615); let ssz = vec![0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 255]; - let (result, index): (u64, usize) = decode_ssz(&ssz, 3).unwrap(); + let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); assert_eq!(index, 11); assert_eq!(result, 18374686479671623680); let ssz = vec![0, 0, 0, 0, 0, 0, 0]; - let result: Result<(u64, usize), DecodeError> = decode_ssz(&ssz, 0); + let result: Result<(u64, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } #[test] fn test_ssz_decode_usize() { let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; - let (result, index): (usize, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 8); assert_eq!(result, 0); let ssz = vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]; - let (result, index): (usize, usize) = decode_ssz(&ssz, 3).unwrap(); + let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); assert_eq!(index, 11); assert_eq!(result, 18446744073709551615); let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255, 255]; - let (result, index): (usize, usize) = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 8); assert_eq!(result, 18446744073709551615); let ssz = vec![0, 0, 0, 0, 0, 0, 1]; - let result: Result<(usize, usize), DecodeError> = decode_ssz(&ssz, 0); + let result: Result<(usize, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } #[test] fn test_decode_ssz_bounds() { - let err: Result<(u16, usize), DecodeError> = decode_ssz(&vec![1], 2); + let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![1], 2); assert_eq!(err, Err(DecodeError::TooShort)); - let err: Result<(u16, usize), DecodeError> = decode_ssz(&vec![0, 0, 0, 0], 3); + let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![0, 0, 0, 0], 3); assert_eq!(err, Err(DecodeError::TooShort)); - let result: u16 = decode_ssz(&vec![0, 0, 0, 1, 0], 3).unwrap().0; + let result: u16 = <_>::ssz_decode(&vec![0, 0, 0, 1, 0], 3).unwrap().0; assert_eq!(result, 1); } #[test] fn test_decode_ssz_bool() { - let ssz = vec![0b0000_0000, 0b1000_0000]; - let (result, index): (bool, usize) = decode_ssz(&ssz, 0).unwrap(); + let ssz = vec![0b0000_0000, 0b0000_0001]; + let (result, index): (bool, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); assert_eq!(index, 1); assert_eq!(result, false); - let (result, index): (bool, usize) = decode_ssz(&ssz, 1).unwrap(); + let (result, index): (bool, usize) = <_>::ssz_decode(&ssz, 1).unwrap(); assert_eq!(index, 2); assert_eq!(result, true); let ssz = vec![0b0100_0000]; - let result: Result<(bool, usize), DecodeError> = decode_ssz(&ssz, 0); + let result: Result<(bool, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); assert_eq!(result, Err(DecodeError::Invalid)); + + let ssz = vec![]; + let result: Result<(bool, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); + assert_eq!(result, Err(DecodeError::TooShort)); + } + + #[test] + #[should_panic] + fn test_decode_ssz_list_underflow() { + // SSZ encoded (u16::[1, 1, 1], u16::2) + let mut encoded = vec![6, 0, 0, 0, 1, 0, 1, 0, 1, 0, 2, 0]; + let (decoded_array, i): (Vec, usize) = <_>::ssz_decode(&encoded, 0).unwrap(); + let (decoded_u16, i): (u16, usize) = <_>::ssz_decode(&encoded, i).unwrap(); + assert_eq!(decoded_array, vec![1, 1, 1]); + assert_eq!(decoded_u16, 2); + assert_eq!(i, 12); + + // Underflow + encoded[0] = 4; // change length to 4 from 6 + let (decoded_array, i): (Vec, usize) = <_>::ssz_decode(&encoded, 0).unwrap(); + let (decoded_u16, _): (u16, usize) = <_>::ssz_decode(&encoded, i).unwrap(); + assert_eq!(decoded_array, vec![1, 1]); + assert_eq!(decoded_u16, 2); + } + + #[test] + fn test_decode_too_long() { + let encoded = vec![6, 0, 0, 0, 1, 0, 1, 0, 1, 0, 2]; + let decoded_array: Result, DecodeError> = decode(&encoded); + assert_eq!(decoded_array, Err(DecodeError::TooLong)); } } diff --git a/eth2/utils/ssz/src/impl_encode.rs b/eth2/utils/ssz/src/impl_encode.rs index 33332eceab..2cc8c977ab 100644 --- a/eth2/utils/ssz/src/impl_encode.rs +++ b/eth2/utils/ssz/src/impl_encode.rs @@ -48,7 +48,7 @@ impl_encodable_for_uint!(usize, 64); impl Encodable for bool { fn ssz_append(&self, s: &mut SszStream) { - let byte = if *self { 0b1000_0000 } else { 0b0000_0000 }; + let byte = if *self { 0b0000_0001 } else { 0b0000_0000 }; s.append_encoded_raw(&[byte]); } } @@ -245,6 +245,6 @@ mod tests { let x: bool = true; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0b1000_0000]); + assert_eq!(ssz.drain(), vec![0b0000_0001]); } } diff --git a/eth2/utils/ssz/src/lib.rs b/eth2/utils/ssz/src/lib.rs index 7c29667af1..6efca80584 100644 --- a/eth2/utils/ssz/src/lib.rs +++ b/eth2/utils/ssz/src/lib.rs @@ -19,7 +19,7 @@ mod impl_decode; mod impl_encode; mod impl_tree_hash; -pub use crate::decode::{decode_ssz, decode_ssz_list, Decodable, DecodeError}; +pub use crate::decode::{decode, decode_ssz_list, Decodable, DecodeError}; pub use crate::encode::{Encodable, SszStream}; pub use crate::signed_root::SignedRoot; pub use crate::tree_hash::{merkle_hash, TreeHash}; diff --git a/validator_client/src/block_producer_service/beacon_block_grpc_client.rs b/validator_client/src/block_producer_service/beacon_block_grpc_client.rs index 6ce5c0fa03..22b48d78b3 100644 --- a/validator_client/src/block_producer_service/beacon_block_grpc_client.rs +++ b/validator_client/src/block_producer_service/beacon_block_grpc_client.rs @@ -3,7 +3,7 @@ use protos::services::{ BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, }; use protos::services_grpc::BeaconBlockServiceClient; -use ssz::{ssz_encode, Decodable}; +use ssz::{decode, ssz_encode}; use std::sync::Arc; use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, Signature, Slot}; @@ -41,10 +41,10 @@ impl BeaconNode for BeaconBlockGrpcClient { if reply.has_block() { let block = reply.get_block(); - let (signature, _) = Signature::ssz_decode(block.get_signature(), 0) + let signature = decode::(block.get_signature()) .map_err(|_| BeaconNodeError::DecodeFailure)?; - let (randao_reveal, _) = Signature::ssz_decode(block.get_randao_reveal(), 0) + let randao_reveal = decode::(block.get_randao_reveal()) .map_err(|_| BeaconNodeError::DecodeFailure)?; // TODO: this conversion is incomplete; fix it.