From c59bab58d269cadc8f57ad1fdb5f35d4c8bb57b0 Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Fri, 15 Feb 2019 20:46:06 +1000 Subject: [PATCH 001/106] big to little endian, some more tests --- eth2/utils/ssz/README.md | 16 ++++---- eth2/utils/ssz/src/decode.rs | 51 ++++++++++++++++--------- eth2/utils/ssz/src/encode.rs | 62 +++++++++++++++++++++++++++---- eth2/utils/ssz/src/impl_decode.rs | 18 ++++----- eth2/utils/ssz/src/impl_encode.rs | 53 ++++++++++++++++++-------- 5 files changed, 141 insertions(+), 59 deletions(-) diff --git a/eth2/utils/ssz/README.md b/eth2/utils/ssz/README.md index 7355ca4cc..30d8ded72 100644 --- a/eth2/utils/ssz/README.md +++ b/eth2/utils/ssz/README.md @@ -69,7 +69,7 @@ Syntax: | Shorthand | Meaning | |:-------------|:----------------------------------------------------| -| `big` | ``big endian`` | +| `little` | ``little endian`` | | `to_bytes` | convert to bytes. Params: ``(size, byte order)`` | | `from_bytes` | convert from bytes. Params: ``(bytes, byte order)`` | | `value` | the value to serialize | @@ -82,7 +82,7 @@ Syntax: Convert directly to bytes the size of the int. (e.g. ``int16 = 2 bytes``) -All integers are serialized as **big endian**. +All integers are serialized as **little endian**. | Check to perform | Code | |:-----------------------|:------------------------| @@ -92,7 +92,7 @@ All integers are serialized as **big endian**. ```python buffer_size = int_size / 8 -return value.to_bytes(buffer_size, 'big') +return value.to_bytes(buffer_size, 'little') ``` #### Address @@ -131,7 +131,7 @@ For general `byte` type: value_bytes ]`` ```python -byte_length = (len(value)).to_bytes(4, 'big') +byte_length = (len(value)).to_bytes(4, 'little') return byte_length + value ``` @@ -175,12 +175,12 @@ At each step, the following checks should be made: Convert directly from bytes into integer utilising the number of bytes the same size as the integer length. (e.g. ``int16 == 2 bytes``) -All integers are interpreted as **big endian**. +All integers are interpreted as **little endian**. ```python byte_length = int_size / 8 new_index = current_index + int_size -return int.from_bytes(rawbytes[current_index:current_index+int_size], 'big'), new_index +return int.from_bytes(rawbytes[current_index:current_index+int_size], 'little'), new_index ``` #### Address @@ -206,7 +206,7 @@ return rawbytes[current_index:current_index+32], new_index Get the length of the bytes, return the bytes. ```python -bytes_length = int.from_bytes(rawbytes[current_index:current_index+4], 'big') +bytes_length = int.from_bytes(rawbytes[current_index:current_index+4], 'little') new_index = current_index + 4 + bytes_lenth return rawbytes[current_index+4:current_index+4+bytes_length], new_index ``` @@ -224,7 +224,7 @@ entire length of the list. | rawbytes has enough left for length | ``len(rawbytes) > current_index + 4`` | ```python -total_length = int.from_bytes(rawbytes[current_index:current_index+4], 'big') +total_length = int.from_bytes(rawbytes[current_index:current_index+4], 'little') new_index = current_index + 4 + total_length item_index = current_index + 4 deserialized_list = [] diff --git a/eth2/utils/ssz/src/decode.rs b/eth2/utils/ssz/src/decode.rs index 426baeace..6053ee940 100644 --- a/eth2/utils/ssz/src/decode.rs +++ b/eth2/utils/ssz/src/decode.rs @@ -65,7 +65,7 @@ where } /// Given some number of bytes, interpret the first four -/// bytes as a 32-bit big-endian integer and return the +/// bytes as a 32-bit little-endian integer and return the /// result. pub fn decode_length( bytes: &[u8], @@ -82,7 +82,7 @@ pub fn decode_length( .take(index + length_bytes) .skip(index) { - let offset = (index + length_bytes - i - 1) * 8; + let offset = (length_bytes - (length_bytes - (i - index))) * 8; len |= (*byte as usize) << offset; } Ok(len) @@ -90,18 +90,18 @@ pub fn decode_length( #[cfg(test)] mod tests { - use super::super::encode::encode_length; + use super::super::encode::*; use super::*; #[test] fn test_ssz_decode_length() { - let decoded = decode_length(&vec![0, 0, 0, 1], 0, LENGTH_BYTES); + let decoded = decode_length(&vec![1, 0, 0, 0], 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 1); - let decoded = decode_length(&vec![0, 0, 1, 0], 0, LENGTH_BYTES); + let decoded = decode_length(&vec![0, 1, 0, 0], 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 256); - let decoded = decode_length(&vec![0, 0, 1, 255], 0, LENGTH_BYTES); + let decoded = decode_length(&vec![255, 1, 0, 0], 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 511); let decoded = decode_length(&vec![255, 255, 255, 255], 0, LENGTH_BYTES); @@ -132,21 +132,35 @@ mod tests { } } + #[test] + fn test_encode_decode_ssz_list() { + let test_vec: Vec = vec![256; 12]; + let mut stream = SszStream::new(); + stream.append_vec(&test_vec); + let ssz = stream.drain(); + + // u16 + let decoded: (Vec, usize) = decode_ssz_list(&ssz, 0).unwrap(); + + assert_eq!(decoded.0, test_vec); + assert_eq!(decoded.1, LENGTH_BYTES + (12 * 2)); + } + #[test] fn test_decode_ssz_list() { // u16 let v: Vec = vec![10, 10, 10, 10]; let decoded: (Vec, usize) = - decode_ssz_list(&vec![0, 0, 0, 8, 0, 10, 0, 10, 0, 10, 0, 10], 0).unwrap(); + decode_ssz_list(&vec![8, 0, 0, 0, 10, 0, 10, 0, 10, 0, 10, 0], 0).unwrap(); assert_eq!(decoded.0, v); - assert_eq!(decoded.1, 12); + assert_eq!(decoded.1, LENGTH_BYTES + (4 * 2)); // u32 let v: Vec = vec![10, 10, 10, 10]; let decoded: (Vec, usize) = decode_ssz_list( &vec![ - 0, 0, 0, 16, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, + 16, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 00, ], 0, ) @@ -158,36 +172,37 @@ mod tests { let v: Vec = vec![10, 10, 10, 10]; let decoded: (Vec, usize) = decode_ssz_list( &vec![ - 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, - 10, 0, 0, 0, 0, 0, 0, 0, 10, + 32, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, + 0, 10, 0, 0, 0, 0, 0, 0, 0, ], 0, ) .unwrap(); assert_eq!(decoded.0, v); - assert_eq!(decoded.1, 36); + assert_eq!(decoded.1, LENGTH_BYTES + (8 * 4)); // Check that it can accept index let v: Vec = vec![15, 15, 15, 15]; + let offset = 10; let decoded: (Vec, usize) = decode_ssz_list( &vec![ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 32, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, + 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, ], - 10, + offset, ) .unwrap(); assert_eq!(decoded.0, v); - assert_eq!(decoded.1, 46); + assert_eq!(decoded.1, offset + LENGTH_BYTES + (8 * 4)); // Check that length > bytes throws error let decoded: Result<(Vec, usize), DecodeError> = - decode_ssz_list(&vec![0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 15], 0); + decode_ssz_list(&vec![32, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0], 0); assert_eq!(decoded, Err(DecodeError::TooShort)); // Check that incorrect index throws error let decoded: Result<(Vec, usize), DecodeError> = - decode_ssz_list(&vec![0, 0, 0, 0, 0, 0, 0, 15], 16); + decode_ssz_list(&vec![15, 0, 0, 0, 0, 0, 0, 0], 16); assert_eq!(decoded, Err(DecodeError::TooShort)); } } diff --git a/eth2/utils/ssz/src/encode.rs b/eth2/utils/ssz/src/encode.rs index dfb969a8d..f310c8d1b 100644 --- a/eth2/utils/ssz/src/encode.rs +++ b/eth2/utils/ssz/src/encode.rs @@ -70,13 +70,13 @@ impl SszStream { /// Encode some length into a ssz size prefix. /// /// The ssz size prefix is 4 bytes, which is treated as a continuious -/// 32bit big-endian integer. +/// 32bit little-endian integer. pub fn encode_length(len: usize, length_bytes: usize) -> Vec { assert!(length_bytes > 0); // For sanity 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 - i - 1) * 8; + let offset = (length_bytes - (length_bytes - i)) * 8; *header_byte = ((len >> offset) & 0xff) as u8; } header @@ -95,15 +95,27 @@ mod tests { #[test] fn test_encode_length_4_bytes() { assert_eq!(encode_length(0, LENGTH_BYTES), vec![0; 4]); - assert_eq!(encode_length(1, LENGTH_BYTES), vec![0, 0, 0, 1]); - assert_eq!(encode_length(255, LENGTH_BYTES), vec![0, 0, 0, 255]); - assert_eq!(encode_length(256, LENGTH_BYTES), vec![0, 0, 1, 0]); + assert_eq!(encode_length(1, LENGTH_BYTES), vec![1, 0, 0, 0]); + assert_eq!(encode_length(255, LENGTH_BYTES), vec![255, 0, 0, 0]); + assert_eq!(encode_length(256, LENGTH_BYTES), vec![0, 1, 0, 0]); assert_eq!( encode_length(4294967295, LENGTH_BYTES), // 2^(3*8) - 1 vec![255, 255, 255, 255] ); } + #[test] + fn test_encode_lower_length() { + assert_eq!(encode_length(0, LENGTH_BYTES - 2), vec![0; 2]); + assert_eq!(encode_length(1, LENGTH_BYTES - 2), vec![1, 0]); + } + + #[test] + fn test_encode_higher_length() { + assert_eq!(encode_length(0, LENGTH_BYTES + 2), vec![0; 6]); + assert_eq!(encode_length(1, LENGTH_BYTES + 2), vec![1, 0, 0, 0, 0, 0]); + } + #[test] #[should_panic] fn test_encode_length_4_bytes_panic() { @@ -117,8 +129,42 @@ mod tests { stream.append_vec(&test_vec); let ssz = stream.drain(); - assert_eq!(ssz.len(), 4 + (12 * 2)); - assert_eq!(ssz[0..4], *vec![0, 0, 0, 24]); - assert_eq!(ssz[4..6], *vec![1, 0]); + assert_eq!(ssz.len(), LENGTH_BYTES + (12 * 2)); + assert_eq!(ssz[0..4], *vec![24, 0, 0, 0]); + assert_eq!(ssz[4..6], *vec![0, 1]); + } + + #[test] + fn test_encode_mixed_prefixed() { + let test_vec: Vec = vec![100, 200]; + let test_value: u8 = 5; + + let mut stream = SszStream::new(); + stream.append_vec(&test_vec); + stream.append(&test_value); + let ssz = stream.drain(); + + assert_eq!(ssz.len(), LENGTH_BYTES + (2 * 2) + 1); + assert_eq!(ssz[0..4], *vec![4, 0, 0, 0]); + assert_eq!(ssz[4..6], *vec![100, 0]); + assert_eq!(ssz[6..8], *vec![200, 0]); + assert_eq!(ssz[8], 5); + } + + #[test] + fn test_encode_mixed_postfixed() { + let test_value: u8 = 5; + let test_vec: Vec = vec![100, 200]; + + let mut stream = SszStream::new(); + stream.append(&test_value); + stream.append_vec(&test_vec); + let ssz = stream.drain(); + + assert_eq!(ssz.len(), 1 + LENGTH_BYTES + (2 * 2)); + assert_eq!(ssz[0], 5); + assert_eq!(ssz[1..5], *vec![4, 0, 0, 0]); + assert_eq!(ssz[5..7], *vec![100, 0]); + assert_eq!(ssz[7..9], *vec![200, 0]); } } diff --git a/eth2/utils/ssz/src/impl_decode.rs b/eth2/utils/ssz/src/impl_decode.rs index 134e438e1..13ad24c49 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 - i - 1) * 8; + let offset = (end_bytes - (end_bytes - (i - index))) * 8; result |= ($type::from(*byte)) << offset; } Ok((result, end_bytes)) @@ -108,12 +108,12 @@ mod tests { assert_eq!(result, 0); assert_eq!(index, 2); - let ssz = vec![0, 16]; + let ssz = vec![16, 0]; let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 16); assert_eq!(index, 2); - let ssz = vec![1, 0]; + let ssz = vec![0, 1]; let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 256); assert_eq!(index, 2); @@ -135,17 +135,17 @@ mod tests { assert_eq!(result, 0); assert_eq!(index, 4); - let ssz = vec![0, 0, 1, 0]; + let ssz = vec![0, 1, 0, 0]; let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); assert_eq!(index, 4); assert_eq!(result, 256); - let ssz = vec![255, 255, 255, 0, 0, 1, 0]; + let ssz = vec![255, 255, 255, 0, 1, 0, 0]; let (result, index): (u32, usize) = decode_ssz(&ssz, 3).unwrap(); assert_eq!(index, 7); assert_eq!(result, 256); - let ssz = vec![0, 200, 1, 0]; + let ssz = vec![0, 1, 200, 0]; let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); assert_eq!(index, 4); assert_eq!(result, 13107456); @@ -155,7 +155,7 @@ mod tests { assert_eq!(index, 4); assert_eq!(result, 4294967295); - let ssz = vec![0, 0, 1]; + let ssz = vec![1, 0, 0]; let result: Result<(u32, usize), DecodeError> = decode_ssz(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } @@ -172,7 +172,7 @@ mod tests { assert_eq!(index, 8); assert_eq!(result, 18446744073709551615); - let ssz = vec![0, 0, 8, 255, 0, 0, 0, 0, 0, 0, 0]; + let ssz = vec![0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 255]; let (result, index): (u64, usize) = decode_ssz(&ssz, 3).unwrap(); assert_eq!(index, 11); assert_eq!(result, 18374686479671623680); @@ -212,7 +212,7 @@ mod tests { let err: Result<(u16, usize), DecodeError> = decode_ssz(&vec![0, 0, 0, 0], 3); assert_eq!(err, Err(DecodeError::TooShort)); - let result: u16 = decode_ssz(&vec![0, 0, 0, 0, 1], 3).unwrap().0; + let result: u16 = decode_ssz(&vec![0, 0, 0, 1, 0], 3).unwrap().0; assert_eq!(result, 1); } } diff --git a/eth2/utils/ssz/src/impl_encode.rs b/eth2/utils/ssz/src/impl_encode.rs index 8714cf75f..c41799d92 100644 --- a/eth2/utils/ssz/src/impl_encode.rs +++ b/eth2/utils/ssz/src/impl_encode.rs @@ -27,9 +27,9 @@ macro_rules! impl_encodable_for_uint { // Match bit size with encoding match $bit_size { 8 => buf.put_u8(*self as u8), - 16 => buf.put_u16_be(*self as u16), - 32 => buf.put_u32_be(*self as u32), - 64 => buf.put_u64_be(*self as u64), + 16 => buf.put_u16_le(*self as u16), + 32 => buf.put_u32_le(*self as u32), + 64 => buf.put_u64_le(*self as u64), _ => {} } @@ -115,17 +115,17 @@ mod tests { let x: u16 = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 1]); + assert_eq!(ssz.drain(), vec![1, 0]); let x: u16 = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 100]); + assert_eq!(ssz.drain(), vec![100, 0]); let x: u16 = 1 << 8; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![1, 0]); + assert_eq!(ssz.drain(), vec![0, 1]); let x: u16 = 65535; let mut ssz = SszStream::new(); @@ -138,22 +138,22 @@ mod tests { let x: u32 = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 1]); + assert_eq!(ssz.drain(), vec![1, 0, 0, 0]); let x: u32 = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 100]); + assert_eq!(ssz.drain(), vec![100, 0, 0, 0]); let x: u32 = 1 << 16; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 1, 0, 0]); + assert_eq!(ssz.drain(), vec![0, 0, 1, 0]); let x: u32 = 1 << 24; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![1, 0, 0, 0]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 1]); let x: u32 = !0; let mut ssz = SszStream::new(); @@ -166,17 +166,17 @@ mod tests { let x: u64 = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 1]); + assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]); let x: u64 = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 100]); + assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]); let x: u64 = 1 << 32; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 1, 0, 0, 0, 0]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]); let x: u64 = !0; let mut ssz = SszStream::new(); @@ -189,21 +189,42 @@ mod tests { let x: usize = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 1]); + assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]); let x: usize = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 100]); + assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]); let x: usize = 1 << 32; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 0, 1, 0, 0, 0, 0]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]); let x: usize = !0; let mut ssz = SszStream::new(); ssz.append(&x); assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]); } + + #[test] + fn test_ssz_mixed() { + let mut stream = SszStream::new(); + + let h = Address::zero(); + let a: u8 = 100; + let b: u16 = 65535; + let c: u32 = 1 << 24; + + stream.append(&h); + stream.append(&a); + stream.append(&b); + stream.append(&c); + + let ssz = stream.drain(); + assert_eq!(ssz[0..20], *vec![0; 20]); + assert_eq!(ssz[20], 100); + assert_eq!(ssz[21..23], *vec![255, 255]); + assert_eq!(ssz[23..27], *vec![0, 0, 0, 1]); + } } From d7a9fac6b52e23c51d33399aadc8f193c9682a2d Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Fri, 15 Feb 2019 21:32:17 +1000 Subject: [PATCH 002/106] fixed tests in broader project --- eth2/utils/boolean-bitfield/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index a0fce1f0a..4dec380ad 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -363,12 +363,12 @@ mod tests { let mut stream = SszStream::new(); stream.append(&field); - assert_eq!(stream.drain(), vec![0, 0, 0, 2, 225, 192]); + assert_eq!(stream.drain(), vec![2, 0, 0, 0, 225, 192]); let field = BooleanBitfield::from_elem(18, true); let mut stream = SszStream::new(); stream.append(&field); - assert_eq!(stream.drain(), vec![0, 0, 0, 3, 255, 255, 192]); + assert_eq!(stream.drain(), vec![3, 0, 0, 0, 255, 255, 192]); } fn create_test_bitfield() -> BooleanBitfield { @@ -384,12 +384,12 @@ mod tests { #[test] fn test_ssz_decode() { - let encoded = vec![0, 0, 0, 2, 225, 192]; + let encoded = vec![2, 0, 0, 0, 225, 192]; let (field, _): (BooleanBitfield, usize) = ssz::decode_ssz(&encoded, 0).unwrap(); let expected = create_test_bitfield(); assert_eq!(field, expected); - let encoded = vec![0, 0, 0, 3, 255, 255, 3]; + let encoded = vec![3, 0, 0, 0, 255, 255, 3]; let (field, _): (BooleanBitfield, usize) = ssz::decode_ssz(&encoded, 0).unwrap(); let expected = BooleanBitfield::from_bytes(&[255, 255, 3]); assert_eq!(field, expected); From 0da268ad5f9485f002a7a1279ed39d1e503833cb Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Sat, 16 Feb 2019 06:52:10 +1000 Subject: [PATCH 003/106] cargo fmt fixes --- eth2/utils/ssz/src/decode.rs | 6 +++--- eth2/utils/ssz/src/encode.rs | 10 +++++----- eth2/utils/ssz/src/impl_encode.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eth2/utils/ssz/src/decode.rs b/eth2/utils/ssz/src/decode.rs index 6053ee940..7b01d6281 100644 --- a/eth2/utils/ssz/src/decode.rs +++ b/eth2/utils/ssz/src/decode.rs @@ -101,7 +101,7 @@ mod tests { let decoded = decode_length(&vec![0, 1, 0, 0], 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 256); - let decoded = decode_length(&vec![255, 1, 0, 0], 0, LENGTH_BYTES); + let decoded = decode_length(&vec![255, 1, 0, 0], 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 511); let decoded = decode_length(&vec![255, 255, 255, 255], 0, LENGTH_BYTES); @@ -172,8 +172,8 @@ mod tests { let v: Vec = vec![10, 10, 10, 10]; let decoded: (Vec, usize) = decode_ssz_list( &vec![ - 32, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, - 0, 10, 0, 0, 0, 0, 0, 0, 0, + 32, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, ], 0, ) diff --git a/eth2/utils/ssz/src/encode.rs b/eth2/utils/ssz/src/encode.rs index f310c8d1b..3de83c730 100644 --- a/eth2/utils/ssz/src/encode.rs +++ b/eth2/utils/ssz/src/encode.rs @@ -131,14 +131,14 @@ mod tests { assert_eq!(ssz.len(), LENGTH_BYTES + (12 * 2)); assert_eq!(ssz[0..4], *vec![24, 0, 0, 0]); - assert_eq!(ssz[4..6], *vec![0, 1]); + assert_eq!(ssz[4..6], *vec![0, 1]); } #[test] fn test_encode_mixed_prefixed() { let test_vec: Vec = vec![100, 200]; let test_value: u8 = 5; - + let mut stream = SszStream::new(); stream.append_vec(&test_vec); stream.append(&test_value); @@ -151,11 +151,11 @@ mod tests { assert_eq!(ssz[8], 5); } - #[test] + #[test] fn test_encode_mixed_postfixed() { let test_value: u8 = 5; - let test_vec: Vec = vec![100, 200]; - + let test_vec: Vec = vec![100, 200]; + let mut stream = SszStream::new(); stream.append(&test_value); stream.append_vec(&test_vec); diff --git a/eth2/utils/ssz/src/impl_encode.rs b/eth2/utils/ssz/src/impl_encode.rs index c41799d92..0bb91366d 100644 --- a/eth2/utils/ssz/src/impl_encode.rs +++ b/eth2/utils/ssz/src/impl_encode.rs @@ -221,7 +221,7 @@ mod tests { stream.append(&b); stream.append(&c); - let ssz = stream.drain(); + let ssz = stream.drain(); assert_eq!(ssz[0..20], *vec![0; 20]); assert_eq!(ssz[20], 100); assert_eq!(ssz[21..23], *vec![255, 255]); From 9cef6a581469fbe98a7f0da4f5ee55b4b6fbe6da Mon Sep 17 00:00:00 2001 From: Kirk Baird Date: Mon, 18 Mar 2019 18:11:46 +1100 Subject: [PATCH 004/106] 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 92d296c37..f22c629e0 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 ed22696cb..581405feb 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 02e90dc5c..7d9c24546 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 f894deca6..2af78ffc9 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 f5b2fd87c..ab86351a0 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 9c5ed0375..7f6fc39c6 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 c85760bbf..97db38161 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 a3914310a..8299e1cfe 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 47598bc66..6b7a743d7 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 4dec380ad..0a02a98f3 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 7b01d6281..efc8c38db 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 3de83c730..e1484c4c4 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 7af6a7ab2..6aebf9182 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 33332ecea..2cc8c977a 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 7c29667af..6efca8058 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 6ce5c0fa0..22b48d78b 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. From 1bdd737a111fe364093ab09ab31155eeef4fe2f3 Mon Sep 17 00:00:00 2001 From: Kirk Baird Date: Tue, 19 Mar 2019 11:34:31 +1100 Subject: [PATCH 005/106] Add ssz test vectors --- eth2/utils/ssz/Cargo.toml | 2 + eth2/utils/ssz/src/lib.rs | 190 + .../ssz/src/test_vectors/uint_bounds.yaml | 1924 +++++ .../ssz/src/test_vectors/uint_random.yaml | 5124 +++++++++++++ .../src/test_vectors/uint_wrong_length.yaml | 6640 +++++++++++++++++ 5 files changed, 13880 insertions(+) create mode 100644 eth2/utils/ssz/src/test_vectors/uint_bounds.yaml create mode 100644 eth2/utils/ssz/src/test_vectors/uint_random.yaml create mode 100644 eth2/utils/ssz/src/test_vectors/uint_wrong_length.yaml diff --git a/eth2/utils/ssz/Cargo.toml b/eth2/utils/ssz/Cargo.toml index f13db5def..fa042a8ac 100644 --- a/eth2/utils/ssz/Cargo.toml +++ b/eth2/utils/ssz/Cargo.toml @@ -8,3 +8,5 @@ edition = "2018" bytes = "0.4.9" ethereum-types = "0.5" hashing = { path = "../hashing" } +hex = "0.3" +yaml-rust = "0.4" diff --git a/eth2/utils/ssz/src/lib.rs b/eth2/utils/ssz/src/lib.rs index 6efca8058..cb3f63c48 100644 --- a/eth2/utils/ssz/src/lib.rs +++ b/eth2/utils/ssz/src/lib.rs @@ -38,3 +38,193 @@ where ssz_stream.append(val); ssz_stream.drain() } + +#[cfg(test)] +mod tests { + extern crate hex; + extern crate yaml_rust; + + use self::yaml_rust::yaml; + use super::*; + use std::{fs::File, io::prelude::*, path::PathBuf}; + + #[test] + pub fn test_vector_uint_bounds() { + let mut file = { + let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + file_path_buf.push("src/test_vectors/uint_bounds.yaml"); + + File::open(file_path_buf).unwrap() + }; + let mut yaml_str = String::new(); + file.read_to_string(&mut yaml_str).unwrap(); + let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); + let doc = &docs[0]; + + // Load test cases + let test_cases = doc["test_cases"].clone(); + + for test_case in test_cases { + // Only the valid cases are checked as parse::() will fail for all invalid cases + if test_case["valid"].as_bool().unwrap() { + // Convert test vector 'ssz' encoded yaml to Vec + let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x"); + let test_vector_bytes = hex::decode(ssz).unwrap(); + + // Convert test vector 'value' to ssz encoded bytes + let mut bytes: Vec; + match test_case["type"].as_str().unwrap() { + "uint8" => { + let value: u8 = test_case["value"].as_str().unwrap().parse::().unwrap(); + bytes = ssz_encode::(&value); // check encoding + + // Check decoding + let decoded = decode::(&test_vector_bytes).unwrap(); + assert_eq!(decoded, value); + } + "uint16" => { + let value: u16 = + test_case["value"].as_str().unwrap().parse::().unwrap(); + bytes = ssz_encode::(&value); + + // Check decoding + let decoded = decode::(&test_vector_bytes).unwrap(); + assert_eq!(decoded, value); + } + "uint32" => { + let value: u32 = + test_case["value"].as_str().unwrap().parse::().unwrap(); + bytes = ssz_encode::(&value); + + // Check decoding + let decoded = decode::(&test_vector_bytes).unwrap(); + assert_eq!(decoded, value); + } + "uint64" => { + let value: u64 = + test_case["value"].as_str().unwrap().parse::().unwrap(); + bytes = ssz_encode::(&value); + + // Check decoding + let decoded = decode::(&test_vector_bytes).unwrap(); + assert_eq!(decoded, value); + } + _ => continue, + }; + assert_eq!(test_vector_bytes, bytes); + } + } + } + + #[test] + pub fn test_vector_uint_random() { + let mut file = { + let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + file_path_buf.push("src/test_vectors/uint_random.yaml"); + + File::open(file_path_buf).unwrap() + }; + let mut yaml_str = String::new(); + file.read_to_string(&mut yaml_str).unwrap(); + let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); + let doc = &docs[0]; + + // Load test cases + let test_cases = doc["test_cases"].clone(); + + for test_case in test_cases { + // Only the valid cases are checked as parse::() will fail for all invalid cases + if test_case["valid"].as_bool().unwrap() { + // Convert test vector 'ssz' encoded yaml to Vec + let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x"); + let test_vector_bytes = hex::decode(ssz).unwrap(); + + // Convert test vector 'value' to ssz encoded bytes + let mut bytes: Vec; + match test_case["type"].as_str().unwrap() { + "uint8" => { + let value: u8 = test_case["value"].as_str().unwrap().parse::().unwrap(); + bytes = ssz_encode::(&value); // check encoding + + // Check decoding + let decoded = decode::(&test_vector_bytes).unwrap(); + assert_eq!(decoded, value); + } + "uint16" => { + let value: u16 = + test_case["value"].as_str().unwrap().parse::().unwrap(); + bytes = ssz_encode::(&value); + + // Check decoding + let decoded = decode::(&test_vector_bytes).unwrap(); + assert_eq!(decoded, value); + } + "uint32" => { + let value: u32 = + test_case["value"].as_str().unwrap().parse::().unwrap(); + bytes = ssz_encode::(&value); + + // Check decoding + let decoded = decode::(&test_vector_bytes).unwrap(); + assert_eq!(decoded, value); + } + "uint64" => { + let value: u64 = + test_case["value"].as_str().unwrap().parse::().unwrap(); + bytes = ssz_encode::(&value); + + // Check decoding + let decoded = decode::(&test_vector_bytes).unwrap(); + assert_eq!(decoded, value); + } + _ => continue, + }; + assert_eq!(test_vector_bytes, bytes); + } + } + } + + #[test] + pub fn test_vector_uint_wrong_length() { + let mut file = { + let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + file_path_buf.push("src/test_vectors/uint_wrong_length.yaml"); + + File::open(file_path_buf).unwrap() + }; + let mut yaml_str = String::new(); + file.read_to_string(&mut yaml_str).unwrap(); + let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); + let doc = &docs[0]; + + // Load test cases + let test_cases = doc["test_cases"].clone(); + + for test_case in test_cases { + // Convert test vector 'ssz' encoded yaml to Vec + let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x"); + let test_vector_bytes = hex::decode(ssz).unwrap(); + + // Attempt to decode invalid ssz bytes + match test_case["type"].as_str().unwrap() { + "uint8" => { + let decoded = decode::(&test_vector_bytes); + assert!(decoded.is_err()); + } + "uint16" => { + let decoded = decode::(&test_vector_bytes); + assert!(decoded.is_err()); + } + "uint32" => { + let decoded = decode::(&test_vector_bytes); + assert!(decoded.is_err()); + } + "uint64" => { + let decoded = decode::(&test_vector_bytes); + assert!(decoded.is_err()); + } + _ => continue, + }; + } + } +} diff --git a/eth2/utils/ssz/src/test_vectors/uint_bounds.yaml b/eth2/utils/ssz/src/test_vectors/uint_bounds.yaml new file mode 100644 index 000000000..4d01e2658 --- /dev/null +++ b/eth2/utils/ssz/src/test_vectors/uint_bounds.yaml @@ -0,0 +1,1924 @@ +title: UInt Bounds +summary: Integers right at or beyond the bounds of the allowed value range +fork: phase0-0.2.0 +test_cases: +- type: uint8 + valid: true + value: '0' + ssz: '0x00' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint8 + valid: true + value: '255' + ssz: '0xff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint16 + valid: true + value: '0' + ssz: '0x0000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint16 + valid: true + value: '65535' + ssz: '0xffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint24 + valid: true + value: '0' + ssz: '0x000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint24 + valid: true + value: '16777215' + ssz: '0xffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint32 + valid: true + value: '0' + ssz: '0x00000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint32 + valid: true + value: '4294967295' + ssz: '0xffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint40 + valid: true + value: '0' + ssz: '0x0000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint40 + valid: true + value: '1099511627775' + ssz: '0xffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint48 + valid: true + value: '0' + ssz: '0x000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint48 + valid: true + value: '281474976710655' + ssz: '0xffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint56 + valid: true + value: '0' + ssz: '0x00000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint56 + valid: true + value: '72057594037927935' + ssz: '0xffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint64 + valid: true + value: '0' + ssz: '0x0000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint64 + valid: true + value: '18446744073709551615' + ssz: '0xffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint72 + valid: true + value: '0' + ssz: '0x000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint72 + valid: true + value: '4722366482869645213695' + ssz: '0xffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint80 + valid: true + value: '0' + ssz: '0x00000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint80 + valid: true + value: '1208925819614629174706175' + ssz: '0xffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint88 + valid: true + value: '0' + ssz: '0x0000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint88 + valid: true + value: '309485009821345068724781055' + ssz: '0xffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint96 + valid: true + value: '0' + ssz: '0x000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint96 + valid: true + value: '79228162514264337593543950335' + ssz: '0xffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint104 + valid: true + value: '0' + ssz: '0x00000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint104 + valid: true + value: '20282409603651670423947251286015' + ssz: '0xffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint112 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint112 + valid: true + value: '5192296858534827628530496329220095' + ssz: '0xffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint120 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint120 + valid: true + value: '1329227995784915872903807060280344575' + ssz: '0xffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint128 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint128 + valid: true + value: '340282366920938463463374607431768211455' + ssz: '0xffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint136 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint136 + valid: true + value: '87112285931760246646623899502532662132735' + ssz: '0xffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint144 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint144 + valid: true + value: '22300745198530623141535718272648361505980415' + ssz: '0xffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint152 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint152 + valid: true + value: '5708990770823839524233143877797980545530986495' + ssz: '0xffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint160 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint160 + valid: true + value: '1461501637330902918203684832716283019655932542975' + ssz: '0xffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint168 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint168 + valid: true + value: '374144419156711147060143317175368453031918731001855' + ssz: '0xffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint176 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint176 + valid: true + value: '95780971304118053647396689196894323976171195136475135' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint184 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint184 + valid: true + value: '24519928653854221733733552434404946937899825954937634815' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint192 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint192 + valid: true + value: '6277101735386680763835789423207666416102355444464034512895' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint200 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint200 + valid: true + value: '1606938044258990275541962092341162602522202993782792835301375' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint208 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint208 + valid: true + value: '411376139330301510538742295639337626245683966408394965837152255' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint216 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint216 + valid: true + value: '105312291668557186697918027683670432318895095400549111254310977535' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint224 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint224 + valid: true + value: '26959946667150639794667015087019630673637144422540572481103610249215' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint232 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint232 + valid: true + value: '6901746346790563787434755862277025452451108972170386555162524223799295' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint240 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint240 + valid: true + value: '1766847064778384329583297500742918515827483896875618958121606201292619775' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint248 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint248 + valid: true + value: '452312848583266388373324160190187140051835877600158453279131187530910662655' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint256 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint256 + valid: true + value: '115792089237316195423570985008687907853269984665640564039457584007913129639935' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint264 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint264 + valid: true + value: '29642774844752946028434172162224104410437116074403984394101141506025761187823615' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint272 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint272 + valid: true + value: '7588550360256754183279148073529370729071901715047420004889892225542594864082845695' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint280 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint280 + valid: true + value: '1942668892225729070919461906823518906642406839052139521251812409738904285205208498175' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint288 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint288 + valid: true + value: '497323236409786642155382248146820840100456150797347717440463976893159497012533375533055' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint296 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint296 + valid: true + value: '127314748520905380391777855525586135065716774604121015664758778084648831235208544136462335' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint304 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint304 + valid: true + value: '32592575621351777380295131014550050576823494298654980010178247189670100796213387298934358015' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint312 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint312 + valid: true + value: '8343699359066055009355553539724812947666814540455674882605631280555545803830627148527195652095' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint320 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint320 + valid: true + value: '2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936575' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint328 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint328 + valid: true + value: '546812681195752981093125556779405341338292357723303109106442651602488249799843980805878294255763455' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint336 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint336 + valid: true + value: '139984046386112763159840142535527767382602843577165595931249318810236991948760059086304843329475444735' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint344 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint344 + valid: true + value: '35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852415' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint352 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint352 + valid: true + value: '9173994463960286046443283581208347763186259956673124494950355357547691504353939232280074212440502746218495' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint360 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint360 + valid: true + value: '2348542582773833227889480596789337027375682548908319870707290971532209025114608443463698998384768703031934975' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint368 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint368 + valid: true + value: '601226901190101306339707032778070279008174732520529886901066488712245510429339761526706943586500787976175353855' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint376 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint376 + valid: true + value: '153914086704665934422965000391185991426092731525255651046673021110334850669910978950836977558144201721900890587135' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint384 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint384 + valid: true + value: '39402006196394479212279040100143613805079739270465446667948293404245721771497210611414266254884915640806627990306815' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint392 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint392 + valid: true + value: '10086913586276986678343434265636765134100413253239154346994763111486904773503285916522052161250538404046496765518544895' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint400 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint400 + valid: true + value: '2582249878086908589655919172003011874329705792829223512830659356540647622016841194629645353280137831435903171972747493375' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint408 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint408 + valid: true + value: '661055968790248598951915308032771039828404682964281219284648795274405791236311345825189210439715284847591212025023358304255' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint416 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint416 + valid: true + value: '169230328010303641331690318856389386196071598838855992136870091590247882556495704531248437872567112920983350278405979725889535' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint424 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint424 + valid: true + value: '43322963970637732180912721627235682866194329302747133987038743447103457934462900359999600095377180907771737671271930809827721215' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint432 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint432 + valid: true + value: '11090678776483259438313656736572334813745748301503266300681918322458485231222502492159897624416558312389564843845614287315896631295' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint440 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint440 + valid: true + value: '2839213766779714416208296124562517712318911565184836172974571090549372219192960637992933791850638927971728600024477257552869537611775' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint448 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint448 + valid: true + value: '726838724295606890549323807888004534353641360687318060281490199180639288113397923326191050713763565560762521606266177933534601628614655' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint456 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint456 + valid: true + value: '186070713419675363980626894819329160794532188335953423432061490990243657757029868371504908982723472783555205531204141550984858016925351935' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint464 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint464 + valid: true + value: '47634102635436893179040485073748265163400240214004076398607741693502376385799646303105256699577209032590132615988260237052123652332890095615' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint472 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint472 + valid: true + value: '12194330274671844653834364178879555881830461494785043558043581873536608354764709453594945715091765512343073949692994620685343654997219864477695' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint480 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint480 + valid: true + value: '3121748550315992231381597229793166305748598142664971150859156959625371738819765620120306103063491971159826931121406622895447975679288285306290175' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint488 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint488 + valid: true + value: '799167628880894011233688890827050574271641124522232614619944181664095165137859998750798362384253944616915694367080095461234681773897801038410285055' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint496 + valid: true + value: '0' + ssz: '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint496 + valid: true + value: '204586912993508866875824356051724947013540127877691549342705710506008362275292159680204380770369009821930417757972504438076078534117837065833032974335' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint504 + valid: true + value: '0' + ssz: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint504 + valid: true + value: '52374249726338269920211035149241586435466272736689036631732661889538140742474792878132321477214466514414186946040961136147476104734166288853256441430015' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint512 + valid: true + value: '0' + ssz: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + tags: + - atomic + - uint + - uint_lower_bound +- type: uint512 + valid: true + value: '13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095' + ssz: '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + tags: + - atomic + - uint + - uint_upper_bound +- type: uint8 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint8 + valid: false + value: '256' + tags: + - atomic + - uint + - uint_overflow +- type: uint16 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint16 + valid: false + value: '65536' + tags: + - atomic + - uint + - uint_overflow +- type: uint24 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint24 + valid: false + value: '16777216' + tags: + - atomic + - uint + - uint_overflow +- type: uint32 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint32 + valid: false + value: '4294967296' + tags: + - atomic + - uint + - uint_overflow +- type: uint40 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint40 + valid: false + value: '1099511627776' + tags: + - atomic + - uint + - uint_overflow +- type: uint48 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint48 + valid: false + value: '281474976710656' + tags: + - atomic + - uint + - uint_overflow +- type: uint56 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint56 + valid: false + value: '72057594037927936' + tags: + - atomic + - uint + - uint_overflow +- type: uint64 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint64 + valid: false + value: '18446744073709551616' + tags: + - atomic + - uint + - uint_overflow +- type: uint72 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint72 + valid: false + value: '4722366482869645213696' + tags: + - atomic + - uint + - uint_overflow +- type: uint80 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint80 + valid: false + value: '1208925819614629174706176' + tags: + - atomic + - uint + - uint_overflow +- type: uint88 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint88 + valid: false + value: '309485009821345068724781056' + tags: + - atomic + - uint + - uint_overflow +- type: uint96 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint96 + valid: false + value: '79228162514264337593543950336' + tags: + - atomic + - uint + - uint_overflow +- type: uint104 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint104 + valid: false + value: '20282409603651670423947251286016' + tags: + - atomic + - uint + - uint_overflow +- type: uint112 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint112 + valid: false + value: '5192296858534827628530496329220096' + tags: + - atomic + - uint + - uint_overflow +- type: uint120 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint120 + valid: false + value: '1329227995784915872903807060280344576' + tags: + - atomic + - uint + - uint_overflow +- type: uint128 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint128 + valid: false + value: '340282366920938463463374607431768211456' + tags: + - atomic + - uint + - uint_overflow +- type: uint136 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint136 + valid: false + value: '87112285931760246646623899502532662132736' + tags: + - atomic + - uint + - uint_overflow +- type: uint144 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint144 + valid: false + value: '22300745198530623141535718272648361505980416' + tags: + - atomic + - uint + - uint_overflow +- type: uint152 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint152 + valid: false + value: '5708990770823839524233143877797980545530986496' + tags: + - atomic + - uint + - uint_overflow +- type: uint160 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint160 + valid: false + value: '1461501637330902918203684832716283019655932542976' + tags: + - atomic + - uint + - uint_overflow +- type: uint168 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint168 + valid: false + value: '374144419156711147060143317175368453031918731001856' + tags: + - atomic + - uint + - uint_overflow +- type: uint176 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint176 + valid: false + value: '95780971304118053647396689196894323976171195136475136' + tags: + - atomic + - uint + - uint_overflow +- type: uint184 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint184 + valid: false + value: '24519928653854221733733552434404946937899825954937634816' + tags: + - atomic + - uint + - uint_overflow +- type: uint192 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint192 + valid: false + value: '6277101735386680763835789423207666416102355444464034512896' + tags: + - atomic + - uint + - uint_overflow +- type: uint200 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint200 + valid: false + value: '1606938044258990275541962092341162602522202993782792835301376' + tags: + - atomic + - uint + - uint_overflow +- type: uint208 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint208 + valid: false + value: '411376139330301510538742295639337626245683966408394965837152256' + tags: + - atomic + - uint + - uint_overflow +- type: uint216 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint216 + valid: false + value: '105312291668557186697918027683670432318895095400549111254310977536' + tags: + - atomic + - uint + - uint_overflow +- type: uint224 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint224 + valid: false + value: '26959946667150639794667015087019630673637144422540572481103610249216' + tags: + - atomic + - uint + - uint_overflow +- type: uint232 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint232 + valid: false + value: '6901746346790563787434755862277025452451108972170386555162524223799296' + tags: + - atomic + - uint + - uint_overflow +- type: uint240 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint240 + valid: false + value: '1766847064778384329583297500742918515827483896875618958121606201292619776' + tags: + - atomic + - uint + - uint_overflow +- type: uint248 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint248 + valid: false + value: '452312848583266388373324160190187140051835877600158453279131187530910662656' + tags: + - atomic + - uint + - uint_overflow +- type: uint256 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint256 + valid: false + value: '115792089237316195423570985008687907853269984665640564039457584007913129639936' + tags: + - atomic + - uint + - uint_overflow +- type: uint264 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint264 + valid: false + value: '29642774844752946028434172162224104410437116074403984394101141506025761187823616' + tags: + - atomic + - uint + - uint_overflow +- type: uint272 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint272 + valid: false + value: '7588550360256754183279148073529370729071901715047420004889892225542594864082845696' + tags: + - atomic + - uint + - uint_overflow +- type: uint280 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint280 + valid: false + value: '1942668892225729070919461906823518906642406839052139521251812409738904285205208498176' + tags: + - atomic + - uint + - uint_overflow +- type: uint288 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint288 + valid: false + value: '497323236409786642155382248146820840100456150797347717440463976893159497012533375533056' + tags: + - atomic + - uint + - uint_overflow +- type: uint296 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint296 + valid: false + value: '127314748520905380391777855525586135065716774604121015664758778084648831235208544136462336' + tags: + - atomic + - uint + - uint_overflow +- type: uint304 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint304 + valid: false + value: '32592575621351777380295131014550050576823494298654980010178247189670100796213387298934358016' + tags: + - atomic + - uint + - uint_overflow +- type: uint312 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint312 + valid: false + value: '8343699359066055009355553539724812947666814540455674882605631280555545803830627148527195652096' + tags: + - atomic + - uint + - uint_overflow +- type: uint320 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint320 + valid: false + value: '2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936576' + tags: + - atomic + - uint + - uint_overflow +- type: uint328 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint328 + valid: false + value: '546812681195752981093125556779405341338292357723303109106442651602488249799843980805878294255763456' + tags: + - atomic + - uint + - uint_overflow +- type: uint336 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint336 + valid: false + value: '139984046386112763159840142535527767382602843577165595931249318810236991948760059086304843329475444736' + tags: + - atomic + - uint + - uint_overflow +- type: uint344 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint344 + valid: false + value: '35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852416' + tags: + - atomic + - uint + - uint_overflow +- type: uint352 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint352 + valid: false + value: '9173994463960286046443283581208347763186259956673124494950355357547691504353939232280074212440502746218496' + tags: + - atomic + - uint + - uint_overflow +- type: uint360 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint360 + valid: false + value: '2348542582773833227889480596789337027375682548908319870707290971532209025114608443463698998384768703031934976' + tags: + - atomic + - uint + - uint_overflow +- type: uint368 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint368 + valid: false + value: '601226901190101306339707032778070279008174732520529886901066488712245510429339761526706943586500787976175353856' + tags: + - atomic + - uint + - uint_overflow +- type: uint376 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint376 + valid: false + value: '153914086704665934422965000391185991426092731525255651046673021110334850669910978950836977558144201721900890587136' + tags: + - atomic + - uint + - uint_overflow +- type: uint384 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint384 + valid: false + value: '39402006196394479212279040100143613805079739270465446667948293404245721771497210611414266254884915640806627990306816' + tags: + - atomic + - uint + - uint_overflow +- type: uint392 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint392 + valid: false + value: '10086913586276986678343434265636765134100413253239154346994763111486904773503285916522052161250538404046496765518544896' + tags: + - atomic + - uint + - uint_overflow +- type: uint400 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint400 + valid: false + value: '2582249878086908589655919172003011874329705792829223512830659356540647622016841194629645353280137831435903171972747493376' + tags: + - atomic + - uint + - uint_overflow +- type: uint408 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint408 + valid: false + value: '661055968790248598951915308032771039828404682964281219284648795274405791236311345825189210439715284847591212025023358304256' + tags: + - atomic + - uint + - uint_overflow +- type: uint416 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint416 + valid: false + value: '169230328010303641331690318856389386196071598838855992136870091590247882556495704531248437872567112920983350278405979725889536' + tags: + - atomic + - uint + - uint_overflow +- type: uint424 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint424 + valid: false + value: '43322963970637732180912721627235682866194329302747133987038743447103457934462900359999600095377180907771737671271930809827721216' + tags: + - atomic + - uint + - uint_overflow +- type: uint432 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint432 + valid: false + value: '11090678776483259438313656736572334813745748301503266300681918322458485231222502492159897624416558312389564843845614287315896631296' + tags: + - atomic + - uint + - uint_overflow +- type: uint440 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint440 + valid: false + value: '2839213766779714416208296124562517712318911565184836172974571090549372219192960637992933791850638927971728600024477257552869537611776' + tags: + - atomic + - uint + - uint_overflow +- type: uint448 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint448 + valid: false + value: '726838724295606890549323807888004534353641360687318060281490199180639288113397923326191050713763565560762521606266177933534601628614656' + tags: + - atomic + - uint + - uint_overflow +- type: uint456 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint456 + valid: false + value: '186070713419675363980626894819329160794532188335953423432061490990243657757029868371504908982723472783555205531204141550984858016925351936' + tags: + - atomic + - uint + - uint_overflow +- type: uint464 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint464 + valid: false + value: '47634102635436893179040485073748265163400240214004076398607741693502376385799646303105256699577209032590132615988260237052123652332890095616' + tags: + - atomic + - uint + - uint_overflow +- type: uint472 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint472 + valid: false + value: '12194330274671844653834364178879555881830461494785043558043581873536608354764709453594945715091765512343073949692994620685343654997219864477696' + tags: + - atomic + - uint + - uint_overflow +- type: uint480 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint480 + valid: false + value: '3121748550315992231381597229793166305748598142664971150859156959625371738819765620120306103063491971159826931121406622895447975679288285306290176' + tags: + - atomic + - uint + - uint_overflow +- type: uint488 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint488 + valid: false + value: '799167628880894011233688890827050574271641124522232614619944181664095165137859998750798362384253944616915694367080095461234681773897801038410285056' + tags: + - atomic + - uint + - uint_overflow +- type: uint496 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint496 + valid: false + value: '204586912993508866875824356051724947013540127877691549342705710506008362275292159680204380770369009821930417757972504438076078534117837065833032974336' + tags: + - atomic + - uint + - uint_overflow +- type: uint504 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint504 + valid: false + value: '52374249726338269920211035149241586435466272736689036631732661889538140742474792878132321477214466514414186946040961136147476104734166288853256441430016' + tags: + - atomic + - uint + - uint_overflow +- type: uint512 + valid: false + value: '-1' + tags: + - atomic + - uint + - uint_underflow +- type: uint512 + valid: false + value: '13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096' + tags: + - atomic + - uint + - uint_overflow diff --git a/eth2/utils/ssz/src/test_vectors/uint_random.yaml b/eth2/utils/ssz/src/test_vectors/uint_random.yaml new file mode 100644 index 000000000..b473eed7e --- /dev/null +++ b/eth2/utils/ssz/src/test_vectors/uint_random.yaml @@ -0,0 +1,5124 @@ +title: UInt Random +summary: Random integers chosen uniformly over the allowed value range +fork: phase0-0.2.0 +test_cases: +- type: uint8 + valid: true + value: '197' + ssz: '0xc5' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '215' + ssz: '0xd7' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '20' + ssz: '0x14' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '132' + ssz: '0x84' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '248' + ssz: '0xf8' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '207' + ssz: '0xcf' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '155' + ssz: '0x9b' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '244' + ssz: '0xf4' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '183' + ssz: '0xb7' + tags: + - atomic + - uint + - random +- type: uint8 + valid: true + value: '111' + ssz: '0x6f' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '18254' + ssz: '0x4e47' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '36941' + ssz: '0x4d90' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '18316' + ssz: '0x8c47' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '12429' + ssz: '0x8d30' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '32834' + ssz: '0x4280' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '19262' + ssz: '0x3e4b' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '40651' + ssz: '0xcb9e' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '12945' + ssz: '0x9132' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '9665' + ssz: '0xc125' + tags: + - atomic + - uint + - random +- type: uint16 + valid: true + value: '43279' + ssz: '0x0fa9' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '15842480' + ssz: '0xb0bcf1' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '3378971' + ssz: '0x1b8f33' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '11871267' + ssz: '0x2324b5' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '14568389' + ssz: '0xc54bde' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '10609800' + ssz: '0x88e4a1' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '6861134' + ssz: '0x4eb168' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '16005792' + ssz: '0xa03af4' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '14854324' + ssz: '0xb4a8e2' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '8740671' + ssz: '0x3f5f85' + tags: + - atomic + - uint + - random +- type: uint24 + valid: true + value: '2089756' + ssz: '0x1ce31f' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '60308648' + ssz: '0xa83c9803' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '3726325546' + ssz: '0x2a371bde' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '3738645480' + ssz: '0xe833d7de' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '2437440079' + ssz: '0x4f624891' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '4155553746' + ssz: '0xd2b7b0f7' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '1924014660' + ssz: '0x4422ae72' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '4006490763' + ssz: '0x8b32ceee' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '468399889' + ssz: '0x1137eb1b' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '2367674807' + ssz: '0xb7d91f8d' + tags: + - atomic + - uint + - random +- type: uint32 + valid: true + value: '3034658173' + ssz: '0x7d35e1b4' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '732495681130' + ssz: '0x6a16258caa' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '448997099201' + ssz: '0xc106508a68' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '633883988599' + ssz: '0x77126e9693' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '199479708933' + ssz: '0x05cdea712e' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '697437839781' + ssz: '0xa5e18862a2' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '530753379698' + ssz: '0x72dd5d937b' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '404973881548' + ssz: '0xcc08534a5e' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '69521473973' + ssz: '0xb581cd2f10' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '574050980983' + ssz: '0x77d41aa885' + tags: + - atomic + - uint + - random +- type: uint40 + valid: true + value: '152370540412' + ssz: '0x7ceffd7923' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '73309755692216' + ssz: '0xb854f2c1ac42' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '84189419668971' + ssz: '0xeb0574e0914c' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '21753680278216' + ssz: '0xc8b262ecc813' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '45178084358440' + ssz: '0x2879abd71629' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '132576241444389' + ssz: '0x25e6c6cf9378' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '121147496065427' + ssz: '0x93e977d92e6e' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '236115611339380' + ssz: '0x74ca23f3bed6' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '154930550072434' + ssz: '0x72e46694e88c' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '277340858358401' + ssz: '0x811a58733dfc' + tags: + - atomic + - uint + - random +- type: uint48 + valid: true + value: '201179675449946' + ssz: '0x5a5a17cbf8b6' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '46740132276364656' + ssz: '0x70651615e70da6' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '16623652076214918' + ssz: '0x865adf9c1f0f3b' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '48317568742675975' + ssz: '0x075651a192a8ab' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '27436486644662530' + ssz: '0x020157d8567961' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '2335965036647725' + ssz: '0x2d95373e8c4c08' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '39060686294409394' + ssz: '0xb2e042bb7cc58a' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '53619523721370132' + ssz: '0x141a7038ac7ebe' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '24569015937124920' + ssz: '0x38ca69cb634957' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '61411969267209949' + ssz: '0xdd162155dc2dda' + tags: + - atomic + - uint + - random +- type: uint56 + valid: true + value: '8962878696566339' + ssz: '0x43aedfd0b0d71f' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '14445986723726977549' + ssz: '0x0d6ac11963747ac8' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '12869751746724260959' + ssz: '0x5f6cf6da068b9ab2' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '492468956296214015' + ssz: '0xff75f112e899d506' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '10624456751094728287' + ssz: '0x5f8680d41fa77193' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '1688464693572029653' + ssz: '0xd54c2664b1a16e17' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '18087339706428085269' + ssz: '0x15d476d5a12303fb' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '11169580477999807763' + ssz: '0x13fd50094452029b' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '13246852848846262826' + ssz: '0x2a525a2f7b46d6b7' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '11448048936325307157' + ssz: '0x155bf56cdaa3df9e' + tags: + - atomic + - uint + - random +- type: uint64 + valid: true + value: '4794675689233954666' + ssz: '0x6ab7fdd5221c8a42' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '4120085711648797646463' + ssz: '0x7f5e124d98ddac59df' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '2457094427075785960776' + ssz: '0x48ad2a642efb083385' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '1596930364856374240246' + ssz: '0xf6a321ebef59dc9156' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '1930869412047970125437' + ssz: '0x7d469cb2122c32ac68' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '549110656645481873336' + ssz: '0xb8bf6ff7e7f070c41d' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '1506659991209273252530' + ssz: '0xb2dae4c9608f1bad51' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '3231167738247765671697' + ssz: '0x11bf6dd879d27529af' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '1111429009663473721195' + ssz: '0x6b9f8b87af0b2d403c' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '4185961329941969064453' + ssz: '0x0552c7986813e2ebe2' + tags: + - atomic + - uint + - random +- type: uint72 + valid: true + value: '113905314839449117867' + ssz: '0xab2465aa59f8c02c06' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '991100786258446953247093' + ssz: '0x7571bc780a6968aedfd1' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '753031464925852152864291' + ssz: '0x239e33825e02e2ea759f' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '939683731400428233982275' + ssz: '0x438120a6e74a6e5bfcc6' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '606725543462066682132072' + ssz: '0x68f670d60c8959a87a80' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '679126923996089191416816' + ssz: '0xf0c3b20bca85588bcf8f' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '851621275047832368203991' + ssz: '0xd74800f41b05597b56b4' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '808533679326786790044343' + ssz: '0xb7323b31af50d6b236ab' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '539405659904328750267652' + ssz: '0x04fdfa28515d4a3d3972' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '915520175015944101075823' + ssz: '0x6f9b2ca339ffb872dec1' + tags: + - atomic + - uint + - random +- type: uint80 + valid: true + value: '1001987930223867019288330' + ssz: '0x0a5f729107b3e1df2dd4' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '258869700201785255971724076' + ssz: '0x2c1babb305de4591ca21d6' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '275659642544661352293187823' + ssz: '0xefc0f90bc7ac692a3305e4' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '24084251387950612164675660' + ssz: '0x4c88040060a445e209ec13' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '193154701063539917246494799' + ssz: '0x4ff89c7e570f715319c69f' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '30859991048663997988858871' + ssz: '0xf7eb75d6e53f8677db8619' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '256957625909962351801772015' + ssz: '0xefa763f9dd6cfacfe48cd4' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '9116989420681003923005314' + ssz: '0x82df69213655a0fc988a07' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '2100038518022097336290642' + ssz: '0x524de06a2bfcf050b3bc01' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '117888974214719880278579137' + ssz: '0xc117b09c15650819f68361' + tags: + - atomic + - uint + - random +- type: uint88 + valid: true + value: '187186470036140670279874587' + ssz: '0x1bf8d132edc6a7df46d69a' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '77525960717344515985507152630' + ssz: '0xf6f2ac474a2844b0bff87ffa' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '6444848414695649181034209662' + ssz: '0x7ee18d65c9f4aca0bc0dd314' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '68243962408500728882382955796' + ssz: '0x14e5d6cae2b7a31d271582dc' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '27496372991539443643614608096' + ssz: '0xe0ba99a6f3d41aa57677d858' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '3221676592695309469625698690' + ssz: '0x8249c1041504d40a8ee8680a' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '44237499188219561716965821951' + ssz: '0xffcd55ae4db17942d466f08e' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '50717211258777902825126495010' + ssz: '0x220318e715076b753b4be0a3' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '42619109157011030380406953397' + ssz: '0xb5d5585f12c614df68b3b589' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '46516875161662588211695011193' + ssz: '0x79453535aef0256077db4d96' + tags: + - atomic + - uint + - random +- type: uint96 + valid: true + value: '11965288496913229204009981023' + ssz: '0x5f1447022cea71236574a926' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '14957454944671370317321635250309' + ssz: '0x85405a55172067564dbe24cabc' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '10936750860918651870040282600946' + ssz: '0xf295db9e4f5f2109c7468c0a8a' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '4618479523891140601380094965647' + ssz: '0x8f77698c0c263021bdb81c4b3a' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '12206751363239421091481079160489' + ssz: '0xa99ee685dd8289bae61124129a' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '12147936957240142789556575803353' + ssz: '0xd91736673f3ee7d5fcee195499' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '13664798469962208486423441295381' + ssz: '0x15c89de8821b2e7b695e5879ac' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '4712418733315898860010519235870' + ssz: '0x1e8df95717c0d31f186aa57a3b' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '1539128697874164453438201048396' + ssz: '0x4cad18b393876b7f4a6b316d13' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '6807259070938440085984182231646' + ssz: '0x5e62f7e4239ad92765ba70eb55' + tags: + - atomic + - uint + - random +- type: uint104 + valid: true + value: '3536656322122519847766685699159' + ssz: '0x57cc7cf97aedd2fdfc8a8da32c' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '2056532122597058116990906754828949' + ssz: '0x958ada10e32ecacea1e7ac156565' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '3996114906184243389819322413577166' + ssz: '0xce73f7bff54d973805eea70f06c5' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '868770318498488032272447445583337' + ssz: '0xe9c5e6ada1ed9d3735394c6cd52a' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '1729929268554041758696502326947101' + ssz: '0x1d6dcb425180d1953309f0c64a55' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '1194313726651249716381469936746563' + ssz: '0x4380646efe4e2331ebfdc75be23a' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '2094450107269228229217567740056712' + ssz: '0x88d49c738fcd9fc055b14aad4367' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '2663444668374853380684782301669273' + ssz: '0x99e7701eed1f417f9349e0655183' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '4760360601309573758337428313570544' + ssz: '0xf07c7725ee02c91a202aae32b4ea' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '4395156956879795456217704634614627' + ssz: '0x6383e96701cb6ba3c8db0faeb2d8' + tags: + - atomic + - uint + - random +- type: uint112 + valid: true + value: '100795555709089593156730443394356' + ssz: '0x34ed199c2f8e6aee99830138f804' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '855557341180839216834057590154814467' + ssz: '0x036425e650737951ce3470d13bc6a4' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '414467537111385463109004141787284313' + ssz: '0x5903c3417a1f439afb23bfc8d3d24f' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '782602525170513983755779101977421884' + ssz: '0x3c28a3d78c7a06618e173c9548b996' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '1250621125234440715142519718833256908' + ssz: '0xcc79d7b7ccdfd4b4702e9bce61dcf0' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '176400952363716085393125226801261643' + ssz: '0x4bec6fdeb6245feaf727170a3df921' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '798728503173792473043367850535783055' + ssz: '0x8f8a9f39811068214edc660a5bd499' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '1192554411710388236058091592161540610' + ssz: '0x02bae903d62f47c21c6a0dd878ade5' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '1224843992914725675209602722260650169' + ssz: '0xb90819263fd462de5c19f5a778e5eb' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '1016148444240496496752914943882694271' + ssz: '0x7f0ef6f720f30e5ff4a84781fcb3c3' + tags: + - atomic + - uint + - random +- type: uint120 + valid: true + value: '89372021651947878414619559095819678' + ssz: '0x9eddade68f79a18723299f80613611' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '337060767022057562817716766532192406084' + ssz: '0x448a9b847b3802c2b1eca299dc8a93fd' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '256783291218949627655514667026556198843' + ssz: '0xbb1f39bfd85d266dd83ee1e7b8a92ec1' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '203697878000813760667695904499069054426' + ssz: '0xda6d274af00a1189e206b1e6c6c83e99' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '199537652244744202127932003531962470534' + ssz: '0x8650e4f835407963da86809bcf8d1d96' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '61920815631763823374286214731610985269' + ssz: '0x3513a0e23dc60f00a27da1bdea83952e' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '113207116805824726959666891960218644120' + ssz: '0x986ec18188fefc915b402441cae52a55' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '12227650489491460353732842508880356285' + ssz: '0xbda382552605370ef7df1df1b6f53209' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '120042034974009028372474670245205798503' + ssz: '0x676ec0261c116fcf79c298fc45414f5a' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '131581408829052556530741761927364578030' + ssz: '0xee8a0109f3039d9cc30e5e7754a8fd62' + tags: + - atomic + - uint + - random +- type: uint128 + valid: true + value: '264790163841886451907268300974850726247' + ssz: '0x67590a0c6ea0fa19f6318c7805bb34c7' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '23009009063061163022450380671176753916627' + ssz: '0xd3aa2d0519a84f08a1342a995bf40d9e43' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '21659133330573268078148387705790285168039' + ssz: '0xa73ddfa1731615ef62587e56575885a63f' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '51594305779282661227020278594601848156745' + ssz: '0x493230f8d042baaeb298afb694d83d9f97' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '77377496959774602887967646747014843770993' + ssz: '0x71a86a301774c60945a138c876d75b64e3' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '62086379269917149809161197528013747517820' + ssz: '0x7cf91f5fc499b1c12323c3308cb29974b6' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '7811691319131517516713442356807602308429' + ssz: '0x4d8520ca82a1cba17a744913d505ddf416' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '44402141111700929609393251490894966995167' + ssz: '0xdfb8e4e6389a2def6f2c3c0af250757c82' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '39886530905979994183117025957314844872576' + ssz: '0x80cfba91de466192677e39e0c96c4a3775' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '20058109343621868312836589995732018947826' + ssz: '0xf2668c6b06bfd18174e6284e5d570bf23a' + tags: + - atomic + - uint + - random +- type: uint136 + valid: true + value: '73693595488587541989362153463090657359790' + ssz: '0xaef74b25c3620c6da9c34fe4e139e690d8' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '18537938434671927673504053721942482481178358' + ssz: '0xf6e641ecee1f8315f09f8defaadad11aced4' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '6964822520642714507357766228271899648701946' + ssz: '0xfab51b1035e465194205486a1efc18c6f34f' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '19924482427972148126040520741003541725428481' + ssz: '0x01bbf9bb06a45df4b102dc07e47195cab8e4' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '22150010364133189339955994960634393946467360' + ssz: '0x20ac5b6ec818b9af75cac16a8ee0b60745fe' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '5413576107222835186956044353627325981096127' + ssz: '0xbf78a9401b1a1b1467a33d5aaa1c0112253e' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '15515972633371723766275325375766903444211318' + ssz: '0x7606f85b232d18b1d748850721176f581db2' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '10280602132159287262346798691546599512562497' + ssz: '0x415b8b2d2b048d02f3938cd403446df90376' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '5494505658031558207419599196163684871928498' + ssz: '0xb27a7bac95006bbbb9f431f00ba4a1e6123f' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '21261220812273676537470962117242856729132089' + ssz: '0x39bc522435b0de2f9d7e3c74a0a8c51c11f4' + tags: + - atomic + - uint + - random +- type: uint144 + valid: true + value: '5805305046991641699899793191766891449670002' + ssz: '0x72d92d58d8701db5ce438cf55ea11a42a442' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '3825174099518686858057314999576904383076947018' + ssz: '0x4ad426076ece6df75e5c473580c0bb5cd886ab' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '3733499060455947131415925977452526654235574132' + ssz: '0x747fdfe0222e49f5b9cf9e8d385fcba2776aa7' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '1171261462346026422309786724078180692622416879' + ssz: '0xef9b1d2f701ed097bd1632fe46e6af146c8534' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '4299885285731473134889752519770808655649283906' + ssz: '0x429f81889d8bb294ff85c94eee070a2843d0c0' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '2702147309269105497705921292095138251485646870' + ssz: '0x16900a399242de50451322823ead2a3e212b79' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '4793101510903444695037543558116210027809105583' + ssz: '0xaf663ec150fb162f6ae0824a2caa595f1beed6' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '835923609654474138522615349897791780610555253' + ssz: '0x75bd42055927d0647ca3f213c361c1b3ee7b25' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '4758435986015644358755755548334659359082288307' + ssz: '0xb314cc21094e946baf9aa44cb1bbff8c2a60d5' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '4820543316492109470742949918242820586188979194' + ssz: '0xfa3baabd8d5028ed9cb06c247eca50971f29d8' + tags: + - atomic + - uint + - random +- type: uint152 + valid: true + value: '2832327379109300624533093590716906616384098814' + ssz: '0xfe914b4cdd3410a3c7b6c45a2c71a51586017f' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '298132119759970464683080205048551339723898620303' + ssz: '0x8f096abada20b9e6b77e175299ddf870e4b43834' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '1388818723368950524729130409846395238709059811556' + ssz: '0xe478164b8a9dccf31e168c78547a4f1711c944f3' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '630954366773311866370781714447899061244390686299' + ssz: '0x5b3e1666de1b752f8d1a84c447d0f46beaf8846e' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '931420146329679607955376257103221731696488435095' + ssz: '0x974d7f24785cf95acc296276c017aba1e85226a3' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '11365591825650676268094601246636917941215502073' + ssz: '0xf91ef1b2b174f7726c73659eca57467698a6fd01' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '919168166853120564410328465631358663091658059707' + ssz: '0xbb6f6e4c80114d1dfb36c5c428cd92fa14ed00a1' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '51811646046192928226923063007458662298811723569' + ssz: '0x316fa5e899142f32d5c86c98a98cd31587501309' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '496750394593545954208482528091910002500822893171' + ssz: '0x7302d0ca9d5532432d0f3c4ee28a9c88de0e0357' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '423385258122450374735040807575953166293599697284' + ssz: '0x84b9de29648a6e113353326a7ba266dc6740294a' + tags: + - atomic + - uint + - random +- type: uint160 + valid: true + value: '916565680350180742247901247333093042409086114078' + ssz: '0x1ed9138527626922b878f0925042e785003a8ca0' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '208685155101564224577462553158083992182641352118507' + ssz: '0xeb104667ef29cebdcd114fc7768a6fe7f1fec5c98e' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '103224122787274465835033055754836485431603577826124' + ssz: '0x4c2bd14ab1ce3e7167912e5fd4b6779174c0f9a046' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '300165292943880195108843318150884006362700836093147' + ssz: '0xdbbc3528d578901f55af70b20942da1edd3fa561cd' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '224586411240470228409514685871176383884323804143324' + ssz: '0xdcde4f97271acb77f370b823bece428f53fb12ab99' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '162833361893063202578352237831921852476808090585386' + ssz: '0x2a89a35abc0ed2a1619c0079565a0abe907a446a6f' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '368763521147822607595016382085290626340472866079418' + ssz: '0xba020a7afbce257da092d7b19bb4668032307851fc' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '107128340616938989509014223809605082531706505595584' + ssz: '0xc00aeda65c2e5bf55bb76a0fc6c9a87124efd84c49' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '161672980449300553331129731676348586984229386457086' + ssz: '0xfe0fc6beb99ada7eb0786a0dd36628e3dc2c039f6e' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '86288778115854259107907493184348540461239836611758' + ssz: '0xae1444ab61492665a1f7a40162bc7c5ce4a18a0a3b' + tags: + - atomic + - uint + - random +- type: uint168 + valid: true + value: '105559421341633923494711123458827890612233020808168' + ssz: '0xe89b1eb3f302e34afe3823babaf895e62129083a48' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '83140597773196103858588251276809779941296254527063362' + ssz: '0x42c569c0d751a692fb64b54985c4f230ae71ff1a37de' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '63347572874011887694417969607546203362409158998308151' + ssz: '0x3735fd75496f62b7c3b58754955a56622cc9122b50a9' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '28355229414081083465774610134863696059623243894828541' + ssz: '0xfd2df56b19a7e3a599f6aee55425feaf79df6d6fc94b' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '60547855894773048857039893325660012034511957248817321' + ssz: '0xa9b88172cb4be8ee6ebc75b56a9bc225e1782f86d4a1' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '66887733022528204775294989864333518229333007219868374' + ssz: '0xd6c21421663f7835f8790fe9f2b9d32fe421b271c6b2' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '94240266283512444958584476278055131942156426015803821' + ssz: '0xad0912ca929ec5fb1a528d630ce4626df2758dcee1fb' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '84147705009790231301060331685768170104811846087780503' + ssz: '0x97a8b8636b11d3badc5f5c38515babcb4bd03932e8e0' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '16594784769879697675422886666139924948892303707224771' + ssz: '0xc33a622cf917aa3beb115c9caabd2a4c1f3ecd9c5a2c' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '10333486373838094427217027595952712322826460203126059' + ssz: '0x2b0da1e0491f09e2c4dd625a15a15369e8c652759e1b' + tags: + - atomic + - uint + - random +- type: uint176 + valid: true + value: '82488517565067170439429897131942042173412572010143906' + ssz: '0xa26068f43818148cdebd04ee67ba02bca3a01fef78dc' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '23325929613275145022302073467642372979830015811842067893' + ssz: '0xb5cdb9940dd26074f5e17d7de2703741e0ff40b4b888f3' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '2577206205287141659870094756106145554158587044243553548' + ssz: '0x0cbd2537e05c5256ae301044a4ebcf0acdf3360b44e81a' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '349657915962513626344116028627044050882721725461628963' + ssz: '0x2308b129b4a38c5923ecfd00cdf7304a54ac95a78da603' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '10895013405319269419501563428819292743207913038957098622' + ssz: '0x7eb6f12366ff4d1048d163c908ab806d908235aecebf71' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '10836482078303888725446464507249725189954602256618632544' + ssz: '0x60357ef8c4b1cf9b34f9816598eac98e2c57e0eb5d2371' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '12322591428258660824406870149343649226386367531794732737' + ssz: '0xc1964686bbe382581cae1230b3b158d6f5789d3363a780' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '21489197691014261855472609522952688351555575272215722455' + ssz: '0xd7b984125f7c5b02f093ff750c04cc7ebbb37fb9915be0' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '24205189860902688400175019354724539766463318160658851289' + ssz: '0xd9e5260c1138caeac1cc1acf61b5806915c198fac6b6fc' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '11825686541981180358392336899912697834165360564728240093' + ssz: '0xdd17e47525f5aa70d0593d1ed2e9ea1522addb1447777b' + tags: + - atomic + - uint + - random +- type: uint184 + valid: true + value: '19344803720702268208265842079944300932591535148420015772' + ssz: '0x9ca64b6de15b1b8f88663cc15180f8e2e7854fd41bf8c9' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '1381279380569480472996584911991522106128827020580318540723' + ssz: '0xb3f3120a928a7bf5dfff2d2ec72fee3f9185717dc83a5538' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '1710800360345507530608903952563366286992335432164890617224' + ssz: '0x88a5cb9a10b54a766d1c42899e2c65a2a31bd042d496c545' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '620810176017102301644122502129107262137975866296329120839' + ssz: '0x472c3d04c11a651e9e3a689de90993c8c6833fb6878f5119' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '3234484202787321180763256591533362264040520567185285133310' + ssz: '0xfe3345ff86e8dca89e00a6013192eebda31b18893b97e983' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '1710414927849226139402721391980900407562101499176327951406' + ssz: '0x2eb4eddb14c0bd0c75e22d1f5f587b62cea02ba5a890c145' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '4234820064615624905197098800651094750515964588498002720149' + ssz: '0x9535cde60b8f793d97e49510c3b1a5846887b94e9f95b5ac' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '3653652360078988377986388157889634958581818092896230664940' + ssz: '0xec6acd3b4dd5895ff124e6a002f4f27a7bc26d4917e90195' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '2058165680973303953206524023772926238779694820250119130497' + ssz: '0x814d252315b34bcf05baf7033c74998d9ad43d819940f053' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '5504017444858969306807185960608372450767459090170021596526' + ssz: '0x6ecdde95364583a2472b790603f3decf1c123c21979f78e0' + tags: + - atomic + - uint + - random +- type: uint192 + valid: true + value: '479923403305856306058759303564570452545807455244817138561' + ssz: '0x8103be27e82ecbf9bc76402d2f75ae823029c1fd55a29213' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '425164173630217684551615645081991927006977690943201695416534' + ssz: '0xd6c06ac4f34f19b2707e24f8f92da53611a93d3c461789bb43' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '1465635457103795858794674849552051561422465264844226680368909' + ssz: '0x0daf7cd52fe2a806067bc48630b09b988b22ce5b9b273c7de9' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '525096906449109809970891601960585512858850731335422818314776' + ssz: '0x18ea064f69143c03c6c968f531be56382fb8368eef801ba753' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '1548795583015129292733586184645532701928115700397613702277893' + ssz: '0x056b2da9ad4a0be1f596a47e98212acf372a0df46d61c4bcf6' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '441023884481641192600575611544719376726303841305791782489039' + ssz: '0xcf8bc88b9b9c5e50610748b4422a08d9956c2a14c032584246' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '1010853716254998192470227443819336589901876310467059473363474' + ssz: '0x12b2ae4ae3df5362da439bf1d270260f37f76a35df3bcd09a1' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '1417764795294999049262609545857762820325438799272884643122886' + ssz: '0xc64ef9b9041e40bf1e6831f6905fe63f8dafd9571320ebdce1' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '1106402620958017563189322241320488113294182177738518553323412' + ssz: '0x94671eab0ce6cdb972a7e6a8f0a067a852b5d53973589642b0' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '1575690551520719153265351098016322227672993470929277521564749' + ssz: '0x4d14e50e2deb78bb585f64a1061bb6266ab4795a21f4a005fb' + tags: + - atomic + - uint + - random +- type: uint200 + valid: true + value: '721944794472535788936011009064996792975025604975751746647746' + ssz: '0xc276b9a01edeb20ff5de490666c8d03d1cb6820b4d592f0373' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '283788161184204248182878451972717653883776761810554986240576474' + ssz: '0xda8b0ef2897964a7a681a05378190911623a2ad218d3f90f9ab0' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '178149934634732678720142222342160460720663581271507967466478157' + ssz: '0x4d1adbf8a64efaa9fffa326c041dc722ec3876e4f11c07ecdc6e' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '314843156758203159288032619652138702470431414064765132744759744' + ssz: '0xc0192d54ee6a62ba92a69efcfd5308c9a3a44fbf59059c68edc3' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '34509993099631611835293559721950077716317052391595715465491278' + ssz: '0x4eb352bc906a0afb8a12c8af8d9976b435387076387653c27915' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '140948492312106658580155794881036776529232112604622005191445353' + ssz: '0x690b929091efe7eb976a621fb8e2af688e4936f47fa0ea63b657' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '195301538056856531014786538472907670770460393091516818019689797' + ssz: '0x45a50dd78dd980bb021719b3ab54ee25f8c5631418397e548979' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '18083990873295815222255963237198734377161511626624015755587681' + ssz: '0x613013d7f78f08d453ad16d21a48202da8e82d3fc64f2af2400b' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '124077408888453943953963699828704442309312709665786018503852592' + ssz: '0x30024c094576107fad4af116f4d1bd5bfea6f04abdf4f0ab364d' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '323006752223052111410620093630126696963214425103554275092146664' + ssz: '0xe8299b67ecf36f56d637144526a3a6cd1b3c087e448fc5f101c9' + tags: + - atomic + - uint + - random +- type: uint208 + valid: true + value: '385800404979545497299365972172020453206788670887888060284461316' + ssz: '0x04e1c803013e8e4fb87ec487e8e589e6a54ac9499b30ea8c15f0' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '55277705514401252414282420959051933790201578867045715128653849284' + ssz: '0xc42232fa0b10f1087b96ddc567982388e93d0c926d20568d665f86' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '25278232180119948717946455021965622507435762748550013669290836806' + ssz: '0x468320ef7bfcd4afa815ce091c06b77446ff226581ddacb8ae723d' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '43619923706358074353058852510590901840184970849846219143622330701' + ssz: '0x4d89a2c66302dbed41dd2e4a246bb4fe54f5a4afd4c317c3be086a' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '69388733346001031413883370721266766925401178816895921762591326011' + ssz: '0x3b3fccf8fd882940640a7f35dcdfb11da1e1e7901d4552fbb6aca8' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '104229493646722114105408097596578013912698131892142250796223199470' + ssz: '0xee783658b138fa5cda778b4a76bb2ea0fdd91d4b9449b0522c5efd' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '213315815603614491605259937972907736494189135089334060132376440' + ssz: '0x789f64c84d265667eaabc7997462566eb8e6cafcdf71872bbf8400' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '71895890286116524197373427126548221259211153238166419878578268148' + ssz: '0xf4a7d0c9c2c3082458f38f91c675290b0aa11f7189903720ecc4ae' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '65588025353358308968494336853601597777797707720963555263879430904' + ssz: '0xf8c21d8be045e49ae79d7b62758e37c10668446f4cc00844876f9f' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '66963898818471239274826191602149519993490641805785201620344829817' + ssz: '0x79f7ca4706b33df225ca1842d4e0b1890edbfa8667a2f78dbcc7a2' + tags: + - atomic + - uint + - random +- type: uint216 + valid: true + value: '76023155346607127955535532687539340958454969079686872613133461762' + ssz: '0x02a93fa9db5a8eb3c8cf77ece63612c8bf7433905a4c576253cdb8' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '11322691247890750772785343433720188326066540124861398076924282597103' + ssz: '0xefeef83d05d74346d770652f9beae7f1da2e11c26fe32eed0ff0836b' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '5076003068668970296658189715938670726627499368404532942701260967131' + ssz: '0xdb0c1ce57e038cce529470cfce5d7ab47f3bb519ddc33ff576143330' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '20557682686888479857009315837853316385879769103168261658025237427811' + ssz: '0x6336e8537c7a331725ce984e8fe2b6072caa157e81e5ce0258f534c3' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '15709270253336590930371927630644925249864297345261298308078636023008' + ssz: '0xe0bc4eace9aaa663ea1675b20d4a51e14b8f92d24fb6d509e11e2b95' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '7504295153069115448819097176322648337476081377900621007107081499888' + ssz: '0xf0f4c55ae73371d4ed219c9132d9762032857d904d83e2b556ee4147' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '3648758727978778269121534333760226833880358322439075676236502986426' + ssz: '0xbaee6ed2d39b38065367e96578094679696fc1ebdaa78d8521a4a522' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '1870300476214775364826227249444100765260639306571992524520152629692' + ssz: '0xbc01dc142f17e090e4476ddd916cf15896e56b5c89772601d872c211' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '13789797499784360192730140591789737021141348067067272581281317306996' + ssz: '0x74c262246d617d9867dfc1250dde7967a317daddd26d5c4e0d24f182' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '14008607891539364363854600709859623729159364542079851236226236266270' + ssz: '0x1eb75db77ffd99c389293cb9d86ef50b88c2d4ba4dede1d2170a0585' + tags: + - atomic + - uint + - random +- type: uint224 + valid: true + value: '4119995425035813947864210422478242206619061080259737437162312141917' + ssz: '0x5d8cf5e88015bb278a46b5c1d20a71e66e31e672a57b7f8d72271f27' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '6302993395515168221845816201170478685143920727994649255486463874343378' + ssz: '0xd2a1ea5085595bd150cb5df23c3657123d0b6131c889fda5a73380cae9' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '4602319844841649035279470304312522378416834284140043508823278007580251' + ssz: '0x5b76639c8cd61c3dacc8f0cf0d6c6b75d303b3858ac3cd28cecea3b5aa' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '1099288187097276898660820007078812312221652881714273838840778879221788' + ssz: '0x1c401915c27612d2cf1086847befe7572e40a1008b481ed04e8e5dc628' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '1634758649409831258452410223755728597460224486673488004542273149265312' + ssz: '0xa0e5c860799b2c8308a1af5c2932bcfc424360d79cb088dc1625f6a23c' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '246012206746276459681518252952824815508591726617234399689920233341296' + ssz: '0x7001d822a9cd1f518dc3eeecb656d1057dd3be2eb343d7bb1c8c062009' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '853158106319162415882399907417783501020742036531269976606442466045022' + ssz: '0x5eec7f56d8ddcce2d5ac839b1deb7e310aba4c0bcd2cf169017938a51f' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '1076425980086328398511627015378358142745884577942760134042486501867260' + ssz: '0xfcfe60cbe9031bb6dd9f0c2bd0429e5ba43b1cebc42dcfd5f49b46ed27' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '5700778800698434104601360353002809053352488223990034553114845943559416' + ssz: '0xf8f47d41e8021dacd54e4b4ff7720f90e1175ed91294c3cd3e9d2174d3' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '5363662116775053836611133807417585997218890869025950508733033688868148' + ssz: '0x3425402ee034db07569627740c5e6acd864b9f43612dc430cc5904f3c6' + tags: + - atomic + - uint + - random +- type: uint232 + valid: true + value: '2426970447728329518602430352580496555036146161668756408998123123794387' + ssz: '0xd361681049498c5b9475a718c8e3941f6f2bb4062a01cd59835976055a' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '1613049271801253962588016060890794346945585061329522177296209138104993877' + ssz: '0x55085d671015b39daf52c9b05e7947a7aebda1e525577e03333ca352b7e9' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '284278524951509607139599097561020878188408518051207212543439289862518734' + ssz: '0xcef76eca0f65d68d479cfabe5d4e25dfd786e1b177e8fb7e1b0afe793029' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '116870510029841554229455805612971786783316051525887540746355013704544311' + ssz: '0x37f080144ca8675589e8c95b8d8784f4615f36190487ac78b670d8f7ee10' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '130053699757167973056104805468309518282725038708228984820162614857194520' + ssz: '0x185c7e27dae2b7e806b63f84eedf22a04da303ceaa287e491f75b7f5d712' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '519051656733957209185197660636401147033409105171004180231442425407577284' + ssz: '0xc49c2f0002856e60c7eb725670032828da1dc5f12f195c8c74892bb2344b' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '857209832652585106857646102249590523540127109077609264100370048423188655' + ssz: '0xaf581a296885b32c1fe181c7411abeebbc99b2281fe8dea3fbcc09ae337c' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '1706457427187624006528264292822192095256082643152135663515387263171331087' + ssz: '0x0f8472f1a558ffe0afd423ef6060ed9fe78809546fcc12f2d1e81a0640f7' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '849109624703413573761136533648225222034100968742834369829476169807133952' + ssz: '0x007d65f504784de34be736a0457eaeadd129ea656da14e0bd406f739077b' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '798751832024326864425928423093545919725985458621787481096477038033461891' + ssz: '0x8362bba22c641548811a1d549436862b6f7e5af7fed1f93cb20e225abb73' + tags: + - atomic + - uint + - random +- type: uint240 + valid: true + value: '487639798004322277613230212642596105802412093780566513839874380887430829' + ssz: '0xad16e329d322dbe04e20b66b1b8980761657005d501463e066cbbc90a746' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '5099489647304605696126349609305974961708701007683686387353437839390036625' + ssz: '0x9152f262787f9e902b7d50c5339e72030c108229b73b28ee202f6a95dee202' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '17649009580055176422669550057659989046600703500965554727940443763516329483' + ssz: '0x0b4edbafcdfcd063b475edb7d7bc34cd70b8052cec3cf8ff19ec1c262efd09' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '426199882223198595784251717646499098659538250947738478072106027803515843619' + ssz: '0x2374c05905194ff7a2f1b718927a796edee04ce51903a06f689ee23e7838f1' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '359189970573997074902092557607433640165941496064453371629708186263557438009' + ssz: '0x39faba6179cb9b39701595ea71141465ee39743da21130a5c5cf2e7b584bcb' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '429290773623992034469666348980875106571394782174536551126643345589487425085' + ssz: '0x3d56ce8648102e5f51ccd68ad5e88f05d6eca19a7f1e929c208593c74ff8f2' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '44071259082207109492646259745674705684281377345460348117013318839845904178' + ssz: '0x32df0964c480d0f6b23b48a028144e1b1a28d388fff9ace0248b41da85f118' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '160026297177693655446406343130987334279420779393054189127212788336074336200' + ssz: '0xc8a7ca845bd5e0c0edbbcc0dbfef1832eb288ce0241514f57d31f44159925a' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '263345946400208064390327089917856520960587585124961183807472163960806207887' + ssz: '0x8f7134b929216c95aca61d53ce72c94bdc1d4f612d8c69a29c499d0a6c0c95' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '149948968350894246575004866141077320508770472064872338669574783547940204989' + ssz: '0xbdf14a35b4f9cc58897c58227efbd421358d3c1cec00f69c2bf9615b3cde54' + tags: + - atomic + - uint + - random +- type: uint248 + valid: true + value: '276130070408210503339928255499048768702383103126254742237401470668835600958' + ssz: '0x3e3a03251dcc83e9a2a44a6019150bfc3a7b63bd2b4e68beabdc338eb9489c' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '109853385383692125130666181346655966905089281798363364577698721873057727288542' + ssz: '0xde940a3c050268e17ae631eae5511cfe79bde96052f0b5585169e8630fd0def2' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '80831061953558606121992596128000436342083741576797050886075787772192693906376' + ssz: '0xc86b7fef4e34a9e140f861846c28581bf78964b2620b7fc7e81eb9a581c2b4b2' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '52410806078160188458272819439265780457914882846202556927297697991223286362608' + ssz: '0xf0f1b65c9cc33ed1265cf3b8c1780f7b7ea07f51f101af1bfcab0cad0a77df73' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '4528169361101625426609703673506975461869016157183845523294323294399026776337' + ssz: '0x114995961a6bba6729a1a3556026ac3b3653bd81793798df01469d7460da020a' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '74684456646805550896660539760345239771784850672086988748411907468011016586021' + ssz: '0x2583b89e18f20f1a00fdc844adfa49d5e588eb81cffc827db2b7008d8be71da5' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '7930821798834217597582520218130251175929961482155689399092862005846980045213' + ssz: '0x9d29de9b4b00e4d4d8c4b3eaca82c5247bc5f874c4c19f11d5ff60f6a1af8811' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '55845590622716724553703978457616024170428171858378863327115341734776712963062' + ssz: '0xf6a3ab64f441ed901386faf3519bf468fa375f8e1d229d17bd8cf943f27b777b' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '22985072167011274730947499983037735489455584301976188610497015534447597134713' + ssz: '0x792333dda772840e7800b0d23a3561aad3e60523058824963c96088ffe16d132' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '90320659887124956444946788396794059667012474298880656657355653544672084590356' + ssz: '0x147fbfb01845671bebaf65ee610a1479f4643e8fbf60e758aeb2ecdf8faeafc7' + tags: + - atomic + - uint + - random +- type: uint256 + valid: true + value: '41588810815912157824843698140391804743576990512566498679819794402386930701841' + ssz: '0x11160633ed240dbecbe7b7c677a62a7bbd14f6a8abc666e13ced14c8c86ef25b' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '21296001826893306768839983183528384358777935475417962327843917760059950361469166' + ssz: '0xeee05fde12679178aba4883a1e88fba706b794b5c26dba5f0234d5a14de375eab7' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '9083424733960371098764188185142073667453444177630658935049986165458427256084845' + ssz: '0x6d99794879e7d3dd1a32f41acc6bcf7a024152e7a486964a3b72e11e3d352c724e' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '29566131553721056040540973645679176958566665718653088224409538237982402742937378' + ssz: '0x226711586853d1eed51d583e5e564abe0d5cdb2f91a2fdedaa45b4f43e6f8d56ff' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '27386396295611794818626010724225871402912704510020494598477724677995811734020449' + ssz: '0x61e18b3a3550271c3deb5cae0db44762c5f8adf9b5f382639f57fe76a8ff7683ec' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '79192727774743132497929211392962814204097474321636093950599090898303326863519' + ssz: '0x9fc037661da29180d82aab4ffaee967cc75f8f3b0fa48450e8489684d97e15af00' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '15526963993513027896715097745190436309615414534779187135724018786412527388264556' + ssz: '0x6c086d6e1c8cf2fb13fe720c2a474c93a94278c522035a0afe911068e62fee1786' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '21618226575683556926946360788707342858418244067939209080935742917769590393468870' + ssz: '0xc6f746330ec7b5b95deca95321deb62deda8f41c786e4a2e4a0116ccf6a1dab2ba' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '7642799733387596618831190290643929361737669173201938963100440909489090827400890' + ssz: '0xba363c07a2f8d53b2353f0f380852f0b5b58120277c8f6611b09da88635a270142' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '24645895616429953322226564354962746510172899132668958313629564893959254613013498' + ssz: '0xfab351773ad49c32863207d930fd6100e52e2d857f8483e5fbd2139f00959ad8d4' + tags: + - atomic + - uint + - random +- type: uint264 + valid: true + value: '22627560330459972751367815278597636440488178815234860278957928427828952266467576' + ssz: '0xf8681811d75c7489e9bc582d18040ded5e25fb3b7d60193a0678a6ed074b596ac3' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '625250111043137170689751858927250902545171477105610440876043903987621787475440447' + ssz: '0x3ff384792092b0cefe3c1800cf79916f9f59c935154099617572dff9b7d9edc31715' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '3820339058978905481755063485076180968185706583661525507183008492682872693957785241' + ssz: '0x99f65a56b29b5badf19733741f0008a407a166224a0e8d98e7215c84b7a69017e180' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '4849680707369048052211824914630045442619688192743438820460357801220369762493208785' + ssz: '0xd118a9c5137daaa8e89fca22bd2d00616ec5033501a7bb92deb2d2f9618bf7a89aa3' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '5093289363124942642069730573322416122158704929553182919117930150942991343979209473' + ssz: '0x0123fe562b65fe20843e8d6a759d22412b4d926096d81b14e1b8a290fa806481d2ab' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '6144571186318854496947375244157314153979375651725952147276695635525904368159259820' + ssz: '0xac7c61efd63b086979561f0617806e726da231b969c355e3d9a58901f2446e8d49cf' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '7242940294389022311959343674777289374026560764572510438623980076056939269565263104' + ssz: '0x002d65f50716a3c3b28177c6c93d3272a9fb563982fcf26df412b63d6fd1d24057f4' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '2847221820608387398617203755825774542746168121608423732730320846973684286967713289' + ssz: '0x090e8feee0b1f6ed804c1826d9cd07f85b6ae2d445b5ba85915a3baf981a6a160d60' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '2354060005572638077449234149036018236507870338365964979615165922663020432038720252' + ssz: '0xfc72c64c67fac9ee98dc8e845fe382a1406754acc1ee6c1fb0fb39f2446c1a0f6a4f' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '5932627088533055643439309711698449984347199537767722408629723169384113267855997012' + ssz: '0x5438f67705a0ea63510983ad19a50830060c56695762007f3c4c2a31c001e22a23c8' + tags: + - atomic + - uint + - random +- type: uint272 + valid: true + value: '6698873197610807542032168881416614265680118672478957820712945650802555946736300385' + ssz: '0x6131209e4f5e527ec64d1be692aec7a946c61b92cd41c6ed84e29f3613b51a99fce1' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '1313825061500410038993240043130374517534905517915647144891011803618969082282703281749' + ssz: '0x555eef6c7a07b3ec8f6c4ea5501f52a2f5a505fded035149a755aae2b5b7daaeee21ad' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '1820559996200452948457373345404221922955244215328143934805596340623460877962024999783' + ssz: '0x675b2a700ca20c64c2ac5b70373872fd4ea2c9a935744951ac3193d87dd4e9fda6e8ef' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '59405018442386835031158580233415031563454955255687830443447184515710201239397864591' + ssz: '0x8f148689f857e8102e640a140237d79a532954f806d200bb0502247e99e095c007d407' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '90275535968147058728031054784511326125689061347242890714737499032945117265560764074' + ssz: '0xaa7e36344d175a6bf197f49de9fbd7c1dab6295c35b7e44fe53a6e15e2c9b9be72e50b' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '1737340175541908426971661911337498503240358417677517478902063475777658726398133904936' + ssz: '0x28a655f50ff93c838a42155edfe0432750833b77440a2642c91d351ccfbff0973af1e4' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '170992041153025670379739257237344523995717798973681047923852658195840666954694794236' + ssz: '0xfc1b6aed725cfb569f4b723aca05fbd2f8641997b1c88d43d6c482ef4a35c7166c8816' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '453022425318917953329769644003931147605314653128258877161926858702850770550375976429' + ssz: '0xed0dfe860b9fbc7a4f74486fe4a2c651d52fb2620063aabaad3046dfcafd3706bab23b' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '1026374047176903929468201061193303905710441884688478624786261645612423271455804333792' + ssz: '0xe09ef707199e701ed5939bb44d72056ec512753fdf6a2308b0261ba17069a145c34087' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '736441003505661011903711212573788050558633808722090759760702642325456516504505894800' + ssz: '0x904761623bca8c1d81a80458d63ca84a0d7aad5fffc6bd9da1a696cdd2c51ca3dc0b61' + tags: + - atomic + - uint + - random +- type: uint280 + valid: true + value: '54215078046337070658914483591387968354971685352520300652696388433184098505836979725' + ssz: '0x0de6bbbee02412d33a0cae8a2c57bb8afa4f420f2a00b85677baf083c0525f8df22407' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '164902953569354434541848228980871926800863812704777025322146572441516435751360384928275' + ssz: '0x130a5329661775e84e1fd67e93e1cad12ebb9e056ba31ca356efebdcf9fa0242a67ee254' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '291531052912787807064587765399461836950404971734993519532387400656978989727882073504126' + ssz: '0x7e79521125d563404e900c92a13cac1a96a84c85b3943813f07279dc47fdbdffcf391196' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '198448216393272029754165267065719248322919651114506823200862937599118495878516498204513' + ssz: '0x618717b54c098b37f9b8dcfe15645c2d904995b1f81bd2a97c303df6c05beb3a36012766' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '411892664643207499593905341381662462338010666761048511981269030775942279690454488942005' + ssz: '0xb585395909914df9349ff9ff2b611a8c6c6e2eda54276733773d5037fb133a77ce2c06d4' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '17460533610627184952980018110698091129854158298256594138071034860087421027615982467770' + ssz: '0xbababfd11625fd539bbaf04e8a514adffc6fd5b47eb033c833423cf3c7b3c152afe7fc08' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '486902605761996984072152670157920118474014684182270296788772954726563173270703966861109' + ssz: '0x3537999cba609d039807db4afd40a8cd4c475a1d389a9e2ad81d3cb6df6b7a46adcba2fa' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '86601162605024166638930457660265166272892054280267727933558485505483001636302956248958' + ssz: '0x7ebfbf6843cd691f254a9314e43df497b6c6bbfa98738476503528ff3539fa521d15942c' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '415512347649363633615608669788780842601503035226699026576004878065364393031370209020801' + ssz: '0x81cbb43d58dad9a0005edc6f9c1873ac6129e0b2fb496749c9380608f01edd05ef2ae3d5' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '208177474990117632190045625073259419885562430564096808744447170026464229462577778502990' + ssz: '0x4ead3bb1373b4084223fd8231c4d7342f6cbde984cc45b0ee75c34c944367c63131a296b' + tags: + - atomic + - uint + - random +- type: uint288 + valid: true + value: '410024872315579396771779952548496199098180743028586455759125340883433037846147751009660' + ssz: '0x7cddd4ce7ca2317aae353a6221e1d507d0aa0d3d500bc314b095ec4e3c263219c50a10d3' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '105196538303486936299998001691849159842180040131100966356595522037239359106506771842593406' + ssz: '0x7ef275e7462df1207614d6f533140b705bc2e303577dbde4b434ffc0b96bb75c291f8686d3' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '51401986902242622175928744574404491512752015460158275286825691505216304697427029818172654' + ssz: '0xee64d1efe77948ed6f5bf00e40200b2a9f1e8cb5fd040de36ab2a6da47333486ea01785b67' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '98078353550630176427424854707064791518279897156269078658369592408854315787454868458812873' + ssz: '0xc9b5efd8761c2533253ff70f38857b69a395f52a63478a61a85e6a8112a44d63a5b66536c5' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '100830145923399032657621993603458755666686247126234381146193961366559866084163715771765068' + ssz: '0x4c9135d3be8ed0e4bd05ed14e23bb302352529f61d5533bf8a67dcfb5e35373e4df6e5beca' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '65843753989403608699845175432897474238609522844359758989686457469464177970425632333255058' + ssz: '0x92514c731ec091ac89129a46fe5c14fc5c7b9669654815f9b8236558f42b6ea93899736584' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '63381984136332901239253547271139676990845360685433698809319737558643681492590147082636158' + ssz: '0x7ecb9b0bf49ef8c2a3e3acda25adbc0d24f4e2826aae21cff2302911ee7870b1f5c83d727f' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '76823274391392865977254749209125429961844369033881984135623084447348576343281508069368447' + ssz: '0x7f62efbb29e06bef0e0e5fd58d51fddaeb7819337de2ca9bcbad9b652b6ce156e61039799a' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '84501721833371540610803467712558222979219676711022996888623254085616047539546803853344449' + ssz: '0xc13ebc70679eaa23958bb67961b597d1e31dc04b321e04f0885208cf679073b3f479bfe9a9' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '109505011555658906559217152478192322548367745826318087755717419364565250718496359318773490' + ssz: '0xf25e63805b74434c1c69b1ac9cf39bd0b04dd4c144d290900839e2d7d6bf383c4ed85530dc' + tags: + - atomic + - uint + - random +- type: uint296 + valid: true + value: '55140007306471310955129196374170842905278024706787194927419557614353926194973854166432805' + ssz: '0x253c6c1a11ff0ddbbe64a0411a949ffae77e3dcb847c7af190c64400bc6951d32be5a2df6e' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '7518424305389828877561448802209599682291353601478042372352335082498834968636952446200139817' + ssz: '0x2950f37f1fc803bd6ec9ff5cc29fb5dbbfcdce5a89d07a16d5e10295af5f936e919b35c80d3b' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '32351462780096859033766424413351019457418357887408473237065469743770778631534554645560543251' + ssz: '0x13c867354bf2dfdef6f1bcebaead4a6228036232c191bb5145c0392f930eaecbacc2c62d1bfe' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '31370641032612024743654524297848040315845302018231903378547610677190058542105443885708700641' + ssz: '0xe16b5f23f26aed50cece9ffa2965e4fae99932a856fe3cbf36433e46e18a6d7cd72522fa66f6' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '29189197768019204867361776509209878880250265344801969104058925326075443201837639541643160457' + ssz: '0x892bda280b19e6e56d8d901b1e9e2e8398284a4295c9158f9acefeb6e0409167986ea69b44e5' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '12126152267791959686806893791657751717575305372984499660774677878023396902925223071441407734' + ssz: '0xf6ce1ad043d02df0fdef34c69e5f9dc9b6e2c71cfe7ea395c98afac54d28871cd0b5b6d63e5f' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '27754000657791870573424297368620051384566454481161968602787832621717177488227594642163196994' + ssz: '0x42642bbf5d46b1f61586767bdb1e514bc3e6baafb8829dba49199a19525e40af2c23acc3fed9' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '14674509897016689354642901586561390812691688259482590490518819103217534723261716036031762344' + ssz: '0xa84fded1aee5f32320a8c715d075f1b376c15c6454ced6a493d446949e8adfbf95ad7afc4273' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '10974409750203643927728785093722862689371882962874941147088980236456174820334325528543184760' + ssz: '0x784739258759818ffd8501f185ace4e68e888a207b01eda406891235d264ab96a6b59ef43256' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '8773034183720629776387722485242417436235390926235538756449852277065464816500949850089588732' + ssz: '0xfc07a00229e5b4a30e48df48f6b48d275f25cfc5c1b60e2431b327d57b34ffc20898de81e844' + tags: + - atomic + - uint + - random +- type: uint304 + valid: true + value: '29402373314605751227445030990381133455144685719620264224291180547053282505574565188480687272' + ssz: '0xa85c3625c43e8c547e730f943b8845c075d904109e0b0d16d3077e5f6ce20435aa8afd40f1e6' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '7321707725011952147753519443597467161356275940570429766992925176822949145101163238647751878563' + ssz: '0xa3a7f15448ecaaaeebe6347c6b167478a1cb23891b2cc5864a73981564f2b3145073c650b7a4e0' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '1136646014892509587986593444105733028018535708983366340816181237331388025740303052244861460527' + ssz: '0x2f200a12e303a724aeaee827637ed108f9e95062825500a53d5eb190fc42aa1d27c30caad7df22' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '7959246976583376766932076981843115940992803074034967365631330264414213255835832243688383998354' + ssz: '0x92693c86e936824494e3b69049447e4dfef72b5a885035f0168f64aa28328ede4f8313ba4c34f4' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '6107351137933273847655581642494869487308907030068614850868116177240323904290909366998987208419' + ssz: '0xe37660585fba773bd5d1f6c622a48e801bb99f09c1eda6b949b74562a6581ac89d5529fa7d62bb' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '6140802159981895781296786122319823582398722389278504787444880185906342085250453508326485302024' + ssz: '0x089b9e577a36e1ca648f278391dfc30179e5f03f4985099315ccb21343d8ac796d55671c3c69bc' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '8110829379496825846585352861566852060822773039592504816667939006737009639168469140580967804599' + ssz: '0xb76e4e0a3a4be5919283d35ba9f62c0a80b046f1063ca25dfc85082e5aef45577150ee44e9daf8' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '8013905790131524873992548727432508440301237907080100872706721844443952385791641418561998731852' + ssz: '0x4cbae2d81fc570d3eeacd3c88fa7c3b959b12429b85909ecef722f0b5059dec2c69820bd9ee1f5' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '5469482167287631768657761622706498198081450134675243549102001224697264614857632730130716237340' + ssz: '0x1c1e8b9976806dd3e490e5f94fbdbeab825b642c12e88f9cd1f11171eb17b4503a72119451d0a7' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '7167791254484960175051783700220377616479875888435400025094742103567578731988619212784418265558' + ssz: '0xd69971fa227e106e61926091d19dfac46d0182ddbc2475dd8cbde5a03ae1e224a7b62c83c5ebdb' + tags: + - atomic + - uint + - random +- type: uint312 + valid: true + value: '4034975365150538046453477537125307010240073575773401700400915249820066282470197993375060557984' + ssz: '0xa0803564aafcba3c0acd5e5ea00e8861d968934b2426993dab571c362b454241a9726bf6e9cc7b' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '1280151611725962382058711679973517217918577786593633773883781861908443041942266852023483892073918' + ssz: '0xbe855589debd4f962aa0a9dda85e82ed3cfc8ce233a53f5f49903af1fff19d74f07ff83c42666d99' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '1175629971915001949897604736589156067254375586979584447253152806917540941900023462029343753849759' + ssz: '0x9f4bbd9f897415a212a47e254622725283ed5a3ea178d824dc8015d8342286c24824b741dc7be68c' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '1190212051475314698606139837785234652685953546261436241044483618261263943453052655223505081533798' + ssz: '0x66054f05fd7e170b34d42c315251e3f48da66e32bc569a9ab314ced46ab7de299a8dced886e3a58e' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '935825875651506998460550668708356905058224685295494697882989368813306095457057887930891805151278' + ssz: '0x2e50080fc542ab552924b2fb01f2e22864fc4dc33be62044b5e16f9dc42e5fb87a410c8fb4da2870' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '1444771337963886936020720722474050000290360243901646522606490622767404470616458484628471375389372' + ssz: '0xbce2468cb53f2ae6b4bf346a76da4ddaaa6087eaa6ac517b116cfe5fc0016b380a4030f20d3c28ad' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '666618525183652677682891603976464028075322822724612208655574574529974687587035550946688961240340' + ssz: '0x145d4290a51c243c51a02b051d548f0a0c06e8c9211171180d84d6d2b75fe0ee9fd9e8ba3b14e54f' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '310730716174623794305164795786344278376287740636880367902788594348308391725324646649798405379108' + ssz: '0x24d4b7246be9ebd2f59a0635129386bd3be3d593a335eaacb328dd0001fd0e6b9b548d20cec93d25' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '1511194807021601526493178344009798094923477890379428371286260842866384534788971275693359615142932' + ssz: '0x146c97e1bd854d7163d33f3bec8eccf0c2452fa6589b28a31b4ee7bbfaca7c463830dfac7b3a1eb5' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '465372998647954481528389514361931743387897694193689723021444038397600362756200075803515147171221' + ssz: '0x95b5b2195c8a8c59fa0b7a7d6415ac4517a7455adfb9e489299eb09622b012f8c2956048467fc637' + tags: + - atomic + - uint + - random +- type: uint320 + valid: true + value: '1392026254506891223414192256806461881034325240247704713119688191365785982202993807741225129224801' + ssz: '0x612a688d99a37864bd13c3101af5d92c8d2b25607cae211daead44f4dc060a970cf891e82eebd5a6' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '284988847798035986172445340697640116528123252056215432831103662315846113095178978363436458612888737' + ssz: '0xa1145484d1223fda4b627323a48838b73f63c8de0b08fdeacf444fea9200f8751603e924a7902c6c85' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '481163248994344932327086593439194971954733697819448144818934921492535272217422580916080330314237927' + ssz: '0xe7476ae5e076cabb169b418950e1f031e2fae8c20a7292caf6f3792d645a33bdfbd884113502db43e1' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '37713122233406867112389913619064826241026464990375425715278617740965850906506127646621868994789181' + ssz: '0x3dff4a621520b18cf6c83820c8b3b0c5b35fb8b5edf762b62995848a8b2fb991dae2e5260fc3f3a711' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '223143814154153834480288820840079310126192620985126455610005544398021316173291328672516391704603758' + ssz: '0x6e2c2e4e3a10e09de48b947144d32884dcbaebc269095193d4f914fd79e1756af260cb35d17ffd7768' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '75627809146869484805456290305203658928336299450275423329769371050780250248552883679013729632538619' + ssz: '0xfb4f48a7c365fd2aa19b4308434596337785a63b803e9f3d98eb5a1892f53799dd6cc360e2e50f6823' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '8171589185932715690517868485615562735698552458005813767713009896598796768220908210197686908719620' + ssz: '0x0492fda475c9df085e3b87f969ba9532d042c77090231a3711319884038d9eae1f4348361e585fd303' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '427816883694258491896164157434668562016235386936369841132276225214380068748949676033754787082305155' + ssz: '0x837eb22458e4913c566328740e81ca788a8e66174e87b19a0132ac469478ffd53d0522a6f0ac3e4ac8' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '97552355299263564137036718071617146467157639218042532980047770995888761147038560480035536803479989' + ssz: '0xb5413c54b17feebcd36d7cb83c63e1ef3e560eaa7ba6b3e541f2eab6d852264cfdbb95e0e02fbdab2d' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '84245200729750627814085799092386285073046710095572604620881645141898909599893245039522911503997951' + ssz: '0xff5b83b2571d816cab9aa9a6b6abc4b9cc35d6bce201fc6075130f65be231509cf8889240447dd7027' + tags: + - atomic + - uint + - random +- type: uint328 + valid: true + value: '169490407166194822469304021843335247417620875210077782816249037678717628252460830442933554917466185' + ssz: '0x49e0ac49729c23a1962a45a9702ab22724c4d686f1b822307f4f81d4da7c349a8865417d669094594f' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '44174223538517922327555465343440446610374783750947128279358659579572008955329968620388752900331742397' + ssz: '0xbd24dd95f2ee0a260f354de06c6e9792469aec6d09c8ce43323fb6bdea5e2b36d3eae41d10ac18f1c850' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '83675237983202871713688981362264876300857685244709258351226319235646708519538261790055079746860542830' + ssz: '0x6eeba823037b0271619883ea1d5d53d92d354689f8407f6c3e37d9ef3ffef12d41dfcad6eaf0ce090699' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '138380135856147544878424920302401266357159268922633543940176204557093965647900659327498319664538422874' + ssz: '0x5a8e03c0bcce5e787771a992491bd5154496b5ae6a2cde5d8923bba5dfff3ded96d038197b1ddb1911fd' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '130368017015493906067321069866296529103524452420956632032538950831138514747905670119637807342815417627' + ssz: '0x1b15e23e35913a85691ef00a8b2ab507b73d5fdc96a7ecb58b98ffaea092d5cd1f54df96559715166aee' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '66517119328379000697800735949188252113397945605964965827126954467345410080689077986809890862598506936' + ssz: '0xb8c94cd254379242c93db4bc82d7f995c04dc141152be5b31a6aff8f720602cba9c8596099e89729a579' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '108155759662685931858169535971104216170716666966185640709250854567131368708478379204842871931918378676' + ssz: '0xb466b4a516dd0643cce33ce7bf5664c66815684e9ce7ad15ed2b305e64f71b258b3e2f730b37b906cbc5' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '2107872012554454467445617570283162852459726237126746955646237078906261202628394888572177844795515377' + ssz: '0xf1a1826c0266dc770f717d9cffd7cbd7349fa69133195cbed3ab7e84dff7d43121f00a29068463d6da03' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '74117619849119497419396576007196371738554735775787354150844672011820444650691971798248787103464569862' + ssz: '0x063c4c4422d4621b2122fbd68c5f886222903cb50b24d141379ea5324fa81b7cc68e55e1926788788b87' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '4352487931763785862083469414626776434909901989212521068018449563551859037052517921781149112783109500' + ssz: '0x7c7df08337eb76675443f921c53ed29b982e567f4b51a444521a53f37a409edf2c5d072cc6e5a8b1f507' + tags: + - atomic + - uint + - random +- type: uint336 + valid: true + value: '122086677660824745687740253193028930339803172296557011197128180084781713031308571537483280111710962497' + ssz: '0x41032f355963c15617b0ff42ef3660b5fa6afbb4832a5adce6626ed0ebfbf81bf33655a876e7fc0745df' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '9139356519165700471586541434800222489413081411008919747447462180231340958915501043234454538292077862689' + ssz: '0x211f654fafdc9552aea63d9f595b77b88ec89feb2e334a3105a3965490b209699d4984c706e468eede4941' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '12454144626129263155986519241337546384755799642425466384456680461447344392808017265591419673646040192892' + ssz: '0x7c974df61dc716a46996b91ff29bfd3f847a845b5694dcc222cf94b8a41481e9c6d1ed7857060071e3f758' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '4105963924503838753238786172335095828059723991737428927166942517046574817330800425321763927436644781908' + ssz: '0x540f67b334b4e162b4b292a74ea2e17aa919c93c49bfaf64561017a3e9d387b821aabc1801d0fe6be7541d' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '32419657378762022456021675939205581791665531882382779500849615958076261762360323301790223510018522800231' + ssz: '0x67e082ade75a5e56cfcc0800875901f89691fa24c9b5630066fad917eb94dc564d3fcac0fcf275566a98e7' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '12270744730360040894454767065328525199545148960897819898660160262878615573122273205524375222544036093347' + ssz: '0xa35dcdd8be1eca32d698253e6451de5f8bfaabe1406061aba9be4d92e8c71276f278f3422f6bbd8b7da857' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '22395267022711250482952868057164684181088528903177786082749703003391473790433361589243988116805777501742' + ssz: '0x2e2e02f030352173c9947b66ab7bcd037fd96e1ac54f3601e96c6d1b8da16254be1387b9276f2d3503fc9f' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '20690904032281624295011945014721547919707948120891859124736840427817022388447502451987632580152924716899' + ssz: '0x633f768b5122731d2fe0428066e136c759f61d4defad89e326a0af17d50e341a1e47758bc3d9d39d1bcf93' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '11877141314993021016954194306504736626651123702775950463244543412266185453251930565233543655819786102077' + ssz: '0x3da590bda5d8980feb04ef3e6609caeb8cee2fd6c8c67b1c13701baf41ff1f2a9d53cf71d10f632aadd854' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '1953290876303443394777910056475728158953115814051097963044187535866142392488406044263712020600236673554' + ssz: '0x120a1a775f54014276e17be7790658d45e4dbcb12274f52a92799a70d2d962b45f42edd40b4b299223f40d' + tags: + - atomic + - uint + - random +- type: uint344 + valid: true + value: '27338175044291453712140260733064284621619330318152291105138117509157398191103534246665631787541238331108' + ssz: '0xe4368b8f0e3de660ec4f2e04d2b0f5f5015a691f1bb9b619265a4f4f65993615c9415da17f5abec4804bc3' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '7678086807425371999861606548598701872056517907912188061224822352540192165763258712376032254003863205101968' + ssz: '0x90c16a352773a941f68d29b9766443626e49c23a01c18e76466527a5999a3698c9a13281f79b4b8f41ba41d6' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '2144016186843968409162995311801653725362458281467257473567339992375907602458578798358365850304568635898297' + ssz: '0xb939c32f6518eb6cd7c8c9a311b265ce106f24024eb5c9963de8c16b48af71f856f96bf2beb73b9a8c25d43b' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '4240898854339149166767265184610866422983105455755884491989987475638493644920258184691465349421876488484876' + ssz: '0x0cb85ce7beaed64062d736582239d7456fb980c60759ef29dcd0be2fd9e508e148c4e438a0d36be644965776' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '2267765604112132015913934377577242098571949666399376033279589762745388339201981915105262126920334985042319' + ssz: '0x8f9986a40afcf105e1f94f5f7399697910cc349f473cd3c9cedb06f1acf5f4b311094c49825df4acfc2b483f' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '1906927330387057667507670493332998403124220485625896134099622262546438797493513408858110563349450966106427' + ssz: '0x3b0177161a3f16b869f8dd84486088b12c4ffaab301fe5f098b1cf8d68a0aa67ac4f0a9dc9a568473b763635' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '7086066947625248993755831198806799984128253742827802484157987526291352476242037095522112821873772034149929' + ssz: '0x294e4e4d6d4a3d784dcf338cfbfda25e2a86d64d6c97326b7f3861d1eda8dae929adf795d33b74a54788bcc5' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '9084373980623817999046029128051007464179264197951875296738810785590122696547328340823448931298876631987815' + ssz: '0x67b6be58e2e989093592a96c0e366c70c26269f5849cdc70b1ef734f8de3d91078f784ae76c10c3adec77ffd' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '8047865582850239427856866986125679812555039836372233911437853300223218665465829731451549914633020165675515' + ssz: '0xfb59253b1e917160fb4a2706f5b0f99f575ebf566709ef27dd5fdc2e0da360d20beb12e490af427f384e93e0' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '3640715329630045910047011955777626753599726008287032631194279156901669149706776155638292774937236375022005' + ssz: '0xb5292b8501f0d2fcd18077e9216c0feb79aed7ad210af06f9f5bd8acae03776e48a7f42dfeba184abf129865' + tags: + - atomic + - uint + - random +- type: uint352 + valid: true + value: '6063642904878355403006067999976167117871384236865664680515660834238680000941876926792928949914280231130202' + ssz: '0x5a54bf4fec7c3af548400588c92bb1092012ce2883f4947a6bc76828174a4ee51d3b6be5cedd4a1bd1ab34a9' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '1030181877056595731690201962923191361856531816302288790497392258892826467773778920593443574871539481764637797' + ssz: '0x652c67446020f254df7b96c2281f1876923e5c11a270520f2c65e6c332fd9ca664720bb6724136d4ec99304b70' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '1991381026850522454713510734760391320479548940420627171516120123676750899557811390817244436065786725532068724' + ssz: '0x746b16ee719ce6ee33896c74744933a27024324f92ab568c9be76feddaa7b234bf75ab60450546e0e2476b11d9' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '146794669928815198323400954401957339744024778999029681693279806431115549894012966307851981521513556475535776' + ssz: '0xa0615a0a87e0eb0a732862cb01d1ffec9d596817e4c96c5e937fcf01ea3f6a4bdba90f4f321ad90ef0da4c0010' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '656725067748292384731507472588331783701485145742323083023223017885219784154340376594969906189701327690291610' + ssz: '0x9a59ee9f95da080be6bbe427196ffddf10da0d98b9642dde235d532bbf5a407875ca3ca679a2cc1429f3e39547' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '1750903063076070506923657454539249642478574196608297479292541570158479179412706359248174516425050391915178280' + ssz: '0x28a90edc187d18720cf9b8fc257d5c80334525ba711753e30e8a052b5b06348a913f141a82db602320c7e3dabe' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '1522102445264777806351326688071644818027244438736771140486430964227191955699356390588587870597296935650212437' + ssz: '0x553a948d7c74843ffc652118446aabba5c428bca70eba0fedbc9cd60522978e522f22b5f513d5487156537eaa5' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '716411411276943594345753534683853217208584367528869646323170456560811475008791461509106937710778849654678370' + ssz: '0x6223cb8f8920e1b2429b65922cb8ee8b04b973641043a7e806e1844e2b33ff3d6194e490ce4686b118906f174e' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '1756869530148095084035317303409584194354386886683533775471781014920610528948012961301372397615401856306907796' + ssz: '0x940ade9ae81eb46724828dd9b91203c7fc4077f7ba09465dc54835bc039a9b480bc43ff1e5cd575abd416281bf' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '650465813811416122446012737287676356309144616844653427499568551064078652664772141117315410997725024474758868' + ssz: '0xd4fe5d0512ca0a026330510035b6a324636fff41836796bd5b3776ae71815ab1060da135ff1509a7d5e539e746' + tags: + - atomic + - uint + - random +- type: uint360 + valid: true + value: '547089254020057132368460768836094886929127607045615628933858957863675757626777874703850719429881678423583183' + ssz: '0xcfe9fea169d15618c5d86d80f80e11cb5083b77e913d0525a3c5dda15c125640278c26526f488430cdbe81a23b' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '272626039890169113235796121293132036228081979284454837776953589827661107639996222967268239173096460043076212894' + ssz: '0x9e988744599c01b92c365e14499be9fef6bbbd559ddc07a6f766a06a702efe01d9fa07c625b2a6ad7d4f44441574' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '540675402282818898678976881371772391804989559128386921125775012153543808061217934033838318848072321496492882719' + ssz: '0x1f3b150890af97a4268a088b1612cac0bf2990db00290fe44d4e8130779831742d5e30e0122ef78b2c6981a837e6' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '20079965529598929486603434055399269942372496350504464133928247628326182227009516631921209501085287816388725117' + ssz: '0x7dc9d897ade77b9eaedb34f6c66db2557e55b1f6f8346cd290d4bd58e3e67e5db3c5f51d585b79c5575cbfca8c08' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '17784704548839280831349524814914364621232359389824864945568465322811926576873927715107747043663039137125003669' + ssz: '0x957130cee87397e6ab2389bfd75694b9dc1a8be36752a8a16eace7e63a38bdeb049a9162354ca2c3349b91999207' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '184995082245894744006198172069733123527998049848534870230970286472848605773454547728513550523237321202231583656' + ssz: '0xa8a3baaaf9d65dde170e55ee94612d302622599dc78295bfec838c7ef76ad3691b01f1c1a9186e640e5a6829c54e' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '258135552691482661088963481080755199064727201036565958552676031058811910759648293964904576719085010859925249385' + ssz: '0x691dc1ad0a0fca6d1e359b61f38edbff3805da71c44fc9d3a7bbf2f5ed159bbc550e7fb81d8b97a4df4cb8bfe96d' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '506447106401391621782825535417559442047221084612017659984944621440090637226692531621687722515955979442769155311' + ssz: '0xefd4402fb15f471918d2fefead207b27331e13404890262d1acfde658011b141443d888574761fe7170d16a5a4d7' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '303560660617314207820166410792184837168868819866373533205581065550244179161802659638224222295498568902860328165' + ssz: '0xe5cc075201a4d98935d971baa8c7a16cf8d1907da214cf767821b61ea4dc344056b4f19a51c4ab50da57cb414181' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '498404969010571329247844529418408144947761593672462021640293619131147447582494129991682313711779381059993961476' + ssz: '0x0484f733e02f006cf259b245db3223bbd93cf8a734dce4c20be71b68a43aedb882bf47090c3a24f76cd2840538d4' + tags: + - atomic + - uint + - random +- type: uint368 + valid: true + value: '370190953423541160654308209939007616910069510509949219105905591483658864965033887394146306398816475799478914787' + ssz: '0xe3ce5ce6bc3593799a8d0294625c5d2f394962ce98de4e968d4138c198be65068a336f9b923a125bcbcfd235a09d' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '111055184911949036136734829151727766943049258042766033273391265708627200239269458091225789509130776239441289349754' + ssz: '0x7a0a9b40b1b0c27db805555771eb9eb54a4e63863d5f2fb9ff6bedccef26ebfd94e85c3924a376c6defe7f0bdab6b8' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '144947245527612210374018137105993380005967937101443137321255030880147795235910973788612463107247421902968713538065' + ssz: '0x116a36215e1b008169b4c02315023925457f5810977c13ef6cf7075744f5ce31b660550b4700e80602bb587df415f1' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '24918892354264929187648520405975705233973156055086727289771079148700792116229325449579736614900086265280567053823' + ssz: '0xff0df613c9fddb92c4eb06865140f00c0938a8231bd9fda08084697786ad28905855a822ca942a9028481f425d7229' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '82132505127051130096881567368862404093487009557008639077059874642241226948849409174738354257739635585303700437128' + ssz: '0x88f8d10127e03aa8130923c136039d79374dab67a9f6936791b203a23b5ec536c25161173166f26afe89d3dab09b88' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '89692734408048000770285467799388956455145122132077680560275472188025834673951658111800011828130392075137824361309' + ssz: '0x5d8b906c3a29c9a0172b5fc5f8cc2b3158cf8344b1655b12c4d231cf06b5082393220977a6c96452f7ade55cce2e95' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '26929326599569992051791749930098981463803494894034161188550796679270807708553116347698513550804357857256085555318' + ssz: '0x768816387adb497f2b668327cb5ece18bf316489b5161596cc52c39a43aeda716cfcaabaedb46b5169f1972c66ca2c' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '116617956336616789310377504840555863154231072233136893729545098751095219482031799338685237022128076777271330025763' + ssz: '0x233133a9bfb7ec502adec5297122b645139b61efa8ff335b275b95a9ae0f9db61bc7b9ff59b0db1dcc9fc91c75f7c1' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '142789823867267321502827807339266813485400149502532521662094350436769418253895789921895601384450140832222571118092' + ssz: '0x0cbe0f86939837e5d8857542cf0080e542db84b405a4131bf9820d0de874fc60940385bec51fd91671251d64557fed' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '49819486254732066582903680818496785196183550481524341933517067489762534929771865412010933859002245116412904641759' + ssz: '0xdf94745653866da08060b12c536494a540d8face74af576740e7c94284598fe44b863be573215d2dfa3e85eaefdc52' + tags: + - atomic + - uint + - random +- type: uint376 + valid: true + value: '20064353672818603224241174606034334937306410937648801428733696431850348173603444173187183367716583063444909098369' + ssz: '0x8185624d70b86a75217612cf7c28670e80c4d82301646159412ee42c2922df7f8ff5e639e354ededc91f2d3b525f21' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '5279086560674718826366959884851424269485574528895956300320184455287389870777585101664114175581452755569572760432228' + ssz: '0x64ae2a20f47b72ea362bc0c38e2da270323a286f97ef7a19b015585c8df469c07f5785397810ff1e9e368652db854c22' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '33749166046018731646348788623618740919928730871231300659005817916558496434983621182856810117061327726088147490248906' + ssz: '0xca18a33cf68def9dfced178c5e7f805006a00aa954e61f7f143341dc6bb9ed572901f996e1ae63f9068232a35dd345db' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '4321681689950826621816734495609392017596300368497816071316146138230462746576841535744375991516648973033867445359415' + ssz: '0x3753212e14ce864528111a325f9c1f806429668c1f9389b5b7584fd5dea1321ca2fdd04fca0c91702dee8a2cb51a141c' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '34284925870822036461118477691429911389596976718740740466481809461177779069185449643317573957502117533521821075231033' + ssz: '0x39d18f74c8e8b8876a0c91fbfacf4887ba9bbc8fd28bd79c05cc13905bbeeb8bcfcdc0bcca2cb1a8e99e3360bfefc0de' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '39123953872888367120425614261905527110740895591538389877835931650715197134263938482945123756165839968498051031340923' + ssz: '0x7b973ddbd72ab5ed4c4306d0f105b4aeea373b217dc15deb3b5fa1f70eb1cb2df1da317a9483bb3001967bf36f8631fe' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '14841420932823149019557945682611580392874941567684108006999108904746957883138811923104195390755449510984606334973889' + ssz: '0xc1f78df0c22a5e9766d828237734ab259d161d90bd96b935eb0f66a5e111ee5b2bc0bf5d86219119b57e86186e396d60' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '28262012021452788433947511498845499609654581012285137839927925554669320570582984054045295543536348489466767522365275' + ssz: '0x5b7f7749f14e6f18796ded23c6371a6b16f5fdd6e0bcfcfd2adc7518007fc2bf9e466ae7cbc2403032dcc0f0373b9fb7' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '27994838955377966757363319384000894815735798395160870870183297422770355992337818879061449696967729051929121146075105' + ssz: '0xe1f78c2dee01b5ecdadd16b02b96054465638f46e24bdfcae4eb26ada1071d53930a4d2b357812727ff0b0fcffd9e2b5' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '9653946316845826710463559064197203155838710537717779493508750113101840191427569072706889928205274626486049371951029' + ssz: '0xb58fb55448471aed53ee6f6dcf3ed596a361b81fed9b0554d565c510faa1517b4988a79bafb9417e5a1d044c9213b93e' + tags: + - atomic + - uint + - random +- type: uint384 + valid: true + value: '18053997788931957919102821737757947924174578181062457122693832101541945307758728333510766154774492968603573809799353' + ssz: '0xb9600bdfb493ecb6f3411f0ff2574958c1b6e154a2d7442b049a67fa50a7fc168cb2728f7161ad46a99e9ef1c0974c75' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '5731739628205919455339762572004370382602294736314565760608149410878624282800048376253171927107459523807334200189022609' + ssz: '0x917176beb38c4474cef338d8e5b9b5deae087bb1dab04e11307b90cac34dba63fea4b4d14880aef902b193450723dd7791' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '6060761852299710477694732029642552099793350773938689409486140131402164197027286521738100474275857073834986260665849402' + ssz: '0x3ad6750724c98b679451d1dbd61416069c0e1bcf595cb1e72240a474f743a2cf1eb27d1c304abf21d8f48aceb17890d199' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '8359341411961963112783459893405628156150200390201294332402885294736498459962888036113630584319310115408463579733425430' + ssz: '0x16fd5d54f64e3e4c3015589b840ed22762103c7d87baeecc10ecd6712b59c5016c2de89b0ebb1b53aa7c49e81ab2bc27d4' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '8507182149926454428585772346079203548820918814534021309542078888134603353834858782750512754903872983472550128046508887' + ssz: '0x570bc3c1ee980d831d9d15dd791eec735252afde1f8ca5d0127373ec7259c188b9cc40a41d8454c7db7e7f239a1a47e8d7' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '1686935923683103158448991139407760420900295000605763177951224648077672317904445451306840011545798675241786454263135522' + ssz: '0x22fd46d2c582a1f5e7bfee56648cd92143db1eb1dac0d5ee7b7fc58feb4f0d5cdb35a4fbc8db4397583c242b926d3ed02a' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '3898539391729495575817437925478146953655330267223907369771855227539339630791488802073921683473738025480662951028952110' + ssz: '0x2e8cc917a78f073ebd9cc31c7aebc433134f767a169162fd1bc781e7f62eb5b714fe63f860fd64d8776580a7775052f162' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '5662719121336147896230557672329921333276228833070396770149921979609535401517883083952205393356356581523235024574488806' + ssz: '0xe6204256c91fe136876a5af42e9388f801770e90bdd250593cac2b4bc04e02cd4b46a9293cf1532d795bf1b963b46db78f' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '6509839137627765955490425164913288862759744769224940662986596794445853437515438025234993077273531728702023247919663861' + ssz: '0xf54a912fce9636ed9aa1ec63734366696e010d14f2dead13fc8f35ad1d3ec7911fd3fd3fd6242389aee840114b414737a5' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '3226872671653206351676914632559409642389296844508917502616956261033920510952425684679204428343585652772222308348430668' + ssz: '0x4c890dbe7826e47328ed34fc4c0fd28e0a985db707e9979b8bed4ccb40321f197915d2c5e05a672b1b517dcf78306ae551' + tags: + - atomic + - uint + - random +- type: uint392 + valid: true + value: '1242606163273365581795881178398470490097374404781583102265390834703788683488007306443266184188594046238364408451688890' + ssz: '0xbae913c42e49089b30789d960ab5ba9b8ba9600c3b99c0df06607bf54e481a70ac3bb2c6868f9a4206debb36040a60891f' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '4247167969569434914428000905166769280195478770049766826066869811620360862761353851322147013504644438852087209147275790' + ssz: '0x0e9a784aa5992b934e329abdceaef3fd977262918fca6f16c1e97c264e5b695fbaf58cd8d62b9d8bd2aec5ced13868ca6b00' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '62897571922223237987948838179091913211911146453952313046870425004733169411395454895144015160838936819250700520783547911' + ssz: '0x070e3be239d1b9fcfb0ac89eb7a09b55c364d3a7742f4f4f2840f4e44dceea8b94cdbfca2a2ee7391665ad94e257c54d3c06' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '1551379147805009083156257178406025869454316064989258034685375266132065192447868085387068747648093849198696098386196354333' + ssz: '0x1dd5ec9255b9a0695079a25a2794251288142754f3b185f6ab46ab47114b9ed396503bc406a7915878c719d2faedb619cd99' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '43752006503828892431060792642033165147579025275413809148312827708285424801253085792607241656512905989463190310478149414' + ssz: '0x26f7679040cd2a26f2c2235a7e88d10907ee27b9c02db603261859d6425754a4068bd398291fbbe8c04c7dd14eb585665604' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '2346254434071671849097744428297383284411620331026052645007959273602011246585321440917194187680404027536760353313556637252' + ssz: '0x44a6956e1ff2c33bc02824d2e8323f6e1578fd91a7d80b772a1b3d4b68b00fd077a514012fe0ed2c755fa3b0d20fa9929ae8' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '1461491977998501580708730827034062501954980061179575335014489917569727768605498672936570013155259396184447460120582787843' + ssz: '0x0393dd2cc4dee7bbd2284a3881e7a1a6ea8c498c1de8851bb2cfa10772d2a6dda1e6770ac279fe64b2e2c6672be1fcd0e390' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '1158122924777378788731681281471678330391746679364789244646355039213337460515179704954753540732069853498248098333265716940' + ssz: '0xcc6653d04554d65ca09441eba911c70b7d0ab1a4f4dde89d43cf5986abca4b3ad34940374fe0548339aa4a667ced797cd072' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '677600784103219907814550219804169098151568238047606671117323984744678780539092251312768920803877918305050104115891226571' + ssz: '0xcb475f92f6b495ba9e9f0714e282508a350e6d1c16ad3d27a5e734e125e54b2ab92ea74d61653607f616b351f452211d2d43' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '2152365302791413768308561343990409587066352724717991811606790055842951739668344482280114092914107740334075035287413688638' + ssz: '0x3e89e1c97784ce5de23141233c98630b0101dc8351af56375ef21db78407db71b187c4aa0825f59c794c2245480f8ec761d5' + tags: + - atomic + - uint + - random +- type: uint400 + valid: true + value: '1470181807307583772686174482271588374569975040098975152461298637265339211365824569060435931932809610864400878831056976929' + ssz: '0x21fcdfd6d0d4a144f0b7f87d1699005f0b70c6d49254384b2bcee10e6bf5e2fe810bce43734176b228cd951ba1b6f25bc091' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '113461021609455118456917400365163393176461427732400393431188790564647687169891263568638752254673117879552813373462116697177' + ssz: '0x5904320b0703df88656f086fbad756afb189091c4b3602419b3ff5cd1c2a8eb5a64d743336f7dc827762f44caf6f89bc56f02b' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '161177877970261894328107020398331290218417800600090206817992474137761559884620792339285984023367490320384908621419860513373' + ssz: '0x5dd218e6213cddf73bc4c51a44220880f73ab4f928b8146c2fb791ace8b7878dc215595afb9df12da336bc25f54629cce86a3e' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '563852494485552482415660442562960508377551210793627899809416909836509534214990856044040238244900230349776503138740250338525' + ssz: '0xdde49bea076c56d938a51cec0445fb89432d8c94ffa592b09069943d3d4be313340b447a46d7fccccc455731f955b95b685bda' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '90091472700162216656495354660229654130227520267099510089187226229042295607434694474923734892617617710570926747629056641179' + ssz: '0x9b48c34ff034ef7ba3f21524216a8d48a207ae0bc0c12169a5baa1b0fb4dcbcc8155fb10ba98ad76401aec972360712d85e322' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '415809549226756195749155342966690336581194021631065106442409653768801095627371356147744819027751181798834614186798936025323' + ssz: '0xebe8d82f193dc0f851da765765166f2e979ac4c263e786a8a6090adee1519205c6f1b15590915a26b2ac541a02d66c83ac06a1' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '276023783823955506549393347863442878099170658215126189010103924230928794599111745180024727811897721625745210370555010521349' + ssz: '0x05993e7a78b0e2852b547f9d1a59b5b2e46f1cec9225f4ee03ed547e826555490d0bcc5546ad9de1bd57c29d653532178be46a' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '449895294533579025300404737316685596878938913462985420449139687421906568165000297009255278770830562333600128171028228901150' + ssz: '0x1e89940a56b846a22d74d2eca1946b678731494269442083cc09edb5e63f0e577a8c4238f3deb9fd50259a96cced71e7e039ae' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '50562471859891828436390960068990818307060336446601124150837221951715804359521554452732086632676134312448426585137357429157' + ssz: '0xa599a642197516b9364c61c8e5deabbeb8dd6cb3b573ffe6e84dff10aecfa9cd343932d428b53d736a8b89cc29989720ae9413' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '453838100169733997046000271605663109119214764159253951985475978133073155443412597985063120525637355141916869712230049925729' + ssz: '0x614ae0ab114ecb1851aa7270702238ef323174b5aa50f0473b3afafca72049c3acb1b35510fa1441f1a994715d309404c3c0af' + tags: + - atomic + - uint + - random +- type: uint408 + valid: true + value: '29099784399573265967434265629358336540859752395828923756099117475981010749749538971931403889578201951999416011583138884099' + ssz: '0x03ea0c6072438b33fb957504246bd064853500f7d68de3a0354ebe94b38ad7896f43e64eab1f8766235f34cbdd13549ae7440b' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '159331365604096661505620376840648156589121568178755563089267291599820898659180600810662108456164619166666128770642984882726469' + ssz: '0x45e6d46e4b094051fdeeeda408c921a27e3b36b26a98f9a03b07624950fa4e059952a110418ff975dd5c6846f346faa12b8906f1' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '17861206962090500043078253521678311806079514676484513709411126873582695935778716158996558404693291067192395720339474404900407' + ssz: '0x377ee4d3bdf9d5d77ddf8dc633b5c90cda36683e02b441211dffb5bd014a83367a4f87f630816b3b47892419553df323a4ea041b' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '66925896388801317513386317110251178735286908875646620681224985346300006022251502647937379454733944843202707819399103733333852' + ssz: '0x5c7fb8992b39438fd91b6f179e5308973a9f65d6d9dafdb97fc9bdcd492b679d6467066fc31402748cdd81a6fe6c2d7324ab3d65' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '126708894271250803276338248141968850405749862876738075440572262718925143562486036458850671891733994793814360836052252377427749' + ssz: '0x252fff1af10ca78e226a473274e22492667152ac6759f3aacfa348018259daefb1752feebdc0ae0484e7a004906b644f172fadbf' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '25988379260447854366815862554836026940884013638127238141531023079033086699026694595449262697206366046128024132033409578956422' + ssz: '0x86f6cfdbd6be8393c23a9ac655577e9a7cc8f4f0a60fd899080740c671545e4b06cc521b951f7b574d5987b1d4e056171e3d5027' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '120088987675348566515729404989827261775586059417498454226356407284305924914098494422138503160447710270254577847355714005384557' + ssz: '0x6d3dd474087e2343df6d57d0baad425917fb4147fe75ee9fb374afea9c0b5caf82d58cf2ab329dbf0a5f27c4978cb4387490a9b5' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '93547491052183338145599971805906377681735797342508503587174837164256802082087022002674715617504870509979774980751854459801182' + ssz: '0x5ece198de9ddd9f77f954f74d8da6a77b2bd5142d226cb7932720f184ab74115c279e8edeae7e3afabf352ffc047272c3120838d' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '164351983873113724076333047429017165244726364297738551879620927141923216081746747581145243619609348517814389591463518769192814' + ssz: '0x6e1f8bc6e80f4040940e345c63b455f7bfe3addcb69e1a55313f275cec20990e0ace4662c47398ab29b95957fcb38c2cffd09ef8' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '54128614234903382852871111974069705655757558498538078415502888538945782498787696738769046517897906323605727301475187474796373' + ssz: '0x558f23e2a02ae379c846580bfd64648a40081981dbed864db5c4b851c9aebdec0f6f27455aaf01c297cfcb9ec36b76a0aacde151' + tags: + - atomic + - uint + - random +- type: uint416 + valid: true + value: '104165421524991117164953390358022253147199975161028648181031904003838458174882580987349681429653037903261306529780647893961515' + ssz: '0x2b8b40fc82216ad1cff05a597f3d44d4c26612056128f2ce094fe772ad2dc0d44aa2519f3fb97d2cb71ae05ba49b21e65404939d' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '4169972146083962858994368355622153980043614666861543850625878741368389447260456844451108648964086323107997764532315255678801292' + ssz: '0x8c95d1b1afaab143cf43ba7df0c67700000d0c72df346328a798743e0542fb58cef17bf75ba0ba3bd2640f1daa53c7dfb30a0ca418' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '39771273993074588619004184460573629293748018167798881943436968176116557454686064571700949882485995151356699920555117287985245991' + ssz: '0x27ef49618d08f771bb85c3cadaf5fc6011cd85a55a3760ddb4694299496cdfd5e00f6509ac9d0d5360e78506e7819dad2f693f03eb' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '22855529001842080759396223578629577462665477539469606948724081840240495577255589228240180541495979751710423837630740767854211463' + ssz: '0x87b1a2f769f6024007e0523635a653b24407132d113b1877e1174a1a4de00fb29d4497c4e020eabcce6476661523dd8fa5ae450e87' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '5889558532175871569990532942888255735079398587019361339127059190885582497236914444258413506253897224960848316226216035011606564' + ssz: '0x2438cd1ab0581e2343def20ef587af021dcaf341c2cc506c60a7498619521ca9d57547c63010a1d3fdaebd9466feee48e5ac51cd22' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '11693859383588198827743922270431245149460223366994698644524524830783316631043965499931893591349451776400621246411167350591367408' + ssz: '0xf0a87457d20652a078852e46f486a03ab7d01c642fa76601a76b2f0f9159b8db5f3312e2a89730c447441caee59360f2bc87aa1945' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '27603421159757410541692309030777374639389468285518150598229786333384429097978523287400289536462210010452160772019672970543426274' + ssz: '0xe2ea7a260c127a36f7d60bd6c9183d866af77c2f9f7fac994dc28a2272ae61f0ac79a6d239b46d815a13a8c855a685ec7f8f8e1ca3' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '15983238058020606322841564303462271747324517492562431430205656490139062357908855836226083945968851195880612475787076340119161464' + ssz: '0x78caf69473ea2d9520f9408f8c3612a0dbefe39e129897180e63d09dfaeb5d2a7fc2905b27ca62417b7acc772d0b244300d957725e' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '7068857972143308191673151889969682971726414171708434124537299818725558714984213855108050683021328595535988801561565950755206936' + ssz: '0x18f71b65d6d7286b8850425c8f61ef18a32735519eb353269cfb6a421f920bdb7f0082ca5657e82d9d400e56a1309772173948c529' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '13572225941337295660648603746777467779188958394212015432660793630540183029609849134967837240138642924482648093669254478669901938' + ssz: '0x7270c95f1d3feecb86e6b25fcb7ea044694a8dde63c497a91c09115a26e2bfd1e5980026996bfd69d0e780f7f156f934a43e213350' + tags: + - atomic + - uint + - random +- type: uint424 + valid: true + value: '11738758844730304687783987959426666333306171641320675629640636876039084625352195450931619756138919353721685459275860112975699152' + ssz: '0xd09c09952f0fb1754a051cfec9e337983cfc496debc1aca868e4bccb44d32c96995a09b42abc853ed179eec3b22067005e42965d45' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '6419141289321281887213744774855624377406927509691556779950652633796989497534113999541941024240959610928817591591198692296687435260' + ssz: '0xfc3de507ee1aeb70a30dbf687d880af878960eeb92f54e919c3505cf3a87d2fa6ac83f18e61f51d795085e0dc99af8fee7ba69632b94' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '394349901397301538748345241928612753125986957854568694986997408377293145408674840181027039516959823981118209843764442835232133017' + ssz: '0x998f06520f14321f8f9004819042769f03ca03738eaebe285336429382502bdea35ad4633bb1513a9c58d3b7599b30202ffa67411a09' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '2995512148459941522251311973202846143976345727465277758032694728224667332643739910489824096762454862531605560802246226142960827594' + ssz: '0xca3ce0f312857ff47f3a15bdc0b7fb7a4943765c94d383e458edc8df219bc4d23d9e70ac16fd3878aa3edd9c61dcc8b725b2bccc2445' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '11062579283695749428688196400557325234013923757810274179671775813391360717205427888660599307532251145469821223829270398683112875235' + ssz: '0xe324e107341896bef61d69995e076f654ad94ca8dfe7f1d3ba886a6c020c50589708464f8b152cccf7347b242598454a582405f559ff' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '6487364518748342252851559755784609760039178228835556767863545066925442836662751281153225616913762734468708992451624420988764862862' + ssz: '0x8eb9cc2ed462207fedc730c3770c14f16005bc746daeaa098424a1bcfd7361e871fde3d4136af7bd7aa6f868619cd6330566d286be95' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '7699161498798831098348883188089734634665216560919475806638009621138740086461014305055176642365948430279919544882776201473115042640' + ssz: '0x5033b0b04d5d29ddf9ece26cf01a8f1ae39c214f00ff314574cebf2959a89226c0890bc1579295352814ad4e29af60210223f129b7b1' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '6357403771462204583172663975627499180128251857587769076147787071325328639978800600952927153554441733559607796208901478865049372985' + ssz: '0x39498a35fbf684df8916b293ac20cd97b34695ccdb4dc028d97d5b0feecfd01a28f2612055e27bff767542eff13a9c40ce7a2493be92' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '7574416043804217061246750748978737513926323945055065325131704218046097685903291608147003087069031306333161650486221114803354824922' + ssz: '0xda70a38fe7894d86809927a0b99dba424586c1d93556901bf4faf9f5bf79018efeab03f052f0b08ecc041dcfacdc7b0e18189907d6ae' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '9357324492136846288323549114756479335338611150748554490901975855172689085450148877520953773076721042245817816806053977249504685804' + ssz: '0xecee85badd3d956c1b3e7f9bbd4ce17b2f9e71cb2f654f51146dd8e3c2685eab17635d962de21fcd14eb983ac3e98b1e7d49dd6cfdd7' + tags: + - atomic + - uint + - random +- type: uint432 + valid: true + value: '2329812730267966243103926754004352213819432007317133515881600370908692568424564008210556271375209377960488777918427266565607814702' + ssz: '0x2e76ac97ebc6d9f9c3a95eeb4cc35fd58c52fad7cfd0cdce16f4a697ae06266690a6008a7e3d84f1f6cbb4e9f27d99b6203c721cc735' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '514028040159763231446008961516794474888916955062297565220382741839411327721918349021425204704594994763163043384860537036290813425987' + ssz: '0x43795d08d04700a32e75bd5ac51b3335b9025be194ff656942adf291038bd4b10f264ba529f4a81d5a5d5d69bc2a0a359edaa05606592e' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '1223041147920691418507535705620177978744499694522727552210745007411233451392996471437448063365143287067418850088121530744795381886290' + ssz: '0x52ed631aeb1b1befc315c1b9315642c10e0392c8ab5f2e2373baf845605a533c0fd995ec8ed742a846c73dbc30b944f9e291d02bc8466e' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '2454236307724703159363090145682800611466361635575839954993043564401988584381181180804873328972181786205585351981099818134684809856957' + ssz: '0xbd87504078da6382f8b9c43bec32b07fec4648941e7b483651e9ee90c286180df389f0901608cce7ef2d39a9a09ab11bd26ef243c749dd' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '1365846486265995352980912539505908724029386421876495783801253316968295182495585490344828427768192412612118460554170221555434734135992' + ssz: '0xb8aa0aa428b8f81958d82dc88ce99509c4599419887dec53c328a4543272501d35e61b9f0bd87348d7b3b2f780a727fe86e70b1914277b' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '740757568295914766229320438308609164752588150569210023992744195480708963260348134261869507339432213055674524636416409384998365053073' + ssz: '0x9140ecdfe79eb2c9834c924dc875f7c972df0f92975b9d1069a5c218ba873d64c404ed7a65b93026545c0ce8b6321d53c09e98397fca42' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '1405439067384555941836050901147193351471391586156867176239384030523392628274089342336242878463740926408410482173184796184887331552944' + ssz: '0xb07eee3cfe854e23ceb2220ae4d1e2b638bbfd914638df0d1e61b9775cee037a72530f8c42d5408de163313cecf19f6c04ae74def8b87e' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '2294004515487741116319256992682205248271301161766838034690043073659296049906865039006207368495301155029418499416905998556115393759302' + ssz: '0x46c8da79ae2809433c662cc9593f9f7a8d06cc3040b30dce5063e47397e248ab27f6e428d9c34a9ab23bc836654613d5bd90ea913cd7ce' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '1202281107898550907621450090974404155939235407732316707421611751680840802831028389407295173942147933115721736254312799330182913302885' + ssz: '0x65a16be76cf76358c926a6ae05c5f9db7647da90a52cca46de0de50182403a4e8b4631729d6790ded52117f8740bdcfaa16636e396676c' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '143618629713062870398677277011908835375718070041707189232511397158188991030570818590933871208872412848165230586453178547410074176656' + ssz: '0x908c3d650fba8839dfd0124adf134e94dfbf9d501e1540069b5d3e5cb076a7d096bcf20823012b6d643a6dedf3262bbbc2da78c011f30c' + tags: + - atomic + - uint + - random +- type: uint440 + valid: true + value: '2572549636006584246982474898308621947242755229347359606746830648735007257189348753989006788433009231509140599186878448662668472195930' + ssz: '0x5a9b7b92671e69cba50503a050ea638cc60d7bca993e9d05a46cc8bf77075a0c4403aa0dc8da31688c1c93f4f5e58a9ff6c3fe4cbdf4e7' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '246416201043726844179360088388913106752351070750163253768160828524971144388163443923241139931618685221641028950253981348946657142937100' + ssz: '0x0c96e45499dacba41312b906852d80e6b824498e446bc961d08c2d1bcd39b66b529b004693678ecb9f1f88bcb2672d0b6b12d6ccc950ca56' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '203238052207924696038662662926765236458869625942995113634860677945587164059881291302030357450133391194754409352096720566440927423903545' + ssz: '0x39379886009661a11bda2619cad292d5245fa592c3951ec17bc1688aa69fcf089d3856366b9d919740c4b994737570691748f5d3791f9547' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '290835705525559513971591750730164868873851068070637928050616258363476796876092010208611194666447682367072950635429024346123593471071867' + ssz: '0x7b96b91bccd5402e2e6b201f8a70e4dcba5dce271000fd8d7917363ded0a3a3b7ca1aa7b4a5d0beb702dd09a4dc3f1e9b6e58942a06f6f66' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '333064016894712497211605312537942543628764109637296170575276279231175469303446716282928246088070914695409501725469954449726202367475713' + ssz: '0x0180140d493aa585ae36ab876fa3ef7c8ab4d7d96f9e3d130ea529df89b87f3a294d4c217337d1647c0ceab051c028ef4109caa85dfc4e75' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '587863929699460423873263263891916233817469707284519723944507640760086410277566100962792784638218176032842415697579742801900792069767040' + ssz: '0x803f24313177a58c16827409fca96b8dee64c2fe50b484b2e1c607aa5f2bf7638c52b927545e56b3b7c0437ec3c3d8bdb4d8a792bb390dcf' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '154694451161940560918503233491504843951427272187380390343486310805307940798605991304788607867244826081313066644123523273188387890838976' + ssz: '0xc0bd2a352ccdd9d7f96270188feaa34da8c99d4cf4f4f13100cb001ab1a4143eed0c9a68ffe25ff1d377af883acaf129de5fd25066267c36' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '691375110132974598504225219123973274349648387306452387169800815471501259742819708149917824838111826897187171188177185115823130182242455' + ssz: '0x97502dcba0acfe769e5af6ddb51912d90a2faa3e5d9b4a4667b7d3852d1732f0a71a535d78337864b16ef8dc05cbf010e170d595056582f3' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '283648559621493816014182606703947344423604196695247695245677751798657574018530537832607378701279968698541634970789664632873697247751645' + ssz: '0xddeda3709f42fdada807c4183f4522fc45aca82aa38785a3610fd91e63d6e2cebcc92a863456bbcf486c4344cdc1d343fc2c3502b766e763' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '276066325033764025582517737651018859959942449495651174100203565966864769029923001646110420858273441743057554012471310506061269236814653' + ssz: '0x3d93e932d4135a06429f979a179eaf297b7266c9b04e780f54147b6a26c5f16ce529485559c524e51a2b4d6d69f7e7cd07dab7b830be3b61' + tags: + - atomic + - uint + - random +- type: uint448 + valid: true + value: '670650493194601646392320947758429870193538980338118199206960402816594957375145476361952460634220584266899935440032884114961997603845875' + ssz: '0xf3b6288fd011913c4c21082a80894ce61e6a01dcdaf89cb9db890a55e74adb6c4519c623f2db7181183eb84a644606ef513538c028be35ec' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '102805373965532814961848807291887401323266174721315483175153020984939115384449127712680563054413656391135331963349759230349825991858984297' + ssz: '0x69152c3f9ac24aa3351e1e13bc73f7448f5ba62578c4c89ea97b8f316722163f86d26e220e18640303791ee5d40491b756a819070b7d19718d' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '93292933700035973057025919159872975181785791189089668247770105558051769978661384826926704767245423368347045894238500216048931070069520395' + ssz: '0x0b38d9b4711f11f5537bdeccafadd8996c50dc957e43f2d536fd62cd94fb7b2f5f2e811baee3827501ded8c624e6dd059a68607a1ba3b85a80' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '123217040389821248420066541897137003194126917464485728822383049407252737026851919256356837770845987625458167149375848383259229504386447456' + ssz: '0x6038dddbe27e2aabb82648c17dc39b5eb0b9eecf2a9bfb41c4806e74c1f1d2cf2c5c23f477c990b97c4a839c5a993b48a4d86d472adc4b86a9' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '61166052648956027090477675109934491936979740066040487029906659807540105604405349067742544547305209757914535746389516307438915283945950363' + ssz: '0x9b8c82fe0785d95f800acafaac187721f2751411fd8aa9a4bd88e370b14266898566171d3667d5d215daa0bb9ef5ed186cb9bbfc9a7c4e2754' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '156786905992872955803308946221010293781630556189028131258694176331573617228904165678711428643524244006354784629777424126882482807151942467' + ssz: '0x435be6cd104227e472bc7deef2792b101e5f09f132ab02a8d914a76b968f49a9979772fe3d149feeafb0711c7f5c6293787279d373e0f1b5d7' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '165152306884598897566960841058103380516641725767185106008038917877347341378194960367629183543310546070109416303307480669655907978384395233' + ssz: '0xe14b4650abe3f5e9bb96f1ccd65e6f98b92d423082636e8f4b047caaf5a0c1cbd40288ab6fecbea8f7a493efb19e480b7d6355d55bff5238e3' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '76722058929635132509803636424762206912328360560732504738234294930434941182241475266925847761476489576876295497605304858794779612347722831' + ssz: '0x4f6cddbc6bf22fb910a915a1bb34cd81811c8a685c47ee22a78ac78dd4d6348a7a42b808b0ce28b81e146032ba2064ed0b92a34806584a8e69' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '76923234647682726111306022868346799722488777891421712719980026091614783268949710619949155870151982396826301134767531006533819039280770889' + ssz: '0x49afe34381e91e0e47eb718361cfcf5dccdff2b1037d04bb1142d448a20053622237a421e6036b0995ef6231362ee69fd346eb4cc88325d569' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '135993888696959055873315263004524900769614866593086427350967815854690252359549596121450912224739835471819924127640787635022775607050882300' + ssz: '0xfcccbb72ed315c4b0b87d200bb56cb0aaed79e6dfadab36f3e31ec8c1ea1fcb0de9454f27c88a50270125ab1ae92a02a25150dad38b26e1abb' + tags: + - atomic + - uint + - random +- type: uint456 + valid: true + value: '80190353610246172908070789426813428389101281816176242368260004540251733021929214362739438016970664569360108193884296208835005749645418828' + ssz: '0x4c21466bfd6d033bcaa0d8df6407fac3cac3cf44db13e8c462d6cd66f7bf1a80d970a95ad568be904f33ba2749684fb914f05c1797eedb536e' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '22530369699872541951983379827836173557738664740144876527285282091069420689946938368032416095050156967430271266810807054801635812166053026755' + ssz: '0xc35b1aaad09cbd0ab4b7d9f89749b36478adf0df7efe7ec28c802d60ad5749475cef535421103bfd43ccfd315d710c8118551bb753d0a1c11579' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '22057702698962344137657465103631616018131081846277651019752523102033344923103885615101889372708730290217648509174578274765702675829377996861' + ssz: '0x3d186891212c0496fecc5791c1f05709f50d16c88214c07da03cd1c8aa7b373f030d913428e5ed471dbc22291e9e69decda8252f7c5280738b76' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '33222118688602071687800017999568596461949609937051308025022858977210821091535260999896132588968447042264371681774887670379746661724453459072' + ssz: '0x80d439e457e1f94ec58be3a7bd2d650b04db3e9100cd3b3414134e4cce18777cf644d9615935e41c8b30fc9cae1b79ac039484cd81a37fb08bb2' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '18183220739516959424947926127609785228682685342499985336469655540887468386736226582060797374380560706640327734356825257558558772366562490022' + ssz: '0xa6f6da16a57a75aad7b63275f3e11e5dcdad4f391a1e789e2c07ed94a61c570bb73370cbe6bfe319d6ecb05be3c7ada87ac40876187680dbb861' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '19472369425114632925711799596229169565118705096519535271191939324591247184726117548427876139732417580214545740439513572615599557945162813185' + ssz: '0x014f6d4fe72d084ac99596bd8d905f19c628a4c54381c00081d86c11ea9890dbb492acab27224c9a87be666f5e921bdf77e65b3345cdcb7ea668' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '43327964681457755689063488002775650902577187652911242693539957215606615748046658003692643741233262269827263707877541977764429895382173823902' + ssz: '0x9e331d7d19694fd2d739d78eaa7d52adea828aba7150c467d342eb8446f007792ff81ff1767d3729ab2382278d743bfdfe331e0130205d86dbe8' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '39869270849136708682000722974167333126355787724829411072096681103986697311550673574444764733874702123010718522584269952949547722426613669193' + ssz: '0x499d8677eafa20af220fe28d4b1ade5d2872acef010bd67a45e28b9e088ce511af80e8a6b0f9e74eef0ee735e862a5c0f8dbd1ebf7352dfb44d6' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '19929601954653473377264309340216604190747950876252034197030884047888769744160837244429168563416357230851658955981036546906027249767121113402' + ssz: '0x3a519f76e8370b5a67c4457118df56a59c0c0d2538ab3cc70a6981b056c3507bafd875e3494d725caf347a1054c9d141dc49d6a5bdbabf901b6b' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '22782190727475881582052679139130903855006389081453159314873822616964329831993630211649773612694835415310499902624990129417220501527541788396' + ssz: '0xec2e130c779e27114c2fda040d1a604093f049f3f87343254f6a0e70b0c815c3ec955afd8777bdfa30649828375355e4586f50d0c0f08f37707a' + tags: + - atomic + - uint + - random +- type: uint464 + valid: true + value: '5879450681903931088511428832977637272445476307243582435715679989493617189235593649143888053618489046584326522905895427095220289897666648652' + ssz: '0x4c1a03a42c4a0a38770951e8079e1f8a70be7ca848c395049748bc0fc3c036cdeeeef572b771127d898ef7546919ce2646a55fa5dc5b6612991f' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '1348423945226775034482437413124154910811249547380974430909856651908475203882614275316442281870487431049329860901475278114608243740196287390750' + ssz: '0x1ea4f107601dc390c93d9e456e255eee6e2fcba8fbb028bfc48a9c9292e017fa61c987bbc7cc1cf0c7d1bb50a59a663c15069ec0be1c5504d64e1c' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '6518465420646570851319774511348748454110212425327691151679507919415440571598786403062478744755042414708135441036466084580259433824165658625927' + ssz: '0x8707bc9948d6dbf9d2e4d0bad7d04fae8eb8fdbdc9b0571c2131ade40c3e8f22eff95f8b64ae331e3828cc5e40b49f5c72aab9ebb9cdd3c931d888' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '3361355086817535935829925085552097133379157271261909894202170974925724175979785331515809738185808804482899087279471352939689933117924005496134' + ssz: '0x46c5e9eac9ab985deb5bd10d24ef0a10232d9f68026f944aa73314f1ce1441fe3e6b94cce05dc05cc7d7a147f6af22de0f56bce50f4dd001ef9046' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '5691196358964131645868088435747619729562995783219308192370687514465361673305451276928613406393932060069366131310402682552122973610244760472287' + ssz: '0xdf0a497d7c63e05521e172386e59583440606213c38e966c82d2e358760bae88db0b40a99171ad123b63692976900c2d2a6528a3a6af549e337a77' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '11264282136275188428637407426838650698968225727234105441940491049964411494641218050633043370397907617375623307957515453883327751093896124334297' + ssz: '0xd98010d7088ba28dc104bb16703e5249195bdcf4c365a4b422f23480f19bf9c2de3759c6bd530161d449fa0ed17747a00862785b9c501937a479ec' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '10127278323209520760618415692176687361921453917667723833039120912969982985704121542925839769041515694394005556415953454813280172573508413651471' + ssz: '0x0f7a23108139f0e7487a05d9a0758e1a1f6e51c992fde69a0e146f8c885d469ed4fde30b18ed675de5b41f274a00052a062e905b364c2d760a9bd4' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '5049951315819495231469201624332535789081264521930316474066240286348981891890626959220851345285427215013974931424473030642099020480324250088606' + ssz: '0x9eb4bba28a39a7f903f9f18c3f04c4dfb5df83a36b53919ca3edff3a4a7e3904cf4f78743d71da79f465ca10d920c03c459d7713dade6b34f5036a' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '11856436373188990359378342622092450699980949034853004167647193219431513982895875100334215768933420778611170982543222474803906067314242414078078' + ssz: '0x7e68322591cef7a8a20ca7748b9acc79500a02ff934068897d14b4abef5015a543e96c505247710375b3ed5fe197ee0592a0141584292b770ee8f8' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '11624443541778448095201055540686355063202164440895564587397790162680550399601284757045166765063481425700986932891989889814975229337927085799044' + ssz: '0x843615b5da03c601b01274f3f1c25b3f06aec28640c7eb0ef54d8dac93acdc1ba295c2eb6318f76028be78191020e76847d49f20bfe497d94109f4' + tags: + - atomic + - uint + - random +- type: uint472 + valid: true + value: '4051271073476725797622978502580490399792635236384486294639472893911851465414466561981774204901299221620286679894605056893749825911397358473875' + ssz: '0x93923393410a3491937a1feac1f1ca4d541f9392ee2fe3627c1c6e01988d9cde72726bdc32bd028813f81508e1a1b892ec488f372f85a3edbf0c55' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '2749638391693814824462311603702485840159383794814334155854492090616052398475848491515735919082904993175388380094061496211224045251435047406893356' + ssz: '0x2c795998a99f6d2d30fb48765716dafb27caa02d4809df730417ea30d4c2d3027a8e5c81ead958c4aaa9990b400a22ee25925182e2137d780b287ce1' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '2188036895666390011590815152270174004281814405156934323883206264124592106292055896950651402980698740463874030155366525986375852261406215276736480' + ssz: '0xe02fd6f24eab1e338a9179f96eeb1f9100595bc7a2d2b355f660c2e0f911bd314dc621b1ca60fb274c1312c9d37e544bef1696888da87e89a0406eb3' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '1317918658680722708835329426976296679006905606319693175050382782786544849356616512385175534937192669906925873432793677418374407122828867874542092' + ssz: '0x0c528f6589113726fda9b3c5c74f95ce8b7d13ad373baaf2be9792da8f5b4269c4f0ecce6f08038908e3657d499a80e2a303bc1a1ea5a1436a8b136c' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '22081782927218928125778779369550968535346714780662978818755333001007975249647342594027742408251774350847450613481239737506645867036514161197899' + ssz: '0x4b0313ca891953da676cf75dd88feae5a39fadd7f2b5b2c4c6d62c667c0d0f5b133863d1ec4468f8845355c2920c57691da2ecab313cdb422592cf01' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '3073958132599819962582914814120619953553652435422800625279463967838384448155953345971195861517445485622160015271136469798768477896310476926445506' + ssz: '0xc267fdec440e24757bfff05decebfe36661bac17a2d815515c5e3f03ff950d60f7b864dc154216ecb4b9226b6b1f11344ca223961040d46ceab714fc' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '930117232314538608814586452703854362641400484336450837205570712712650153539412263812152601598794563702835367499133979505777862606271482636869163' + ssz: '0x2b1e5def808383a613b33da17c79abe4057144bb6c4631b24199b4a495efb8aade66586bcffb77512ed1b11dfc2e50040fc00035f5f090a2dd49464c' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '9525113958011702260365319632479238019253170676743842331215206589878259120785368912303378704294319450776010398841072964634690364147683501832919' + ssz: '0xd77ab0d051f5bffa519a0528e3bf8a3d79ac26a64753508580077e7e074ac9015e6b7fc0a0d9a2210877637c062424a4a7f70f9f4368fe10d4f6c700' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '3089869664575579896881292687382493530745729278054430855563647589381778126889873267222430969263701364006458815325664744411484027417041541587571290' + ssz: '0x5a92f4d7d9ca7a7191a182b915e4864453b89032ef02ce83f9d842f23fb10c8bd98e60fd1c11ef23a30edba033980dd973b400d6cd65baaf46c162fd' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '2676630200424584735522771830162664683378598553860255551969711166687239609709162210628081837545410742357465150754036397513047374917086141553499324' + ssz: '0xbcdc3274af1b9535f183994388e6bdc39e61636b32e8fea6a1acfef507460bd0251df46f9392927d0c4cca0fe3f4bd57f0388ae44234a9ca0e787fdb' + tags: + - atomic + - uint + - random +- type: uint480 + valid: true + value: '348089219201642602859222519120059062451065537871706874544845393900787393768103175851566160496785297069372687174861800607487439864891252373292477' + ssz: '0xbd85e988dcec844867e74da632e307e12c45af4b2b4ba59f1f06b66f012c24d8943c61576756abe21259aba75ba58fa5cd6f81744ba588fd32908b1c' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '37147144462198307272012116417366048679122614032307038258777683417167803815859754405546623683318694085241108779205492759561913426551294535309477623' + ssz: '0xf746c4ad4f13687227dd39f90c1069a50e40936976b1e08b05076e08a94df665d678ab8a09b8f659179339a3825fa901c1d4b55a083d3cc6657b43e60b' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '82226115669998822836719969198820426598888673144332716434284929874435450310546629649031939739249831974452600516866771362601061262900544854224839034' + ssz: '0x7aa1d8315b5de59a96c0cc89a00422e0b426ab37467064af7e36621d84026781f93fa767baef341e94f49a8c1136bf0d99e4294327ba98514daefa561a' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '400852819349924830094471586988724509084678818404051034344371034961042390911732219476908123880791718186697115634180997744525639035259012174046506506' + ssz: '0x0a2e9773724379af1e33b2bad58ed1c5ce703d2641d8258205309e962c83a5047c2b0999b354c7a670eb52f953b0d6ccf3f4009b8053199c35ae106880' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '786498151876341735250524189249312157539439888501900344959834142236046919346680403575612914762547920276695371274534301509838548456211941505773846101' + ssz: '0x55be6f7b1fe8ba4563730c9d52e709bcbc71488822ed6bea70df8face00a1b39dec7314bba578229e4b51e3f859be8ec681b6cfaf4127c33821209f1fb' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '100361271215266487034245481073609753601391531014004209741577374303320717344268986947987450522592817741548471525770922932342212457886889818746040920' + ssz: '0x58b248bd69ca233e0ac347fbe8fa6a3ec4c54dfe8a033ec45d555045a95554d1d41a7258505a3b302a73dcebe2b44a9239d07fb7590d7153d194282620' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '482901758660725195390213085240475183072278084516918153178638010667860001221845126063047657826974795076709961661517576987286161447668587449312769945' + ssz: '0x9977cec93e7f6a628204923137f6fac24bb19e346a4830d4cca91e9d9b18849af5e266351c73b6d5e4c49961aa6be1dd10bbc929ce74727c72d583b09a' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '720960038680116811970143838090487314496440388991549358072696184028184865366572584808545200280273699788643128582280650623819887406899373962675644023' + ssz: '0x77667c9de5735d14c8f43be82d486cbe594c711838c168c460dd72fcf8a3cfb6012bc74efb9beb37aff16e0772d9f50d418868592d015416b0ae8ff2e6' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '520166226244534434753310198374347434264060199793196460401679664541902691950997853917462599342312745238077811640319690716407214526018479199502540945' + ssz: '0x91204d4ac07dd24f15340c7eba11726061158046f91af7384b6c38ad906b358f6d0e235f9063f6879d73b8ecab57d69b1b33f41bc03ef6e7995266a0a6' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '614610537810329639884486046732207318214370077413904256583811823807862498401220699415400304723389407939636667114451262455462166532506545631284367714' + ssz: '0x6211cbfc4b1e8a64b57b815e95c5461e6c78fb8873eeb8fab6b900c6fde1fce4219b462559fafd9e960f9f798380219c70f5d7dae8a31996ee0556e1c4' + tags: + - atomic + - uint + - random +- type: uint488 + valid: true + value: '342295295609394523042250426329392128078505988690535537334313556248009687717825982198850178469136590732796770102896744784058633910046749254227791274' + ssz: '0xaa0ddb6c9a70d3962cde6d8d1bc7138f8fb17b3eb8ecf71a66002cfa4cc98f1449ed35dcdae365fd59184556828c406a46352a884720764e7c5609a66d' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '149032207128341879543864880133276380098995601337726506551449979703616934716915346164554061563540996643968533058639883944310369514829776440517473253130' + ssz: '0x0ab74a7e17593f7664312f2ceca284a1c00bcfa47f4943e50fabc3aa4217699534624396e7716f49da525f850f477d8a76f00c78c524e2c961845efa7bba' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '184801130946020455460243220257467380422812018701051803876761587979412282556133070256983612515158281586264997579689789060392578063433905071596766425940' + ssz: '0x54f312197457c0d5d5cba3e220830fb99fa579002d982d570a8735c2eeb6ed5832c696750f4fa826010c3f8884ac1a46c808190d14e10d10eb7a8af43de7' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '98583807830140083736416774169197805374333098226401877256840245391472432637346446543395217225254337218664012930050849759243719057707539490237207026522' + ssz: '0x5a1b502ebe7fd5cbc1fe9cd35c5b6a7e2b1df4fe5edca8a75ddf11e3822d2b4d471bffa2234a9982cd75f926e94dfa2837f6ac97523b0512118c0fad5b7b' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '92707658340718799162754001854137238543516939578100575652576282221705140599271230821050767918413308324333194365145312580010707559670345373129381698179' + ssz: '0x83dadaed66e640800646a5afac4cc5b5d66564298c57d075f073ba097ac5fb1edad7bbce08085c84af77335acabf69c0a0b9f755c14e736d7c3c85590174' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '74293755296208201697672135615748571510821142082680496888814805623776538631438017122657707439361011875443922958437883036002814014189737748611466189790' + ssz: '0xdedb8e8fb7bb17b82b8e8a4ca989f0dd1204b3e698cdb3e9e61e4b1a86c8229d2b03fdc9649a195f757ca50a3894bde8dc17c0c685dafb95aa6471c3f65c' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '42724748555787501082144179532637671412782900992539413758464884323267459090673863948204661983391591179366026700270556892894469527368891604090404675300' + ssz: '0xe41efb50a124366e78b1b86ddc925d7a47a6c6307af2df2887a2ef7a768f060daa44e4c6cb5f2431e2ebea0ad51fd67ecca9f9d8c7765400ca83d4287635' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '154583248036438390517604284230716284868581384983332469373203394640206777690203138031409474801902640981271526900965681829174005866538680573921517177114' + ssz: '0x1a09d529cefff384bce33a36815c4aae17c69fbd16cbb21c7f50bdafc8f1141f60ea0ad92d589b6d7a19633071794187cfeb7be7bef17f05496b46296ec1' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '43069282347078261932658448546005549266888730458828445446653613148980681209038476687579970019643982782196527242819615478848171467457776340501601685927' + ssz: '0xa7911b2952627c1ee092c06b02feb5dc03eedc550a3f67836a6785c2247ab0397eadf2acd7200375fe64450fde3c791c9e001b1cacabfa3299676f86e435' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '61239447140501560559568031085344016814621494220202567689455820528615104462706190982853299717804839549228858732582858841182178051944570001996190001160' + ssz: '0x0828cb64a75d73796cbb1061a3e6790f16e5d3963cee9e2ec99ef09b8cf485ca6e59e9044b70134873e930194447a4d22dd22e0c863caa6da2b4ad08a14c' + tags: + - atomic + - uint + - random +- type: uint496 + valid: true + value: '112277454660197498060733520259851955856213874935591380356398822859775137733446948441068473558011201814988628102400680752051410131207326812492009133342' + ssz: '0x1e55193622fd86e9fbb40de90fd83a4e57639b137c9e6aaa66f37b31eac80a059d7ca293ecf72d734d43ed60a94fe86f85d16faac4ea2779260000357e8c' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '5056907309888320541161815051790306774311625192505776597574984312962064700149114942032106078409202083025036230097613740448507193542866612456855455986967' + ssz: '0x17f5bc4d5bd135f84e3af3340c1618222ee3f5f00c6dca1bce678cafff44483e89413aecd89cbfe8a58fa3a36887e9355ca94a4fe0b1b540164041c8b7b718' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '21042663561824662907439863652943367536165454361227350243723294067906748831180843949364446430411035615231220267815497384645056770973369755976079517873858' + ssz: '0xc2f69edd1480621bcfaad6d030f0f325c17a4b8b8ca21ffbadb0cd7f5d142ce2278bcbd1733a5b4360c4e2b48a747b2244236d15ca9d821c955b58c2b9da66' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '37970130004697840636168102047147344344965799417923432677013653413865330421018278457881008275837068147559371248744648078028415696444816652118647055357458' + ssz: '0x129664d13c1a659efb8e4c81f8f4973fbd43dd383f12a521bdcae373a1928932274a3b7fce3c80df6f974ed39259999fe5f0e17ecf084e1aaf4c5cdd1898b9' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '40874613696515365148716271461247932926896313675076421717941775023457279241892706142151987988710094882907879115076033339986649985394503582973858745783528' + ssz: '0xe8949d6c6a0b688ba9c2772d5c8359002e56ec680c0912a5812fa0cca11630921e7b0c9c3532b920866ac7e9e712a09737fd92b5dcae9c210b4c56b27bcac7' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '30354104768280132924093255160372981196521082872129827955524726394419053838597189907332671323192665866803620188124783928453933041650325553568750549854088' + ssz: '0x88e77bd40e6212ca67f9bd9bda3da77603251c0602ff2d88260320d49aff7aac2faba1f93dad9f9b834dc4bb1e58ca7c1caf71ba349658d6e0ed7667265e94' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '28077175127124308678119511756497846614106656294806232232843543790632539151716475544645338153291086144668863756674565404427528096670779197643383587161792' + ssz: '0xc046f7dab23f9f9c07a5a306566f163d5cff1e5b3ff1b35940602dd4a9b4425206e0b02bab746d6be8edb330980e2065aefc7e0d181b5ace43c47907063d89' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '30618930765723730149522908761683872819434963136264791261235711277837009210987811748318013991497422347919895928654721964552171582610563222600246935084678' + ssz: '0x86dea65d11eb94935ad23b4c25c478fa339505e523c477cb7697b8900d97554167c8bf3b50d76ab36d5b9b4ed70a1255ebf94b86062221d00cb513fd86a995' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '14933412844657125324483197859541509614180769461727386014505154243757808743022307058224926306256690056842436966222763777055669237807380208196331619725877' + ssz: '0x35b28b3d69dcfdf5e01eff3f4719dff6e4e2bf97a6230a3a0e5492ad4a3ddc08ed9495489508171c9d3cd66243463f56c92544f7a800906a0fde755835fe48' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '8494331617577107332723953462470964595188709870770205104337501379022997913356223412681967596161931317955400706143943274997555810254449195226131467214764' + ssz: '0xac1f1ef4e6e34e547a0b704210bcf798f54041214f2265bb9c66d3b4c569224c51434009fa2be3f57c150632f0d21c868596d94af76ae9425c5ae23cf98429' + tags: + - atomic + - uint + - random +- type: uint504 + valid: true + value: '38025445379213196192441073760724476757579482537048976383029657271979426909438610100300717108728023396846821482030981442243685594329410646464875931416654' + ssz: '0x4eb87075ad5d021d5262cef38a2f19886ab8af7cb1525bbf96fb2a52fc6dfedef7e8212ea1414b4e1f24d8800821a91a3e5bdd00054d1334f3ea8b3850ddb9' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '9128966724462148518234911578146712917885254463606709989283820697984291209122779459914313261910141263733600212783359304909160449079766870350194738827336267' + ssz: '0x4b9a9b096f2a8cfd1e65fea7780e327f2e508398cc71d3e26c81ac4fecba97dcb00cfc8d201edde048fd173d9da6bbadf0f475b78405fbef70abb3e2b8754dae' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '2766493950336444940710198980720847972398247314814001557983040377911846407275289453022892808844897125103573580120474388753772450362650204185003538705554409' + ssz: '0xe91bac1e7622e9cc6bdaca359a1aced547087b38a4804a27223dab27af3a9947dcc11084e63c1e7add0e5a4eccec67729af7864befc051318b0cdb573b57d234' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '4115497952546647476925661252772119087826261280445661968791027020780012609088575278269127153744344466291693363215646759538448493614234729178659813481683159' + ssz: '0xd7983a763b366d7a101b4dc963fc68e3e522d129ca201583e629fa385ec945c3f43f326ea281a063d838f24619cbc7fd6df0c937b75a2459637c10a68c22944e' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '9980292414604113787835342279115433183869356064133943161011616742251271867484413736390613023110859809498132705823235131692389778905240671729564373841263480' + ssz: '0x78bbb2ad25ebe421b69011b38bb9b76eb544756032d9ec7248b0ae6806cb79baf9fe0236b6f2aae42094769d53f6080d47326a4120f9b3915b54a78534a78ebe' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '2359155039914936175730764276861405682146165312860612480423599749208228272468929866423237102526476077993123511550869260701553361110369890721289717709028546' + ssz: '0xc23c78a81bb24a7b64919b93fa8770ddc3800a0c42c89b699202379fb753ee98f587baef83f6952ce36e1c07f87ce903cf30d298666a844011798be4434f0b2d' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '10071369062717600164754620904004132800619221282325932350295267058726514987118905090611714500666886435230489613485002281471395048914802470526934749916800920' + ssz: '0x98a771d1508526082cfad345a6c11655d55c5ff7dc27b8057ac15db59ce79a4cdb05ead8126c426429cf441a3ce81061898329685db3b7bc98d8a95497d34bc0' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '194916717751881780418206535424259636474087919265866157859073744525550156034340900097028049128885941733289809476824148046775698382732355556278649446538370' + ssz: '0x821c913f40872fa7e886128032c048579709d4c43532e5ad3fae0a69def06bee0e589592b57edb559f25bdc4c1174f11639930e012d5ff5c8e23247eaabbb803' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '5291662429160726864623853923064738605475161405731312661826007366085264849741156990967632894508842548406027420568664280371426629180289490610520820067973419' + ssz: '0x2bb929f4399b5bc1eb351f3c51b20a97244ca00b64198afa7bbb59d89ae8b58387efffaa31c6e53125ff5b8b4e251b7d9edf19d6399a775f72f7922c6f1b0965' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '6163617280699666745812376347703701577172141970886977214416727712934915022377539657382096100283043276169738730392227844543672055220386490836722703347482019' + ssz: '0xa3fd2fdbbf217ebb44f4ba45aa62ea5037a402162c3ffb18fb2104c4fcc08a2628f5c7a47267b4d5cd3afd39f3a8b77e5ed18888ad140d2e34c10a0f3a22af75' + tags: + - atomic + - uint + - random +- type: uint512 + valid: true + value: '8580164595911285878194311207791930585109680382258760154696139588823485283878156291631618476199413075350727786008847908978387989012980548631310633718461755' + ssz: '0x3b354754ba69a090d660ff5534fbb352269adc15465a734d9296afa25597ac6723813ae3c103e9129fa398b06ba9cac7fb57707d94c314ebb289359e8ef8d2a3' + tags: + - atomic + - uint + - random diff --git a/eth2/utils/ssz/src/test_vectors/uint_wrong_length.yaml b/eth2/utils/ssz/src/test_vectors/uint_wrong_length.yaml new file mode 100644 index 000000000..30c062704 --- /dev/null +++ b/eth2/utils/ssz/src/test_vectors/uint_wrong_length.yaml @@ -0,0 +1,6640 @@ +title: UInt Wrong Length +summary: Serialized integers that are too short or too long +fork: phase0-0.2.0 +test_cases: +- type: uint8 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint8 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint8 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint8 + valid: false + ssz: '0xb3dc' + tags: + - atomic + - uint + - wrong_length +- type: uint8 + valid: false + ssz: '0x303d' + tags: + - atomic + - uint + - wrong_length +- type: uint8 + valid: false + ssz: '0x084e' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0xbb' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0x7b' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0x0c' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0x28349d' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0xdac494' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0xa4f41e' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0x788ba9d3' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0xa71c2a27' + tags: + - atomic + - uint + - wrong_length +- type: uint16 + valid: false + ssz: '0x14a0441a' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0x9a' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0x87' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0x72' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0xa56d' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0x6946' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0xe5c1' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0x4f2987c0' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0xa7a896de' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0xa96308d8' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0x4aa125437641' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0xf79f17e3e14b' + tags: + - atomic + - uint + - wrong_length +- type: uint24 + valid: false + ssz: '0xc62b79ead5a7' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0x7216' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0x0a8c' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0xcd49' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0x7075d4' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0x594a19' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0x7b3102' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0x7a3a201562' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0x7e4e6facd0' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0xd129bd2da1' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0xc63ea61a26189698' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0x125637bfb49157e8' + tags: + - atomic + - uint + - wrong_length +- type: uint32 + valid: false + ssz: '0xda617c2f3ed451fe' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0xe85b' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x0030' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x08f6' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x4e69a81a' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x2b824185' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0xa9d93cc8' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x029199d4a2fd' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x9d1b08fc413e' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x106b80743d72' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x6197dd96ecf4d66d6802' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x6ebb559d6f11ded1ad6d' + tags: + - atomic + - uint + - wrong_length +- type: uint40 + valid: false + ssz: '0x42962c421ea919422238' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0x38183c' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0x4bc19c' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0x0fe134' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0x6106775404' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0xe087945cc9' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0xa135553d4a' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0xf24f0511986f3c' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0x8584e6f8718adf' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0xe99ae370d636d6' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0xc8663eba7c0a230ad0b66668' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0xa8df3717fbdd9c8bc78ec44f' + tags: + - atomic + - uint + - wrong_length +- type: uint48 + valid: false + ssz: '0x4008235815a2baefdf67cd1f' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0xb6c4ea' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0xce8138' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0x589257' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0xcf8347299fde' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0x9bde01fe6891' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0x67069d31d0b9' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0xc3bbc36ba0041e34' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0xd538d4ac70aeabb2' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0xbd4ba0ad2b82af8c' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0x904dd3ca71357589e54291468d18' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0x047ab9aa3be71e8c4ef96e74aa2e' + tags: + - atomic + - uint + - wrong_length +- type: uint56 + valid: false + ssz: '0x3686fbef9cd7ba5e2e3c40ce8b2b' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0x9455f2d4' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0x7dbf8c8a' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0xa859846f' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0x3295c5ccadee30' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0x237c54ea60b888' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0x124503bce3929f' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0xa85b0797530de1e33d' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0xdff22a12eedf738d41' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0xf4e42cb4d49efef2e6' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0xa09e2a3a36267ed9e122ee0b5b48d2a9' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0x55ab507cf6c85631bb51e9314daa133a' + tags: + - atomic + - uint + - wrong_length +- type: uint64 + valid: false + ssz: '0x999f8c596ac9f10a89cc3998bdc39397' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x28e57394' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0xf20a7a09' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x380babd8' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x49981434329def9d' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x47db82b984d6d79f' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0xf7df795be8924431' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x5d4280908d36a2390264' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x21a21788f8da3d578363' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x76a05c131a00643019fd' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x2e9c64b6da517b55e8c4671bdafc4cd02758' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0x56a152d2b8d8d59469cfd0d572eb2b05f312' + tags: + - atomic + - uint + - wrong_length +- type: uint72 + valid: false + ssz: '0xa6aca6f790241f22975e8b7c2c3061119bdf' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0x832b100942' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0x772bd943b3' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0x276975f22e' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0x72ed50eabf7f47399c' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0xf81ece6fdde840c514' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0x017ebb0f432d367054' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0xc6be6924d1654977f0d299' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0xb4508d98cbbf7a7c65d346' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0xcf90695615a2ae119460f9' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0x4517546bbdebd874415cf6490a14ce431f67c36c' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0xf401ce3f85ed19a1f71bf84645b4e9a71f2a6500' + tags: + - atomic + - uint + - wrong_length +- type: uint80 + valid: false + ssz: '0x2ad38b6a3bac78abf4c86276c824f8f808e06400' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x64749e552e' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0xf8c9c8580e' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x1f2732fd30' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x2468c8a48c1cf3a732ae' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x840a8a1e11ceb202f1b3' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x5f7d5e548ce0eb466e8a' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x5f3f71472a8ae6f0b0044964' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0xb37e1609835f12e085b736c0' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x8aa5cdaec0b4a2629bfa6418' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x168eb650f29bc47d0c4c8b58cf9b8709b137bbafa772' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0x79810955a16a87b07dc8b0c1a4a9dfcf9577368e2bae' + tags: + - atomic + - uint + - wrong_length +- type: uint88 + valid: false + ssz: '0xeb4bf92a836c533c89a608ae004eb8f6347cc676871a' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0x02b089a30f00' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0xc67bebf79540' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0xc50d6f74d821' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0x2f9f24ac43db3a396c3459' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0x6266bc287f8c64628c286c' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0xf57924b1009c586b09efb0' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0x73cd47bb52fd266affb9f1d582' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0x5901fa87142410b0f7dff93f67' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0x19bdc785b0ad47a84c3eb62e8a' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0xb3cc35a048c79081b7531c3863f22fa07182e256db68e85f' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0xf842f2f6b8106b5421a0c1fecbce12a24951865356ec33b3' + tags: + - atomic + - uint + - wrong_length +- type: uint96 + valid: false + ssz: '0x72cea446e337cbc095aae2a3c5e93640fef7e25a6d5839b2' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0x415de27172d0' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0xf05c16889530' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0x0afb8dda1480' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0xf415f2f6acf3d88d13242c74' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0x606e8ca159cf747c2d0bbb06' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0x5c9dcdf31e4aba3f9c4ac4d7' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0xf9f0a5567fb0a257d0c3aaa7d049' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0xe2289bc4640ce0719c050495001f' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0x7ba9b9b32b8f0b451e23aa27894a' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0xb07d03dfaedbcbc4ec3b02e2853ab725fbabcac133005bd2cfb0' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0x111d51b55bea94f7a09833ba58fc12eadd89bd6303be7e3b69c4' + tags: + - atomic + - uint + - wrong_length +- type: uint104 + valid: false + ssz: '0x9d570fd6beea5bd0976389b0a0c0d639c169126afbac747ffbf4' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0x7f38444c8aa241' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0x15c054c0ed1483' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0xefbc9cc7dd21d6' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0xf09b7f09d596e5f7c5a9b341b0' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0x9deb49689d2bea47803b54b8f4' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0x145ed6668904b300a3a832622e' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0xc315c6937d4032b16b60d352df098c' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0x802b01e7978dbb14d6101564004a2c' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0x67cad0a137337ba12a5b5b78f82fdd' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0x76ab8ac3e33700d129b0961d18be5d327eb711a97872a22d291c32a4' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0xffc7cefeafb71743e52fae45d3af10e3d058b6eeee7ab50670267e2d' + tags: + - atomic + - uint + - wrong_length +- type: uint112 + valid: false + ssz: '0x5bd5e17b9a3702fc1d084f1af54463de4b1468540b6a224e0265cdf4' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0x04eccc8a0be059' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0xf8652563ed0fa6' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0xc53ccb5dc5d89f' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0x5ad3883dd42cb304f697c7e2fdb6' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0xf47d0db9757e9d81dcdf8e90400c' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0x7b45fe68fdff1cf116093374277b' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0x4dd99b486d84eb968f4b8273d5697d14' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0x458cb87187700926fc896f0fb6c1d6e1' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0xbfdb858f94ad940101bb3fc0b5fff5bb' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0x4f5009ca7d3647669a8cee84739a1f4975b4ab66f73bfe8167c9d116de1f' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0xc224ed6aa70b48e2ebd712424c71fb2517230e01a621b9176ef024669e9d' + tags: + - atomic + - uint + - wrong_length +- type: uint120 + valid: false + ssz: '0x0f71f85b79b01b1fe7a2c01716085e247bf97a1e70e205401656e779f230' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0xa3dce37a7e2288c0' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0xf7c85c939586026c' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0x7376ef032dcba522' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0xfe05bbe6fd198c8b675881812d36d0' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0xc120b28787dbe4e5d1d1d581344cd6' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0x09a25dcc9912a5060f067ebb672669' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0x156e5fb18ed634fc4dd903b75af4aa0300' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0x886b5ac9f2fb6772bcf7b9dc97df8091fa' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0x30180289c7c9621dc00ba6fe7eb9a91f11' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0x71e1d1fe8d902c09822e3679a57554fbd33cb4182f4e3f37c4f8c559a3fd0c62' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0x9ea87a56c5978935c7b02987bf6adcb12f01f40d7c25953981dd1a8136c06bbf' + tags: + - atomic + - uint + - wrong_length +- type: uint128 + valid: false + ssz: '0x6b4dea23c03e5c39e56b59a0500299dfd4176225fd5b75ebec06c939866dc560' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0x2d333dce6a9f073b' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0xb9700fc713463546' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0x26e4bc6e548929d5' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0xa494a03a7a61cfd148277a7295de93d1' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0x191fc9c88f0dce3403390a921609c449' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0xf9302e19d1697e780025306f6be1bead' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0xb205dec7c2f7d5a74d036f6bcdcb42fa8816' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0xd5a66008d4a55b3b7ba2caa3a25d637fc037' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0xc57e99045d9ab9a5acd1e25db22b7ebbb966' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0x13a730bf800c2b8d45e18d962527473d217d1c42ac31264759b34485f28e7d01966d' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0xb264c3fca782064a87759b99477ea64d2c36ffac2b779652148d070d289d84a2dad6' + tags: + - atomic + - uint + - wrong_length +- type: uint136 + valid: false + ssz: '0x453ad4e6b79af334e3da39df359ce48755c843d06146522f7563bb9897ebfb15af8e' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0x96dcff0a90da096328' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0x7b92730bd42b722a86' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0x32c3c13ee42c078953' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0xb7fe786c95b4624d4bfe6cfc5e4ea78c07' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0x4f8527e07bd97ae51dbc36da8e21ffb360' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0x2c5e230fde3faea53a50a9993945afd35f' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0x4a15ad9c667f92e002813e066a5ed00c42e7cf' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0xe2eba3e0f72d8a21db64282ab32bc4c9d560af' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0xfc15a1449c9604421c558ca5ce80ce7564a9f6' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0xa55a0f8a4b8b72cf3ed7ebe1d0d32d046c9e0275435cc15766d9145b0810448d8e89d165' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0x272a0b996f09a620a57524e4f7f5e0ed793718131cd9d1f5690ca502df6afd2e358ed041' + tags: + - atomic + - uint + - wrong_length +- type: uint144 + valid: false + ssz: '0x91610f5cdd70bf1c49cbe9c933c4991e8b7548c258a4701fbbcdd30e7925be53fa3232f6' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0xb9f00a525be069ff43' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0xda981fee5460f82443' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0xc53772d1fc999a3e24' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0xe0d9c26147b326098574a12b4a70d01b9003' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0x25d922c216223a6220d413cea2c702fb9abf' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0xf11c800197907f5a9870306177e5d43b0342' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0x57315ec664e1f46477219b441cd98c958af1cb82' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0xacc12631f22241abbb23d38dcc5c9d9b1d9c4df3' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0x62de156a948d24e7528d2aa41d545adaafab0527' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0x4bbbb4da0cb920b3af4aeb37e543e4c1f69ef86cd8a10cf9d14b96a06d386441d314fbad89a9' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0xf736010fbe8ed776c67022328b08ca95bfcf5eb8c03fd9aa84ab305be37a6132e554015eb61c' + tags: + - atomic + - uint + - wrong_length +- type: uint152 + valid: false + ssz: '0x9c78522aa7f529a60f14a53a34d4f5c2b28d127b8a6400fd020e02265ab9ebfd30ce51ec5fbc' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0xee5321ec0eeec4281aec' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0x2a394ee150113f16ddbf' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0xaf3ebed4fe341e623f5a' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0xea05fcd5450847ce383f757e0c3a2a14a761ba' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0x3aa141a27219fa3343a7f44e5bf9b14516578e' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0xb1ad7d88d393a208f3964d846308fa9df30433' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0xbd7e7ac763c5315a8233905644e9d3c4d476292fdb' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0xa39dffd4d2b1cef1cb7f103b90a41ba09ba7fa2740' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0x1135c97f0197769f33c5d68d200773930b24884e73' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0x687992202a71ed220bfb42b5d9c3aaed450364de6f258e3b9aefc563c27f34d01b20a3ab9d54410e' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0x7b2e96127558dfd5aa3cf226c1f1183756f2d2866fd49f572b32e908945340c54d7739c64c6353f9' + tags: + - atomic + - uint + - wrong_length +- type: uint160 + valid: false + ssz: '0xbf3508c50dd08982a72d6ab422b1107fcf2e21279c12c60ecad232b16dfd591223604689e0755ec9' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0xf43d8a89d423c2be3032' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x4a9570e26268ff606764' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x88dd817982f546f97e0e' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0xa926f6cf5def1011e1717277cf027bf16ec4b4fa' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x2a12fe7e3c66ef41983a1fa9148f4622a0c2ee93' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x2534f2b76d0a32c161aadbe9ae88cbf728dd8262' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x61414ebbf9b7e8819918e2a7b47cb708446f24b3da57' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x6229c7a684b15dc5004c3016f00a7473ecafb5deb0a7' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x75228f9e430168ae91eb46523f2c4ec5d0c815ea99c2' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x375b68b5ce4192bfd6db85ad08d11193e8d478433b7dcb4284f361889e6a73b978179a9ffb97cbd6b53f' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x0041b0302f6f89ddfa13d107be2fea9162aaedcbfd0782bb3ff4a69466712061ac840470f2d3dfac44fd' + tags: + - atomic + - uint + - wrong_length +- type: uint168 + valid: false + ssz: '0x47268164b3a6902bd22cd077815345785f307791831333d191a63521cb26540af7705edbd892c7dff92a' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x4691223be6e191eba67881' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x57f304df3455740afef2bd' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0xb3eba38e7115a92f53e2a1' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x45dfe82940f14b23db8eee19a8d415908c04468149' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x92e5e1fe9906fc3e43583b197fd21365c264276d93' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x6acf482a3ddd799f0532ebfdb4d21d16613d174cb8' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0xad630e6b8a4a344cb53c0f05288c8bdff4a049bf346c6a' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x5f4095484b931e616d58c3869870114e4465c10dea2fda' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x3816bdd47b3e31ee424cdce98b1fa9cfab60b5b1d2f26a' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0xe9bccccb604aca7079649d071edbef34af17936b60732d8c08271e469fcb33dd76ef17589a5f82780fbfe70f' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x3a1ea830bfffc7c7828bc36504fd45c988998e44c5231ebff1957035e6564a53b2ac0cfdf561265b70d64cfc' + tags: + - atomic + - uint + - wrong_length +- type: uint176 + valid: false + ssz: '0x0fcc536e25ca1d0c56f79c95f63c080c64b11c5ce625a4a3b7af8bbce168df10abbbd5306442f6e69ab55912' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0x7692ac29e945db2e622258' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0x2489c86a2aa73f04534e07' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0x414e5f955f6e145ba7a7d3' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0x5aa2954ac8e93c5a8450bce19c7a16e5c7049d602e7d' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0xb3775d862eac572a3126236ecc7fb83629a9a8d9c675' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0xee1623270fe1b03d913a264a607214f93c6666e87d4a' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0x6f7e63586a287850ef3b9debb64b5d558084979b744b5c09' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0x1de757fc403fa9bddf612a896251fc24eeee9710cab60e8e' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0x71672a794fc4e63e27c29b85fddefb5875f31c31a2563edc' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0x24f44fcb5a1a775c28d15a55a98cb5dd779358d82f7d5a67a1950ad26a93a6f05f7f0a29db1d8ca7120af4c9cd70' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0xd1bd48d49abbbb24bf5225b975c217366f4ac0536d38fb7a60c85d03c11c0c31f059ed0a5f84f2896cb4d5242d2a' + tags: + - atomic + - uint + - wrong_length +- type: uint184 + valid: false + ssz: '0xdabe741d22e2c6f09b985a41114c519716a7c9d8531253dd22a9f2ae524902f95c7800a264ff9162206a876a4001' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0x8530f5dda7640a858d3799cb' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0x03c829567e754fa1c376cedb' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0xa3b47e9195be530e20c9e771' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0x78ad3d4cbb59b977cf7d7bff15db1dae1fbe3388010495' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0xe5e96a1cbfc8c3333bd82f754ac36f0988264690895312' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0x27c27d236bc4e30a0fc2866d20358233ecdda76ac3a811' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0xdc02d9051b0475926c089e3872d97d9bbcfdcab8060e248990' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0xde52e4d1cc99870b87bb5ca9abecb5e4dd5dfab1975f61f758' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0xd60802f2517c7ae6f1cb43d02109b882a952d9a87f2be10f31' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0xbc16a2ce35552ed6da38d9c25eca27d9a6d64ba273c4ce663060a201fac1d6c8f9de41e7a68853765a26c35cf258689c' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0xc74e53185367392396b0ef5829e168d8cec041c2355f74fadfc70f8050d1f65a3a81e0d99b4796cdc50f911281771eef' + tags: + - atomic + - uint + - wrong_length +- type: uint192 + valid: false + ssz: '0x2eba16517078dca384127c9e217da35fcea1258499a42da60f95efef31e6f2180847d25a39017acad303b1c248f41f6d' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0xc28c5cdaf510edfc2e0cb352' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0xaaa9edbc41ccd44b1cd0a31d' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0xf4e748344ecf3bb37106be0c' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0x35bbb417d88bbadd323051b1b1d63adc3b259a57c74dd375' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0x93593e9b10cfdb387551b22a4878fcaae391e793e70a072c' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0xf88893de2fba7b72cd92ddb1ac1ee4e35da47f86a7cbb581' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0x86f1f5add63608099f756f4a5b30f8afd2bcb5bef2eb9bbc11d4' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0x0c14a66f43d3c94eca9b4e46604c63cc07368cf2d1937a514915' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0xbfbf9e822106a039111d6c4172cd2a8a4ad0136c56f40048afab' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0xdfa9e9a6aa066179c45742ca1218cf81ec7919d2d2e31dc66cd0d60afb7042282523b62315285e9f49f27b6974a5b92681fe' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0x393e3fc87e9e5e8ef2db6bfde1c3014aba8f337109805d9c5864b790132ae91d072c0670430db657023cbe3c42ab77150e98' + tags: + - atomic + - uint + - wrong_length +- type: uint200 + valid: false + ssz: '0xfbf21d14d9b8d1592a676ffc593933e0490b4e65819f71f2a5904f24c705fb771e14ca2ffcacecbfa269150a6ba9a074eead' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0xa9504d4dab6ec1b3dabbbdab00' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x0514c1c4537b7897683c05f2ed' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x87ca86d1dfdab32f1787872fd8' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0xe9b296dc7f22f12a9ffe5455a196ab9f6174cd4d7738022329' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x285bfc861740d4422a9b84f7672b3ac131894b67d17d6b36ec' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x696b24cad62dbb21c80c5341290bc1fed5a34c662fc7f1a8c0' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x3d9ab909503f0987a43f7a33eff0fb77027d92af73aacc3f6656d0' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x21d1e80e47035e3be9a2e3830b73d3aa9480ef7cdfde86c3a96234' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x76ee4d15737bd76dd42105d4cff354dc495f5a2a371989611d9517' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x8b09955d9fde86039376ec54ec13c3f9388fa911f09a0e5e3869eb62419ed01b598cfd16fad8990d837eba5bc659e1aebab9b8ba' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0xa54d2000c90ce177dfc495ca7ca5ef0aed9b3106e1c9a3880acc3dc8b601e2a929038a28f80d7077b9e11b061986c1d3cf6b9c09' + tags: + - atomic + - uint + - wrong_length +- type: uint208 + valid: false + ssz: '0x7050edb5f669ccac306a1f1de67533ab5548fa81b8063a78eedeefe217c43ee522a7d1455b57b0de6930d19ad76b0e7a300db5ec' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x60a70587424b921f688e1a9084' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x272ac0d2ffbc8e34539d0450cb' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x79d955d54d3ce2b49b57071fce' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0xd0a784e1b73aafc56764bc02beb0657eb04cc22dcdf860cbfed1' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x8d145ad338d4715acabbfe0e54f9b425a571139514dc86b821a7' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x2e13c62fcee76cb80dc9e4c46412781c9592c2ecaad3c33ad2e8' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x95f06b038ccf6bdb21a0cff405c8e77705557b6bfa96f17c306275be' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x6eeaba9f402e9a8693cc38f7eed8bb24cd853e85168c332373e643c4' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x67bfef85b144f955934d0b8ec14213c6c80963abb3c7c4a48b72fba5' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x99a15d07028256113cc25a55f93a93618946b76a42761e70c21d86e4f6a1bef5f3369d3280173b1f1821eda7f5aff194e2a708d5ca18' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0x45f568948261f7b7b2fad45e32d0f0206683d16b3cdf73eb7382099bd0c5b09f017785cc6e23b70045e0a601291d8bc4e0c2e04f3b07' + tags: + - atomic + - uint + - wrong_length +- type: uint216 + valid: false + ssz: '0xd5ac6b88b8a4e25c19e99872a56bf5a4f715affbb4809ae3a5352f4581f18b2d265c65a95b6e83c3622f84ef11a55848e9677ed30b5d' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0x518039088ec10d04115f72641f83' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0xf8d30938b67f50782720e5bd16bf' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0x51d84f6760f69eff08fec696d664' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0x9428c69a091a3408314b0b975a187249e91dbb9ced7eb5c5a7f425' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0x7a26e915618532c9b3cf95bf35102d71fe03d669758db716a73d0e' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0xb7556da79f107e7eff39ee8ea7817d11eaa9d6ed54f8357aabaabe' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0xd7ad229946bb78fd478f2a4aa62f8d1507ed261db312d3880ff1752a07' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0x62acbf524ac312e53ceaa61e579056607dcf4b65afee1756bed2383fd6' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0xbcefa732b710e9bd9745923cd3352e5937655c7fd0999c01e91f65e9ec' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0x0f2d46bcd48f511ca0a49b4f9554b05074fa0fe65581ce0fd12556c82f3a65d4864a8eff5acc6796cc650d20eeba6bcbde102fbf676dbeef' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0x72fc2562bfbbc5e07b4c32c5db9fb5e2758ababb6928b641258367351bd7b3d758548a0b7cf305cf2c7870c6ed7e56b64e48aa57c4b0b2a0' + tags: + - atomic + - uint + - wrong_length +- type: uint224 + valid: false + ssz: '0xca50e1c741eaac5f1813e585783f05f3fd747a42619119c619e9d2782cb1a37f62ea2a351c55a3f7dcec4823998de14d45ad92c6f4a2e5e6' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x58e4d537d0470b6468487eebbe5e' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x74d1c4a560d03062bc81c4016818' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0xf3ac9db14ddd8bd2545dd11cee75' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x9e99426938cc6624d98f7098c35e08f0d82de65248dfd0030492aba1' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0xa12f7d84b2825156744a94ffd2e44e1abd18ab33680e4f991d7e023f' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x1f5005f85947979860b130b114ac2c0aa89783f55a5c87e53626ecb4' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x94469aad2b9ab7acc41a5553c016911cd6aa6bdd856a54ec7ca1d5180074' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0xd2f17ead7ca8859bc09f4f3bd908c89d31227a53a8bd00dfe83952e91474' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x7b53f9bd298e5df2353be348bfa0c43d40b4f27cd0e317115bd655d254cf' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x208d744a6be95dfe72146a118b1419ba63e46b39b49067795631d3b5eb9e954b1e0420d8bee81cd795cb5760e611354290fdb2e49b2470c0c3a9' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x8ac946d0eac9937d9f64125409b7c24d6ecc60073631643d1ed38647474276b6f0e5b4e7be479178be06f16e58ce3213263492aeb229d03055fd' + tags: + - atomic + - uint + - wrong_length +- type: uint232 + valid: false + ssz: '0x896abf3edf1139e4fd56d72f89960854aaab8bfa65e564ff24258f7df6b17f2fa6f646ab61fd47ad6d386dc1e94af185050e69487ca67661e394' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0xf2d67a9c79c02a5123c6af29040f47' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0xc293d764e5372e533bb77c9cb46313' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0xc75690e953d5862b96414256c516d7' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0x9e30cea10d935d1107b295fdf60b28951a8ffae1577e06ff18afe34f3c' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0x345bd4461ad1d17e55ba5d2a1f424995755f80600201db36ad68691e0b' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0x903fa6b62f66a67d818ca0ee0595bcb37c18d41b4096f5059d273b78fc' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0x1918c061a0d6f9c03fe548350f8b0dfb31b732401d69125a23f0cee95ea668' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0x6be1e26807020d7ac20a40105e94ba771df7acec79a9a18ab8493208e018a8' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0x3d69415d303bb691468d8110b0c2eda04e5948d8647d2d46f28a2e5d0c4d9f' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0xfe7b5ebf1a78dffc0f0437721a09b86e1bf1187d8344aa9b71e1030483e5aac0d4a780103509aef7e15e7c31204382da0739fe8f9d703c5743015137' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0x2e97efcf05447569f7dbda80780cccc149ac3b7e276abbdf455b3b29f61ba925f92fcf377133b490d79b874115d1a639a7a9cd662959b45312a120d5' + tags: + - atomic + - uint + - wrong_length +- type: uint240 + valid: false + ssz: '0x04ca4031fa6fbb9204f3c2100dc119788c82ed923a6bd13de8ac55e48c21a2f07d298f622ef40e149b6038c095fb3c905aa01f3009fc6da9d17b0b7c' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0x78f9f6a85ea67af61cab1b0ea908fd' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0xd99708242bda088b0c077015a80c86' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0xfcd1840ef88fdefdfdcfd16f9ff2b6' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0xb659b2731c3c0db04db896c6ebe5f80d3ed70cbd9caad51c199a4c8efaac' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0x68741606b549e7d56f4fccd90274d608737ca9fa3e5087f7fba694dcb140' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0xeca7a939ff404a979bcc576668d6a84d13060e03c4df7ae42f0ed754e0bd' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0x93eb82d8052da2f04ed0f93e3e6b3d08394e35137b3b392c472c619ffd59885f' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0x6508a966ecb521f3e9ba1163246cf4503ae50c0639692fca0f48be957d133da5' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0x756985c8b372723c4f96e7b7bde776baacc0074dc1edb9f0912e36b75b1cb7d6' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0xb3457d0af543dd7a8b4e18f2f319cd4ada3c1b05276743a98ee74a95a9ad6c8cb22e12cbf3eb6526f43e86ee7ed9bace8d153ea840591d277875f0f933b5' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0x32a966e62e2e3df54af0972de7438543612515139e8ef678e867bac26dda462576d99b69954b508cb73649bcd73969b9c15f5fcc834c16b80c85f1a4576c' + tags: + - atomic + - uint + - wrong_length +- type: uint248 + valid: false + ssz: '0x221f600cffb6c9f7212d35783179d06d61ec6104755c06c3531bb5dc23b9d907d1d0b3a5abd9beb7dcae3f3ed72a793f9c27818d61e8468f05f49c30359a' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0x2f62847ca5956834e6f0b942d437c6d2' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0x351f7be0a692cff70f081079bda87c4e' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0xeff1018d1b0c984628dcd5a8cf677d87' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0x2a8fdd52435a558088a6cd9c5d36aeef6143ecf07f92211fa2a3760e5df3a7' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0xe77db02c943695344e04fb51f9e67e567a59ce0a457eebc4bcfd20aa346bee' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0x3b09e8004bfc682443db0958d0b6bfaf1d7f8a4c9e519797e10c0dafd11e62' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0xad70a58a242f4aa655b1440988aba54528a0349e142cf90fb8338fccba50344c96' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0x8909b9a8fbac5973ea61bc0d243a20c276fc2ecefb7500ca58bdab619b132ba3f6' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0x15558323c4f34c89c54a185c8d41cc067be32a1f6a57bc54610cf2ecbfb0f021de' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0xfce4efce47c8dc11c78a1297681d9e9abfad627e4b88d72022ce5ee38712a305ef1f05b1bd1b804384338b87a5c2e149a875499b1b648ad08610a872eb2ee73f' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0xaa6b4a22ae178f10220366673540291ef20536d5ede22acc77e216efa79be11bbaf3f5746c2a988a14af2cabfb51537517cb5c86b5607029656949424f426bc7' + tags: + - atomic + - uint + - wrong_length +- type: uint256 + valid: false + ssz: '0xdb987d1ef845b233d63426a67f763113139dd2b0300b0b3e1a84b0bd8134257399871ac844349d1a3d76441de222ad3db2a31cd5278cc684df33beb2a7b9c56e' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x48dce9f8effcaa1f5e41481ee0b9d66e' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x7a9ca3984bfa90a45833853b1144834b' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x1e0e5d113615e1bf15048e88c61853c3' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x8d288625ef557bf685f8ed3bcf5da6c766b7be14f062891f321e862a93d5ca37' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x030bf80fca506c162bf077cabb8e9511ef5bbe2f6250b83dfffa3021b2863f50' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x57987915ce3ebf4958b0b5d7be0155ee60149d5b574805726a2329ebf3362ac1' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0xda5e4a63c46b04e8e8c1b5c42d601fa02b33a5b7825921ba13da79da5ab1825b527f' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x0c707565e044b3cad0093824838e0c4cef96e4043046236a28131d37147516e824e3' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x82368e5045bec61002b96df9ed8f64354d2c9f99dceefa6399c4b83d77eadad5958b' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x8e76029c62a0adfe80617259d69f162e0971b8d76525c25b40678ed6f8df672919a2a607f3c8917df25071ba5c2da7aec4d5ebb90d2d23e58c65f5f89769de256fea' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0x12723eb9a78dcfa566ee4e2e666bec777f53dc29735ee92f79ac8d0f44095d251d78b6e9d0fa8f5f9cf0e0fc629f526b5b8e3fdfb4f1df35d08f5ac91f0886aa5a9e' + tags: + - atomic + - uint + - wrong_length +- type: uint264 + valid: false + ssz: '0xe8b0aad4cd2a5b4f7f399f7f21f2fd05965309fd364ccd9874f5bdcd9e141505b93d5f8a028610d7d40120d98c657d9d3925bcce1ab17692c303eda241310dc04094' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x01bc9be95e3e8c49f6980c3979dcd11bc5' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0xb220b46cb44fcef46c0bef85f27d9a9058' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x1b515652ac759f17e648af184cd867e8d2' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x61bca095c978d8a21d475930cff37906d425f89c5c28eeb0d2b6af340ee5e4162e' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x054523c188904a8ffffbe2c0b7aeb550c926f0a2f521237923b68f5764d127c207' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x63a6541f2fca16b828512a92e0063655006c9931a756b37b15cdc1323ac0371fea' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x29b675df8a170945c26ee24ca5939b1708277533db1fab37ad8eaaef0b82aaa7ae2c43' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x4d8fa043d7a134ebc04ebd64fcc86a56a8fc9e2d5f7aa3720679383305a7f0094855fe' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x3fab258e761d125a2068fb51513340370c90986f663f40a22e3cd1225154257e4c5d96' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0xb2650fa3df8e97feebe7c6222a473a781b392ed6bc35b4f4c3f26a12c9e76c9afcedbc11c771098f56c1d8b69235978e71d2bbb4edf07eff58d99526eaa94d388d4e8e53' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0xae7ee6e6823596ab0f040ff2ac1bcd07171b252f92af19a21ba07ac74fb81b8921b5e224e978ae7dd7cc8e3fa7e9bee6790fdf86e9b9cd827bf50489a0735da24ed6a060' + tags: + - atomic + - uint + - wrong_length +- type: uint272 + valid: false + ssz: '0x21e2fed3f4198b6a03129c519a414ef6b46e0c43f500007812dd21a8c721a14e4410d0db6f0b4ce77a8c0caab69a7da9ff5a2e159e6feae1420c9c5a3bd5e6de233f9c45' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x20679650168042e7677d24dc00aa018aa3' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x61fe9acec1e52e198504e67be87abc9dfe' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x71291d17ae6b1a64d7fe1829079b4943ba' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x2937a8b026276b7dde49129005e22cd808d05d74a715be34346dadfba8014a6c98ba' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x8438bd05e88727913fb8e90627da5607aaeaf4805c1244be23b3639f5f37a7534cfc' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x4d87eb91e8d75ad6ca672d2f5a0ec78278a4f35607a5ab6d09d20d086b6e1fc1f291' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x1a39fe14563feb9f14c2b3b2c28dc2ee7ef07d92d2c3573e2c071b6a9b3b7959c922966c' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x3e37d30e5cf68fa9aac9a44baf5d1ab6f391324fca72a0420151af1989c4cc9bf352e9a6' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0xf2716f5a3802b875885f8d12c5554fd1baf224dc635f93c7f3e759acc3edbc02e3adb28e' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x2c2d47b4348dae44c85f14e88e7bc360539a51ea7f2fb66261f7c0180f2079135ce8ca04295f704d88a24320573304748e7c89d4568f9386816c11fc320eb03ee513bf769c52' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0xff480661766dd744b10c326215a1c39703dded203c3a0916e57d8cf97b225e3addf0c6f03ad494851c607491a3e28ae53ed495288b1a7bbe07c0e36bb985820b24ba1cfcc00a' + tags: + - atomic + - uint + - wrong_length +- type: uint280 + valid: false + ssz: '0x2133ad0019ceb58f7305f1ac03be1f22d5325e50e3e06226f4b085d8f7a7f4a7ff10b8bce03e4dcb3774cc85eda0346cfa37846a94553b1e14ab267b3eacc379cd1b0002b301' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0xc310dd567d0e69393c17a3ae9c2dc75a0b7c' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0xd0aca1916a6dc03f98f121f5a57cbc700d7b' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0x2f0d5aa54a5aff51bf7fb54f2cbaa946816b' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0xacc6622dd7b5045fd45f1f6b117de3581fb5bf16438805f5a47bb50ef401b69069520a' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0x5e9b87515ed5ed2ccc58ade677a2c57c1ec592beed3a9a97edaa9f86b06da10cfaefb3' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0x6a50a6feffa9610b1872eec6cd3a345ea88131542505c1d9663d17bb032107693a37e8' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0xd46a68e1a3195a8d141109efaefe94198ae4b96ee8fa122a5d0029276d5aa50934792ba8cc' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0x42b4dee091b9060c1117257a35575140f3c7c64a69982b2b3e5d32d88fb01dee77e3af4f71' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0x0504d2ff51eda46950242ae5aabbc67a7fb2df1dc2022e52d1d95be76c50314edf8e3f37fc' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0xf5340edb4c5d7dc8e47240cb95a541eb785f64205519c7f99c71408fcc2d86c0f4362b0e28b4ad1bde6067030f7c18d9c373670d443dbe7ccf96220b0e3a0bcf0495927d4ba26a0b' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0x477273a89b963dc60334b169c25060898c558f8e74a89e25e40e73ef4f51beed5c14d3fa94588d5ca0b1fc376e9c9e61e51213b288c6cf603f0d513322fafb2d2b8d439b3d1e8824' + tags: + - atomic + - uint + - wrong_length +- type: uint288 + valid: false + ssz: '0x5078f77e45b10fa9e677f878ff576a05060c7e1e7fe990e86168bc9ec4e5060476cc01571a559e4526d6d8c25025fc724e18bef22fc01bc814eb24da150a8338c5ddc9d7123555df' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x2c23ea17cabf18c980634b778b1701051ba3' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x0b0fddc6e0dfc9a68c50958d6c9667ff8838' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x3b76721135a01cc8969ce590790e625700d9' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x57f8a4c2c20a178ed7036d4d14b6968a766758ce9cb3104906eb564340cbd4d75942a4d7' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x216a513d1c54d7d6a2cff8f6723504a6e353cac562eea9c36d1bc4c5d9a737c20401c94a' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x2e26dd126e4164b4e8e8c7f8ab8aab1d7f2d58c2c4f05d11355288bc0f446e911e87b4b1' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x915232e4386d5e8d30f0bcc31580473635b093f3c482c773c1670c7a3136bc736766ae488227' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x6e14d0d51210ce5e37cd7ea5cbff91f062db95740c8c1e781102b3020b31e74e8b586ade2093' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x8b8e620324c9caf8441d0c1bd85dcce28e02c65c0645e6948fa23ef5e9f58887b2841eb6b6fc' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x9f8e79f54b24813e5df4106edd8c8caec62c26b2fcf399e88c655d6ca81d6f1e320aee87f6e1dd5e7f7a908c3fe847959bc82c49c9e42dea58fc291ab7a1f9b88441a0f17783567386ea' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0xf4f52aa66b006439088ff0221a4cf25ad0aa39ae8abc0399f7cc80df2b85be1a97286304727575b49cd317cc1ea1d2471845adb40a32313664483f7b4bc0d67846aa9089f9363db4b350' + tags: + - atomic + - uint + - wrong_length +- type: uint296 + valid: false + ssz: '0x51d9556fa9e725afa0ca9d4583c30b2a0cf93fe408f4bd234585cf4193d3215f53a25ba9f5e98f2a2d533c3617ce37353e9e6bbcbaaaa56179988ebd19f45fa9b896a2ce3200ab51cbfa' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0x303a839291ad086162517f19a92a84f2ab7e5e' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0xa75a547f682a7b4fde451def735fc0406eec6c' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0xe9a56b46547c248ba4e5b482311f3e792e218c' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0xf1bdad7c28ccbd5872e96a0456670f62985a974be26770bb17b1845bd46eab9029209334a8' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0x030fed1af01b928743a56a1cdcd722688398742a4c51ef7119d53d051961b252a86eda7251' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0x669ff012f61860ccd72f2e831409db551cf2affda440f1dc072e46ab4d6df724ba02e3c5e3' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0xed64c6775a14ae38528c162c520ef66599ccf69f77cc2eaf14d1f00fa73e5b74ffb9d330025e52' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0xc86f57ef28f5fa9e7000fc813241465926f4ef939f04c267133245c0797027212baf35f3c48852' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0x28eaca8a08016f61ab10a3f06b3b5464f16383382b26185a67c467383f2c9ac9483377b4b2c2c7' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0x08215ec41959e1fa32a44c3eba65929839712f9908f8b37a0353d768b25eb0efe01e7db2235d2bd709a678a47c08ed8af696a01017628b8aa0ac226702a8661ab502dea5fa69295f24894668' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0xd6512afe88f040ded1122eed137b49f6e17acf61cb709daa5107c25476892994298b0ef5e881c7db591e75da6a941816aebb438756668b84e9a9d0d28f5bbf1d243ab764ffe9222165af2b45' + tags: + - atomic + - uint + - wrong_length +- type: uint304 + valid: false + ssz: '0x8d28eabc07106efb4d6f35e5eb5d2972e194aded25d7396332370bb2d7541fe40de7b3d1a62acf8e97f1a8fcb161dcb48f29a2684ae62f8a692ca11de29e6571b783ef63f536dca0945a458a' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0x855e288621d2bf7a2f761c2a15b2e8af6337be' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xd80aef54eee6d9b3db4155bad8147c10610640' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0x45693760f76a7a237030573ee51224bc5e8289' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xd837c933b938a5baeddd93588115ec15702f30faaff7f5cb4174eac091be534cc2741b5b8c74' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xd8c34a12aa57d661b1b8815d81371e5b3d5abca6b227e3014cf0ad7bdf50f9d7b7cca85c3d9a' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xb7603e633f6a080b82dc3efa2433d301bfefeb523f9161dae22610dfe49b779122c54e9c0b32' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xff2785850c99508fad5d061852b46409c4a484d481070a9755f89652b29af4062c9a3b8baa67183a' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xeebcca8f46f64a335b5609b27287dbbb57675382773166bbf1336d5582aa80d44db8abbd2ada103a' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xc8f0141ecb8e766cc87405b351bd630669052a21d62fe438aef8d4e9a7e8c85a657d5434330df607' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xd68ce5729bfb6049d2afb417c4748de554da96567d9762e8ec0d2b022e59f8a1066ab63e15eb641a483d532c423b97a13f478b74878b9663084c99385ab693a8ccee623a006d5cab773c46ae6eeb' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xf1f963f1a2312138c34fe23a337fe7c669d51c7e5b4fb1503bbe31a742a3977be390d007fd05b9f247c4c8dd1c3ca4229604ca2817cc5c497ec69398d38bd2f64ab6be8da2ddb67c660c29cb1d98' + tags: + - atomic + - uint + - wrong_length +- type: uint312 + valid: false + ssz: '0xf6e4e5304c84bf6f714ec2129f35d6f8c630e99e1a8a2fd196b33c0ff578a7e0bd4be0d83d57a544a0d91079d21050c7777309f8b4cf66e30cfb96f852b37e44f00354d4a257388a96fc7c4c9f3a' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0xf2a248bb3ed1112cabdf5396ac5833b9ddd24f8a' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0x0a890ed36f588ca10a0ba7d71f0a70e3431256b8' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0x6cf8754e2bb01729e49585d885956355a882f0e7' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0x7df3f17866d1927199ad3094e9542ce157f36ae60c5ec758bab761d3747296060b013dc2a1b438' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0x811944bc845222c9678199fb0ac2ff5067be385e1316608335b92fa955bb306b19fc2a40247420' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0x5778b955b7708665431c762e91835e33c2d4ccb51c45afa387959b7750447eddca3f5121aef215' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0xa93294cade3b97136bffe0793940f0667d5eefec0a35d20d091913b1d78d6cb996dc649b0c74545982' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0xf66e7c4e2383042e49fb564bcd0d7629b1ce40a3d002168e1c0a005b8c06f90797120c33d5486dae7d' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0x2c8f743224cf91d7beb205cf2f93d54390ce0297f851b3ba565d9441a411f321c0cc28f85a000ad453' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0xddacfe2503ea2b6b9d7e1ae15f5ca747a2724f9260257c1ca534a6860eda8f3fece2e4ada941cc3d9443fd28d8b00f059e2b273fe084bc9e7aa5833d3bac83d316928cd24a81ddba0ab7c59f830f78b8' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0xab2dcaf86c06d782b8617d2a313a39975fc7006e46f2c51271555b10afbb074c2fa351532220abed0295c65faab8c0cbe5e02597f7da1dd85aff760c3e331b7a15b83475cfe9f35361032d5229693ac3' + tags: + - atomic + - uint + - wrong_length +- type: uint320 + valid: false + ssz: '0xd922c02d80ed66c4f4896014dbec7dcc995c9427abedd217f436fc7e9998b686b67c54d6ecb5ad62ccb0f78c5299f244273ab0ff8f09aee161d89fdd2f6bead012708c9d8f4c36981e2eb55063339c4b' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0xc3d4a0e6969675fd8ac40ca7ea9df1239e38ff1a' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0x67365f5f17881a4325ea76b5cdce43f8712bdbf0' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0xcd76bd9457db77cdb28fd1c0eb00617f66b0436e' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0xe09f110e65f74e0074c3ebb1eb0c245d1556164787cf34be2add7755a40915798caace32909b1640' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0x947f1927bcbf454ba5f0d09e5bb9466e728f493b7ac192b0d5251b0bf3d08a478bbea4f96a09849a' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0x5b5beabb6fd8afcd679b797c8fccd75f3ac3d0b7ba2883814a0551afa05234e34fec82dc97d869b2' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0x0d68358758c0cf580df66b6d2ac072e4908c7b45baf1136f8cd2ddc58ec8ecf9fbdee5aacbc0ff772d99' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0xb1697fe3386135b645dd734584891b967e6a1dd9e676a8160f42c941ec5d2501b045a6aa698711a1b89e' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0x684868e9b5c2ff838f71b9d7bbae598b1b4c44d8e3ceab88fb64d9615a7dce3a27b5a3fd5da3b8a11563' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0x0b7539c3a4fb6053fd1121350f192814cd8acf33aa4f6a1e5687d56e439ba372958c34a2ac117695d7ddbf10f40f2a64d24d7bc69b7df7a5b3849a9a5ecf7f956d44d1b219bbed37424b4b6db710025f001f' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0x24ceb28b3e7dc66e6c9075ad3f9d630476207a5648a16a3774d2b74fa36462aace758c157579a0bddd0146caa0311a161fef8bc65457fa6e43dfb099eda4cbeb9135140ca91db5a93299e38974aaa4651e82' + tags: + - atomic + - uint + - wrong_length +- type: uint328 + valid: false + ssz: '0x47fa3723e586b6c0b6899ad9ae29397b66c75b020886d4f075c20586c375d22a1eec6e7529588c253b9521de42d5b7153009497855d5f23080938ace8427db4a09300c7f4dd10fda6658e101fd7583f5392e' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0xe26bdeff208af7cc818e99b4eb7674382be06d618f' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x3959107db5d31496041d2289ef157c285ad68df3b7' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x6a9ace2177fd4f222628b8b5b373fd2a7b42267741' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x93edf98fa992d59f2e60ec6098f1d511e2e0d745a7e4f282612f411bd98e78d56b6874f0c383011660' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x6e3488458a86445ba5a855bcfa8fbd93953fab19548f068eca0b4a183f7a9c3f7c635090cb9cce59b1' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x47b0499bfcfb3d3d62cf584c2a79f0727f8141ac822da9f00e4dd2e0bdca17b7599fdbfe519088b9eb' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x4eac803064c449d1b66567ef9d5c04e09dbe47759b6e3076ad379a56ffcd40263ee27d3055099225362ff8' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x55b89b6649419d786d3f544101939c5e0c4a387976b498aef99921056afbbc44f7dc855e5f184922116da5' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x9e6b5960f8738bcb38bbc9bf490e5765484141a24067911d54aca7ef168bc7d1e6dbc59cd40467d875212b' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0x1d11c17945b4917a9700dec6c58ad1d7eac122e15861f2893ddb043de4e9e7bf4b998ac6f209c4e26d0bda13fbffbf0bfc7833b87b3ed8ba27baaedfceea800838d83300a9b68848a93b54f095aeb0675b992607' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0xfb6c98febb35f15b02c603fc9721168d48d44f03d97c9fa61e6f5a58176d26b4c54ce5930a9cb240bc60c72bdb3bc03c5c444bdd58bedcc5b56af95e7307588f457bacba8296494d22707a3d69268b8813f18dfc' + tags: + - atomic + - uint + - wrong_length +- type: uint336 + valid: false + ssz: '0xdf73d5203c529216b16eb741be239b51f7c9388ac76e6882d15950094b443b280660757ae5a136bb6244e3d06814eaadf918ccd5425d1853e64afede32e1e7f88c9d35f44acb232f91b5b0b2015c228c4242d5f0' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0x826f9f64e5994d360bfc783830478f0b57864f1bc9' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0x050e08c4f4ab9e90b44f3654e8a13f90d2f3b4b4dd' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0xf3432fc443bb998eb861595efa1b3cc1eb9d356234' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0x8245ef41e9fc35aeb40bce525b407ddd868352747711c29b8ca363c22ddd8c7613c5c0de3e6be10feb0f' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0x0a25412f8b4a9830cb1a43a3c1cc449a6cdc9240c47a1f8a6f74f3f55272f7816e7475e6ead95791aef2' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0x3f354b99d93f85e092aa35ac28bf43b8adc7c5f6152f7cfb3448f30412f42f9274c8eabc246e3b0e9ef0' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0xaf029795bc907fc4f8e2049a8ffcbc50fef789172cdbd65ebfd98e898b061d0b812a555c5fb6a6a5d2aa799c' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0x393176039842d6b7371fc8518a1c5dcd9c78a4226e12100a33c9e0fefce815e7efd86dc7c9c28e18822fa609' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0x8adc416b89ead9d696fdba6eae2d0cf93c4c1afa988351459d1ea5c18154375d28caa6fe48f47717921d0cb3' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0x397722d9c7c2af700ad3a65769fbb9e0c4737a68ee276e3a6eae32f609b30b4072c6266ec5886bce9988606f6ea9e6d7355e3b360d14b82fde67c82e52c1f15887322a5221271e04edc482d7eb85123eead007a08048' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0xe9bd9b3a8e8ba0fc07f0694ec71dd99a731863b8e64aa081f0dbb988f42b1f0dda31c0b05579564822bb497fb1f1f66f42d3ba683a8fe7ac533096ec517dfcc035e959e70eed2946503c4b36c62aaa3bbeced3da4d65' + tags: + - atomic + - uint + - wrong_length +- type: uint344 + valid: false + ssz: '0xb0e85268f023de0277b3ccce78dd8cf8be5d0da9b69685bf922a6b1be876051330d83d80aaa2a3bc07ba9c755b4203d8de4244f72943290d482b02d0cce9174723736dc5916d4ec5cfc358af6ea29ee7e188ac62ffbc' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0x6957ad0f08f832fd79cb30bcd2e520d90fd133bfe449' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0x7a2b5cb363134ded17e75bf4369d3c4e51b2f7f2cdfb' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0xec427946ae1850dfbf5bb19a4922aee9f3863fe0b4c6' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0x9c08d6d9f468bb330e593d76f0d754041966ee61110d481021167cac49abe019859348657c5e6c1af5b0c6' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0x80a12ad57142ec2f25f7b884cdf05ccdee44cbeb74963cb056cbaf7e9e4a1206ae57432db2119605dbb31a' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0x01a71d02811c364165f067d6d00fec347dd389ac6067958184e7bb9a59363bdea488daf2d2a20cbafb93bf' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0xc8ade857a02bbb4ea938e7866b95342496c009d9fd5f1c93d972fac414729c196fee1217ee65b48c83393c0fbf' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0x25cfee058c6a5618f02072c1bfe4ce37bf2bba701ec2c8cd58b960c7fbd0e27d48dd1acbb65c6fbe329dd22b9e' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0x1065d71eecc8b510648f5deffe9b6c9b026a6df7987bf717fd491b6ac53ca0fca89495ed488104538cbee44eaf' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0xc19dc3df8883914c2e1ebea4b596ff6750e9810e5d0eadc41feb9838cc549d27a6f13723ceb45bff12b1b8355e030204ada66f43fce4be0ce093d5ef09fa04e95a22d481c1274f5f6e835a8a2dbb8fa491cc82373b149858' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0x8644b7a958f33d49717a37cdc5b9c946d5d417601abf93a9e9082540d165aedd85a6cc06ca91e163f96b15a80461d2a659211a1cc9a9a9c85486aca5d69539834b6b69a694d8c0fb660f3abec7f3ccd5b71b600295454a12' + tags: + - atomic + - uint + - wrong_length +- type: uint352 + valid: false + ssz: '0xc9fe757c1bb286962807a2187a6c906f320cc834bc754d9603a60f3d351b64769555ff25d471cf8a736d9b74feff9e319e5e895a1aeb8d063bf2f6065dc3ba04ca0f072cbd5452d91c2f0e135e2513e5d78e19421b522ed2' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x8fc58e1c342e4dd5517d9164bcb40dc9e71c6c47e9bb' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x679a96deadffba35256d57a193fee28d02ebf02f54fd' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x46c08fea327b57dae0291c19baa4a61c6eeb7aa88ae1' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0xc612f5a3241a96e102c0f47d1472d6128e6c8cd2fd887848f374388604686d7cf44c4017f68fb26cd766663b' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x38a1bb1eff721f6456c2531c6f842bbd23d9b46b877999ec818d1a5800f02cc1c457740fce32e25eae021ce8' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x94c644aa7b9a32b533acfc4165f2caccc67436b2c90e2673ae6898a436e89839ad053fca12cc86fdc657f002' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x4e45cb5434dd6626abda95a585ec0203b629301140549a6a872e97a17eeb3439783bbc5f8ec50e21294bb71be714' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x0834b79a0ab26c25cddead4034cd790a2984053fb5be498443cca6e3e9dc8414e7b31b96e8da351538f5b3b591c3' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0xc394c679ebf52278f00bdab091a743718ea6520f8106c8dfb51f92b0fe93384cf4176631ea0872b9aafd408dbf56' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x19b1b58e4e4e737f4b0c70947c9ffc2335bad223881d832845d71b63fb368606f399816ed7f1d4536d303c8dacc69ad5e84f1158bafd6706e71ab4a14513f23bdc71f0c653fc8b2f14e4e0d68c964c48c0306e000f42fea79d0f' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0xf25258f9353399dad59d61266b80ff08515426fa8dfc6760930ecd78415a314714b0658930cb0cc5a037a8e0cf24a42fada79ca2e88117be2fd5d1a8ff9d5e7fd96c56e6c4608da5475e431e3423b36adf6cf8d18511aa748571' + tags: + - atomic + - uint + - wrong_length +- type: uint360 + valid: false + ssz: '0x27c5803760b42b535ac435d1e84b01581fdb73f32c8bbb173676356ba08247f516214143c91f53f9e947f09c6de3235974dc1a8f4e6c71837ed02b5044865fbf6092eb9a9ba2c92ba8c4774e3ff8a639505c7e2a70b05d28b281' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0xa9af165e27eb030e82ad285116d1f458751af96abf73d7' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0x84077f4c4e29029b608185a9bfc7a08f8adca4c5175124' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0x15289e5e78842102ca26614e95a68da6987d1f8419248b' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0x3176892a5fa9fbaa8a8ccee430d6ec5b39b70980234ce16e8f7c10e88a6035d7a3e05fcdfa3d8fd85decc9c5a0' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0x734189e539f242ff08a012b74a5e460631bd885e9e051751b3e788101932ff8a1ece66bc841fed525277e15ea6' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0x21e4ad59caa377ea662815733afde4754699595c7a9b9d11b476450645411e94b7d9b8cbbf71ecba9f4a1bbcfd' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0x5c0664fd3152c0e4a7212f2292f05133921d403c01813ba82e4eb660cdd4363b2e1d5e43d994f151d359946ad55f1f' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0xd3a655da15f13e2c60b8c3da0e5653eacd3927948694b25bd89a1294b0b67728badeb6604d2b6e3df6f148f777a149' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0xe09f1ec9e6cb9526615ac9ed4940175715fc3cb82879b8422af9d419b95f41c225d78834b3254ecaff9e599a33c812' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0xf9d570c08b4313c48d4599aad7ebb1e9b75bab48d126608c13558a41d36858d4a6306e883e816e61061366d58e5d874fd9b166b3c588a9c073cb7f42ec9664ad728572afeba9c41786abe723d796f7b2b351e19a3b0eaf89ca7bf170' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0x7bc782fcc76c37d97b820f94cfd1a933c2a4abedadee645d04f2cb8e992233698585b61a9b0918becd63f65d52bc26993e52e50cc5eeddbb07bc38c167968ce6e418fa079148ef9c709d5b1c0ed5d359ee4413f700a620ad651db796' + tags: + - atomic + - uint + - wrong_length +- type: uint368 + valid: false + ssz: '0x2f797b04a31090298ca32e1439d3e46e46f76e9668d9ef45f73ccdc7ca33648e3180487b7c819a48ffd50d74e77746619bdeed83e94f92c116ad444023ce0431bfcfe25a685af40fe18779b0320b096b722b160667820b9235db4ce2' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x4a6099af52104ba5cfac66495604c0d66f62536fcb62e9' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0xa5ca188e863f36fdea55166d6c6a8fa79c7015d7f45768' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x0484603bb032c4ea9d70b9a634e5faa124547fefacb45f' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0xa0c0403f73df56a6d917f4ff50ae210d5ae0b0f95b7a616ea68585bf1903e2741f0370763ced027dfaf91e17dd42' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x30f0324746aef564e65e2b408697b124526967798e0dcc07cb7229e9ba2df7cbe38606aa6d79f8b6930a9c97ef47' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x37132e6bfd590cc95e5ecd716f990d889dbb7c2b22d5beee261ce1adc84d5f6bd1f4304d461d54114ba07f9471c0' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x444a4211f589ecb52445f1f03054f862db583d7c2a82e5be13cfdc88fbd31e4da53ead95a2e64873b2be96ef8e0b28f9' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0xbe2ad6689e9c7b5aaf20f6a53f996157e81cb2c3d07f2cb5e9668e88ec1351bc8eb6e291bf5e8c1cdd0e0a1306c6621c' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x418da1c0f2fa7635aa77063f7650f643f2250079decaa1066fb4174b995a0032d6b01f805316aa8772a234af903d60de' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x0e6d83dab2112f39dc1afe5174103c41d541654aa011de9534efa0c9a8d3cbb97d517dff2688d8290ea0d4a70733e77d599f35c1b5f7787884f020413f027d4190018da4d8d7eb567f38bc1e15dffc34e799d492d5f39e160b5cebb678ac' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x84068efed07cce4a43493be1ab57c012d69da4ee911081e2fc02267aca815b2f3451dd254dc8f93e590f3d6451bf42c4929d8f398a3109241944c0f4eaca59cb866c027ae53079e22c76088f980d4d12c398b424044f51ec4eecbd8cc479' + tags: + - atomic + - uint + - wrong_length +- type: uint376 + valid: false + ssz: '0x517fe1ce76280b7bc53f5b48197668318e28ff1824e391e7490d10bd00c658fdb68863bdb44bb8edddb753ce89db7ff4c32131ad20780671afc0e3dcb8f480c8331d8bff5a92684dc15b583ef67fba42a56dec0336c93f831f0c33576a43' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0x5f1172192cda7158f250500697d0dfd14f0b001aea853b37' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0x2ff04052d92ae854a5ee0f497439965d608f1459865986fb' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0x67715c265fe9ab327783df021985ae4d7d9c8d4f61053c0c' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0xc6749e3633b81485aba20b5d22f2503ea488ac67f906e5308ef96734d5945b35b73d395f4eaefef757d3957b0ad992' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0x4a6629a018355414447972c3bca81ad3a3be6f9ecc68b65fd442abe80960572eb29a5b6238fb0a359c4ff7e0d20604' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0x1f797fa77bd363c9bd1658387baa08f3146c25f8a5e94b4534897674cb419c2ad9cab312466d854d632d241b196b3f' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0x616b4b15832d8f61abd155934e26d67a0a8aff5844f739311aaba698314103b6c9f550e37bc059746091b4790225c1b5bd' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0xcb6e4061fe6829831bd249e131dedd53b0b896a2ceea8b662c5a80510bc12d9afa9dc6cc2bbbaace98aa26158f4ae7db17' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0x6ce558c9aee49c1dab59843e277603e382646f6e6f63d21284e39b9d7e531a548dc1f094aead8f6a124ea730db55be09e2' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0x5608c43ab055b02496a63e28d035fb5847ba2d51bb722059d2dd9ce2b53190ac745d9f3d8c1c96c06061a8bb3cb36d6d924acabb605e820d7fab4b364c930d8871afb653b038b41cb47bd413326ce4ee96ff2f01602c1be3c6cba441a1441314' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0xe244771c96e8e64f70993aefa16f1f7fb9e91e35375b949078cc8dcd6c9ff673ed23a2286458506405bcc99b5aec3f2b61cfa735568c7768d6cf9bc562ee3ab2fe78ba02e7268a893019ccb098bf302cae136c9386198413012f394e33d11599' + tags: + - atomic + - uint + - wrong_length +- type: uint384 + valid: false + ssz: '0xf71eb886dbb6f956420e4ab15ef09a0693ca30aeea266a1b15460ae357234c0c988e3ebb431473df1791e2ee39f9c22fdcad0e00f5dde397ba8cee53c4703746cf04c3c856382e3975326d98c414aea429a3c6b6664548dfc0a94b4fefb9b489' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0x0d64005cd1c82bf7c51a1b06b749b1e34d87f93fba39a356' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0x7f43cc159c3dba717beb450f151b6c84756d430b27126bbc' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0x0a6de4f64fc7bb9e91b5095f792abfda3491444752640089' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0x27175ce9908bcbbe2147651c5461481766b7a160273104423b333ddaf7613d4b91a5744bde16f2793ef78987b3dda249' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0xd7541b39ffb5ec9d1d097e5a3cd1dc0e2a0e2c404ea58c9dc89ba5b240a4aa3bac9319f7a18bf84a40085d1db0ae0f67' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0xa721afe3b1fcffa095662bf7822d8a260fc3ed62b6cb4c86e920783f08538f41f1a10477d9e6ea266d3348b3bbedfcd7' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0xa32be239cf784e1126ad39836e72bfc63423975d7b641e780034925d3f2328607f88f0ca964a15bf8ab7d0d9998bdb26dc7e' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0x8d355360078580c49c0d81e29385762d85216eda29e5b10846091b8ad9d2d71674ee263ec48c2e6b0cbc95ea4ab2d66f43d1' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0x3a8fbd77b467636bd2e0f08174b7c51160106bc60ffd842e5c8f3bf568a762c64fa6ee1944eac0e46412712ffba34db08e5e' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0xe17965d4f3ed7304f16dc675542813e2d6a126f9a429205bd03c3df37a189a3dec6a4cfda500dfecfd643866a7ba59b39b9c44fb1008b879ea85bfa414cece85223f16001c57c85a1bf5ffde7ea9ccf3b51d5706dabb6c0a1ed40974841dfadf331e' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0xe28f10f773ab71b864cec049c036d339314c125bf3f9b42c88bad41abd0c99bd0ead51e0cadb256683e05518eba64e56cb2fa5f2427aa105f03a715a783a7a6d129f43c5ccb3fdf2bf0516ef07f9de0d51f03386435740bca9bda023ffbbe615a1eb' + tags: + - atomic + - uint + - wrong_length +- type: uint392 + valid: false + ssz: '0xe9780d7276f2b66e46e286ab3c522cc677dd57f74d36bb410821aae64450edaf18b3dd6b57469e449320e06295cdcfe49692c30d16b2c3f40f3f8717b97b6060fafb815cb3b78973f735f727f10ea4a1baea6ae35c0ff715bc2857278fd8ca8219d0' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0xa39de5e044bf78a4096927a069b5d4be00e60397bc8bfc2570' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0xb34930e3241977b4934603e622af76d290000546b8a4f54caa' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x0463a057e0206e1aed2186d0385be6a7b0e775e376b3158bdc' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x105215217bd0c475261d6e0d4c085b959ad0dabe2398de602ae9a492f09284dc8660f52331f5e9d600c178ab0594d3474d' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x320f82a0990bfe6b58f924f617a05f246ac601a8facadcb683cbd23bb70b043e6aaf23173e14ce521ce3066629176f7e66' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x06a9687fcaada8b72da45da616cdedee1496c812694e70722a7582083f3e27a0ea4384a99a91874f2061558d70ad6c595d' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x1380bb5255818b59940fc2547959e89d58e59110b3ef1cdaaadd910bb0143bad0298403c54c423b940547e88103e24e5f6df5c' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x9e7a9fd0ff5e9cb63017946a1f9b03dde416077f5bb0eeac55c450e62b17ed7f504d7173aee04dce08d98b832c014802d3bbca' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x86d7ca5fc7ce59dfc1ccf77b54f80d4f819e506a65664aec7a1b92b2398f5d4133cfe61b345de1f6efcba0557e1f4538b95615' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x3b70abc82f1cb97d37e1b403445af6579703544c2288c382fd91c1f163b45046116407fd85e57857dd192a6b643eecb8f3b5952972f19dddb9add0782686101019e479aedc56b7544f94c6269a93a82e1b1cda873aa244b90b0fab703bb76cbf5867327d' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0xa32acb4e0292a1260e205eb3ecc4045b7fe5bd30ebc8ddf1725a7ecb9322a0019fbb249f50011f2402856de64d55c407e98738bf1a3b0582c4734b873cb40a488c0667e7bfcce7e5c3b28160e2d1b18f98bd7dbd4e9acabecb814725aafa91cf78cecb1a' + tags: + - atomic + - uint + - wrong_length +- type: uint400 + valid: false + ssz: '0x1179cf97a395956fd7ae80c9d595b7cfe29d986580fd2eee465e468cde52b4dccea8ab4e0c129f899c8480fe086412129562ea65cc3480cf925fc2ae76e72fbba8db6a6660af88ba6532cff76ed8d069b01223d6c232e58e51c5612845f7f9ea73ce042d' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0x5643108b4f6bfa32a8928fd9b4fda474a8eacad384bb5a3457' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0xf9da25401f5ec2664305dd13889160a175d3c427ffda243dd9' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0xd7474630d076c49e97e343d745af4936f218dd3f869aec9a70' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0xeb5ae2a04b4521b3323d0c8c0313ae46b51a0a0336fefefac94d46f8fe6f998ce4770c2759f7c3fc32b3a5aedc49ac3127a6' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0x1492fbe369358da050550990df67084c0eaf71c2e8b8dc45e36d583f198dcdebe30249d8c88b29b3ef2bf0395c11aa52440d' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0x1a3a7a62da6de3dd03306d3e18301dc0d0056798f52ac7a158d7f86f7d07592795b98d4dd7c85e8b8914b71b35aa7202393c' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0x417c919381e1adbe772880a29ca80018a570ecec969537a3ee15a0690e05b5b4b6a78bb941884f5639a7be24ce4ce09c245aa1ab' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0xcd82f1163fc0afe142e07d1bd98fb804a188d9c3af4fdafd0b5cc304f3dbe6766ee9dcea6fa2a5752cc7917d4bd56855bb2d14db' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0x0676f7cc0a886c2ba157d6159c46cf5b6f9e7ec539da97265ef52506ed8e9b1d1b91078908ced73843648ef53a524afb3eff2cb3' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0x7840b5ddb28ad36ac5b0a34ab8e727a05a8f0fda5349c9772aef78c6ecaf10e571c57a85dfb28502e3557a913a68b29d3dd901c55f3ca81d99c6e7ad09d1393a92c5779cdf99569ffef8fdc84f19a3a0dfff17aca90332854c29ca8958dc88ddeb79685e0f37' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0x1af705fd39912561f304da97fc7bcc4063fd5b3b278e926d980fcc9c9bdab2c6ca56ff7ecca2c0453ef6dfa7e82aef0cdeeca41d2c3e03fda444604af5838f092de8d546f61c2d39280cdfa12b056e3c36dd918152f156dcbb7962d82e275d9f3cce815c70e5' + tags: + - atomic + - uint + - wrong_length +- type: uint408 + valid: false + ssz: '0x4d3306d51404b7bc7b7ab4f74a488f97859669c94052b11c2882b363ee942fcb40add778b1c4210536d946f083cdee527aa6a440b02ff01cfa4298545bfe5ed68473ca39be87f292ee3d21cc6981e5e88ac3236498d51dcd5c6c37c88b0822129f85c9edb4a6' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0x07e16279355d26114a6b33379178e8e2ba8b8ab7bb0fd2b3a202' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0x0c573599886b9b64791f4a48d43b5cebb483c3ad9c6ab0cf7f70' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0xe8224625fe7e02448302b3082e34084bffa2c160bbd88916f8aa' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0xabeaf7a0109ac9e9a481a787325bc1d0d9706fb67c65d50e6593fe6d66aaabd00307f2be39d6c8acf206585846c01abda49638' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0x31328904dfcd3c2e98b839bae2ca6bd053ce4ac895818417ce7f1dc15ac4c273306d0b8cf866384ea3148415369e0d566ba677' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0x65a42c77008b4357c625c5d017796b5dbccdc8258f2009ccbd8010df35f69c048023dc97e0ba29482e950fb19bc7e60b8916e2' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0x813b3269c4dec6120947ff50e445b735d2619b526ebeafd2eb0c50f1579f59e1c14f8c790705ce8d64b2f0d34fe17bfa300ac25d0c' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0x476c17771fe5d814fdc101705160b220fd86bc195e01a6193a21a50a1cd9a978bbc90165e4b348b8e1e7b5f44ea9b6e25bebf57606' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0x1ad90840ff72b2e30150b1adb3a3f6ef72050cf4ce242c6389639e21b8b0bec745ae472b9e61814c76967b183774cb00ef3872240a' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0x63c164d641c86af1e711204bc29570b8f88fd9ae8c12d86f6330ca564611da491f843daeab7829026c43a3ef9d97591553cdc7476530c7ae314a41b4669cbb510bbde27d412cd0755793ce2eeb317f56b2a42b9fccef6ff07719ad4d2e37007553ae2244691c8a90' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0xf2cd0f6b37dbfd716480d8571b8fff14d45fe1d10f06136129a9809dc78aa0b5aafce0b4b4f031f0ec780328b9f7d9a7c8ad2e16b8188243668baeb2452b0c9d69bd1bc520c641e74f4b7b463d7a6d9f132e0ff3853e5b12e5bf1b20c35f6bf7f7a3d733d2cb18a5' + tags: + - atomic + - uint + - wrong_length +- type: uint416 + valid: false + ssz: '0xa4a2d359919a04fa9da555ad095a1e0b10d04618e409e81b44d37845c0dfa2effc598a1b2260c9587d6545a9acd5d4c444d30844404d3d7e3981721549d72cda33afc5b58a3cbf81884f12e4e8e600b6d9cdb270081572f646c7987c1d54d0662da1d8dab0e59fa3' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x2f2cfb34b3218b61f4ce602bb55e3d142cbe199d5f01e1213411' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x6b10d41758b30a30e417510bf2bba6b700a2e8a5a3411d652d26' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x93267ddcad6f83eb6655de602156194f9b7b264a80f5ab8bbfe4' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0xb1a1d63332bf868c3cd01203d4b923541b942fa5344d5918338e8cf71fc96d75fb2a226c64b779d83bf64e98d8a82c06d1923244' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0xec38403b5316408f927287a8b8c08f254c4f24fc8dc6a6eb2fdf2f0d2fd36e7071fef02ee984d3c1d1704b8f7b60b0b7e379526a' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x6b26038f6a0f8d85d75ff739310e2673843f9b106f29631436a2ec447d84c64aecfeaccbe4faf6688368e08fd38a6073f15c7102' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x0ca2882ca235355c3fb1beb36b5ce1787540208767ca071c9c02c7f29d1cda1b861bea5940c4408b6a8ab87f1e0bfeaba4ac4291c5fa' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x2c7eb4f95cd54c6a7482908196b0f4d4bac9a32e260ac95565acde8337ec0ef6dc8c34e657de320a02624f6a92a5b440de57f4d1a31c' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0xd3f74a15cc272600baf3fa4ec6e9c3053d3a89967d41acca287f69024003938685857300095acf5f1daa46419d08bfea459b93da9e81' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x96c53a4e427d27ce4484f1678cc5dd753b8aed2e29627bb0e6a3b4617310ff0e0c9874efbbc4ca0388a49661ef366da2b1c8f0acf1b20856c799cfae0a378560782d14dab1a700b6000476800e9f2a308b85d9c1afee278020edef255c986bccf872fb3f13e69b47eea1' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x1855a068bed4215972a8a4d2335750fc6ba8491b74db5a16b8520cdaa0a3ff3356820f0a9082eef11bb305443901f71effcbead0b620bc84b1f9a2c156e6fa47c9fd4577518e01e417206f99e3902fccafd96132916258f498f5f4eb13ebdc8aacb29ecfe7a7d4972212' + tags: + - atomic + - uint + - wrong_length +- type: uint424 + valid: false + ssz: '0x08106d40ea26ea42296e7562470817a8690ff73559238683fdb561989c4d37da9ffcfb16b76c52eea89c3e9343c52bd4d09f692cc91f2edf5be6c65f71d1d7b28f3aba60753d3441439b13c03b30c5e98481de854e657b2137b8ef2419aa260c27a7d929471a15421e30' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x797996096226ad988bcb3deb668377d9794d058172e9e06f13007e' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0xa392821c90834b15970f92e2d33dd76cb9609a2352be59c9369ef7' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x77097901ccec17d174bc5865453c86f1bcbd955446457b4ca2ea2a' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x6ea8d16603b26ae0d3078de0098142e397c4e737c582cfb1ecbabdf4b641b2b8a63a854b4f4648e99b72f5b064667542b400be116d' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x86930750a7ef5542cfe861d09b11848c74e4b83f48b361e3ea668694951277267530b5d37aad2d58461b4bd92d1e0bffd703563bbd' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x65b0f9fe431c9c1882785e06022170b27fb56371859579ae1ec6627a7c6346701c58721ddecab4fcc8563832f40b56876b5b53d22c' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x35ef5b335913768230802310074c3fac9c582d04e66ad35cf9b6594e85fe0171f0f7f21f46d5203c9bc21e731c569c768c129551d46f5b' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x3aa75fa7e4fab71addb64c0102ae9c020d662f4087a1bcf3def4db65eecccae17aa2f4f7f57c2a3fa467bb07507a298acf2c7a0e0dc795' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x8bf4e250e1c14016995c72e7e401eb296a99f26723461faaeac15130eb7d345291372dc65c3a7c54c079dcf9bf082af6e11eeec6d2e930' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x27600ca26316063de2f56feae44d9f2d366295475d00229f0cbb71adeae7625921d1af045afc1f286b6f71ecd4bd9c88fb3f04ead6b224e528fec53e15008ca2df183d109ab1cd64da8741c8a11c97d544d951d296edad281f038921bd7991489c8e17fd3672f6694f3f0257' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0xcc3f1c498200459e29831412bbd2d01a660f5724d49f460cf4b8288552e2a1c23a8c344a81e3bca267671213c4e7d72c4ea9f5ed63f2189c0ce24d2523303e4929a637dfc2dcf65eae45d78d56ba294feec926d7bf104d0a3b3d1fd572e1e6f5234a172de440559b396636e4' + tags: + - atomic + - uint + - wrong_length +- type: uint432 + valid: false + ssz: '0x6d6db68d2a7e7673a586203d18a06c3559c81cef0f361d6fba89b99e7a581d43ad858b6bcc25b8e4dda135d9efc4b1f6992717b7bed14fa1814eb619cda092eb56414f37ca3b438586df5d5a8cd45bc428db16ea3a3e3df461452a48531f227465ea5a008368f9bba3c21a8f' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0xe1fb766ae91a0e4d32c6f38d8554a1e9b835eeba5340a2ea7fc399' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0x7117ddd5fedf5e15a073f8784973ccf018120681d6192ca8d78019' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0x19bf1e50b1fbb3a6566f52a6c0dd3fbb136e04df79ca8ba59ca178' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0x49cae529bb297c96c6290699ec50d1e89bb753d23689b15c38f42fa1da6fd8d162d2d497cef1bd732d92db620cb077ed323afc5994ef' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0x2b4860b282a2b651db5147994c5093539da93c94349fa63e4f87d4a040eb7bfa1b7d03a8f88ba5323aaf7e6b250897718d0c30c9a723' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0xe351b3f286ad12e279947ff3f788673e8e8e045e4f016f1d78429e4781df03393d9bbdb6062182fef250e114bce35ee1bd8ffa35314e' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0x66eb67491c0788b6220cebd99f9b8be09c3cf791ab985b0e09dde30b1455e9e442d8ced7fd4c209f4493a6178a688fec62d1979cccc4d942' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0xdaf13404c6b60fc7e62d266e6f927ed9d440c670fa122a1bbc50eb3b24968d7caebec327ce97cfcd101301c6486a993879b91cc909ac968c' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0xf7828fb817942c5f40cc80f49faacb83137b3a780a9f799efc0e8f98603986448e4bc4ade698920884488f1d78109ef7b8616546db4acfc5' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0x37e37776cf0a7e723fe45130285713fddb7ed6a3dd64dd00d07fbc481dafde0e45c4c9faf6b2b79a428b1808eddba9c332f19ccf167457cee94421db8a458970415cbf10df834ae44cd8c92e5ba305ed73b1b0b7c4d70deaf6b4c15e125430735c93d9f7c924438f4f8e9495b6fd' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0xa3144250b866fbc4ed72cf7ba973ebc44a05eab447ca215628a887b8870be38dfd70f73376f03da43b83ab1401e1b0a944e8d750260bbb2d5739827c71d812aff39f46bd62d661f5b70494bf87eac4c433cf363b4fc771f198e6b09625d7ac75fc92e06972378d4031aa2c86fb95' + tags: + - atomic + - uint + - wrong_length +- type: uint440 + valid: false + ssz: '0x3f9c23d43999ffea9579b92eb033f1e8d042b5705cca6948282358b407fc3e152900a9224470d0c7010d3efc57b7543ac343d62f5509524a6b8e4c82bb4e3e38e19e7283ec40f5f70e3c24eddaf2396cadebfffb4a385049283d05b298442b61a29b3a3cadd98cef3c7250741380' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0xc47e6ef3c9df63f641b208789b7ca913d121e75e6a0d64f75275f280' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0x69be43f8d4ad49fc97761cb6439ecb454d7507aedbbff58aebb96b12' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0x06bf94ad7729b1ae249b4ddce15ed757ecd1d8adf00608433399d204' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0xfcc8f6533d73d436d38e4acdb1e9cb3a5f54bcde16a285de352799324fb92c16a26eae756077e9080f08c4d062c7d21f3b29ddb7eaa358' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0xaf4c05d2826ae0c4e9707ef2ca826aaec19a425d464ab78f4d33fe6f47b549b3895131746814da0a413d1f8e308c77d1a936417834b77e' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0x4e7a7712439743bad628142a9f98b439085cb7b803636268c69a4df5dc7c0f7e77dc8553318c538b27c4b73dd0949b7e595903098c3070' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0x7d9c73896c5fbff9c772761298e3bec367dfa176a3ec4430702f6a8628b99d7f93f24a34481f2e2e9588db1f2c19462e915f810d089d030baf' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0x590a41ad4d6c090e9fd1c4dbac5927041c73e9f3e854d91131b2ed2d8ceb9926489eac8896cb1949fa4a82d55db80f223fb65c022ab9d9fe4d' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0x9ddb8590197f1a44a37468bfa23bb43bebab99c246507eeca9b486fa50cb717e75a5caa62f401da14a5c91d72aa617114d192bb30ff0b30670' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0x515c528cdfe319920840a2b4c0f2e844cc36aaf9f8fc2d8379c658c1df32b7de0f3ec0a87eebf23016df38cb69d9440d44f4459c81c8e706ae95afff173b1c3fdaa5f8fd9cf10acadac0fa02c4ce78fb358cfe55ad0d9beb10f17bb109f8effcde7a697476ef916433c40815738556ae' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0x9cf6dd551996e64112c987919ec618e8bfa059fd20abb5cf0f6e30d3c570f250a42adfb045fc821a3bfe0cad4195f1d685a2c9ffbe3a647043c0c5c880110d20cdf2a2bb43680ef401b373799f6841633edaf9f42357978499e85edbaa24ab9c4083f93f4f5a53a6f1e895cfcb501351' + tags: + - atomic + - uint + - wrong_length +- type: uint448 + valid: false + ssz: '0xa78c711dffcc66abffcac5c37345b7211d657ae51f3f1a582328c8f3bf9825c08368f0626390cf1f20b8045cc4805bf46ddce9acd8133b42f84ea21cce3f8d15d3871b447952344b634dbf95ecaef9c67b7b858c4f20589d48032f772e8b6f6676b9b8b7345a630685825f238f8d0c92' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0x3bd28a1b39ee6abcf6942ac673a69998dc96d7c1fe9bc8fb865aadce' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0xf8d532629663af4c4aaeec263d8469505f379b29ac15763d339606de' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0xc16da2c7c38a202ef7085583239c232d3aa132bc4748d56a71b9cc2d' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0x99a037074645bef0275a257258476dbf23dc48444595b162f17e4c951cb4178b592ef34f453b5d679252d8c191fa53aa87c0a7b09f10e8ac' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0x4552bb17eef618be0270ce796672f9f6ca66ffa49ad9b707a9c1237e7b9ce3027acca367b7b037baae12da486e7fde5f7515cad246ddb082' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0xbf6de95166a59e0cd503bd970e1b88f6615a8be0dd3e594c35fdb03b798c1c9697356236624c4b46b121f7f034dcd99ff8537dcabc4daff4' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0xb72fa75d18f93ba9b0bbdffa282b58ce46013f76f239458b3cda622b6be15f14fc79172de2e58cc5de91fdf56d9b6bbbb013aebe1ea88f3cfd24' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0xbeb8398003068bffca90880f45c4eb5052f5008c169d26aaecb144d6fe67a3c1ec4a12a67c7cc3461c646167ecce1ea2b4dd6e7f0214f41c17a7' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0x319fc2c6c021418861d8ca06a5e4efa4aa4da3ad5fd40c6b14382ee8875a681051d8bba6d9dcd37f1feaa8cc3f43a40495b4de2f075d911c8ec3' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0xbcaa468aa842a72c0f1fb3e28a0ba03ffb879e42a560ce5a54912651ea816ff15493e7a0f864ab1d0d9d646ad51903bb947f0ab86b87c31a38e5e8ba1317eb13ccaccb1f964c3b18fbe85c54ce1a9144f5496c382a928a0d3d08c25f6cac48b3dc2ea65aa8eeb0fb5fdf0eb9a2fd6686131b' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0x6d1d53db83bf44293f93ee429af4316ec3157e487250c353ef351fc22942b4d74bd79860b93ebb3135c3f6157a9a2cfdff04d9045752ae99a395ae6a66525f9117830d27160206648005991c6cabb1a10e441f63e9c1ab8d087956e090a5b83bc41ea51f64e40b7262195f66c09b7bc4e59f' + tags: + - atomic + - uint + - wrong_length +- type: uint456 + valid: false + ssz: '0x82a7a3b28fee35e6f2cc68a033c47d4ebba910328e3d76141c330e77f7c87b45c7dbcf87c770a929fd703296357de9ac6d9bfde4bc4a57cd43cc7372df0768c567bd34e14fa163a462bf48c80b54d98ef0d7b0cf834a457dac2f7aa11f951fc06e52a2d69124e1482ad50d1e4d2af1a20e75' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0x914361ed8b919c49c9dbfaa8ea3cf26141a1629e42fe5109dd9f01b5c2' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0xa72eaa122d64b56a712503488f1b5a0a91fb1eec85a794fbf50831cfbe' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0x7df1fd46f7e4bf301a6a5644f732f54c03521e10cfbe574f340544b082' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0xff1aa190946170b2c883f5e1688b4352fa2f2b8db05295acdefb3fd4b7dbe73078a98058e874f9225b4712f7c95dfe3e5cd5f9b9366ce3aa9a' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0x5c47cf9c6af4d94b45223929507bed091a1c668d2ab568890b906dbea393ee9ffee4eefd685d8b1f1ee75fd1df6c4a995354676ab576a3f9af' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0x69ecdffe8224525f5c4ee53391c0dd64cb61fecc3a767da83b7637aca8a9d2f3a2946e7568f035bb39823ab7fce6379dca76835a28ce33b8ee' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0x43c9ab4aa8b733367045f1be2e3dc7e91201d7d74f51dff43db625d97e16cec6bedbf69fe740c79d3d905e0d8e92d004a287d97a8208c2e1b5799d' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0xdfa1be337da8598eb00fbaee9b9b98aafc4ff18e6de0d5e5047a8d92a59c92db309a7ee553e99bbbe9ff6f0f19c572098ed365c21bc6bbae70d9d3' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0x0d61caaaa9f785e052c4ef40346257f94594bc0244c29adaad48d0aa4265a4589055d515bb3bc6443316002624b034be4beb6f370cd9ee138a91eb' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0x6675b8f5222e78d0bb9819afc80bc3582c438c877dcea2150390cdef1feab6fb2bfb6383e15c4f38cb1cf6f5ef3e942cca8b608328ebd72ddf66d6a22d6e0efb367a8354ce894c095027c7f774578fb1d05b6ee6407eebaaca5966f29e202e5e9067e58705b6bf3012c23305240e3f523319f3e0' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0xcf45b8cc1a22f75d54c115df03b349a506e3b0dbf5944994e323a6cb4450bf068a291af07120575e305f0c7a63d7c1527e588f7c23447d79901b304fe890686a41c12bfcb45306d7a1f52ff5caae1556c8331ade64741a238e91bbb2754af824c83bea21afcd1201ab53c17b0ccb772eb509ae8b' + tags: + - atomic + - uint + - wrong_length +- type: uint464 + valid: false + ssz: '0xac727ed76133746314d964fa5231cad9ed1c786658a7296aa6b52af857e246c604cd455b606fa9a9f2726c6accfdc22ebbdc0d16a91caa6573ba22e7aaf529142a6a5b3e9c74fcb34ff686eff323f370c5837d680e9b3b80f9280de57ec9da6b3a0c1fbbfd24ac721f60b045e4b75c4e8a2b60fe' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0xb8f01d60dc17cc31fa92986d231f3255a33c8233645073dd2a31db7c00' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0x7aa9c98e1cf238193703aff0d196ec3b7a410bfa7caef6b294c46ecd26' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0xa84bc042bc4487556363659c6afc5ca0d7677861407b5d318f93095c79' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0xc4a1ed55699847ad0d7a06dfbcaf78c54845b499d9d83b956123b57abec78d319dce9de992794e56f38a6486bcb9530c0aeae03ffaddb9e5cb59' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0x20c00a150c2221bd19e7500ec6c7b881cb2e87ad1848d1415eaf1c2fbc6375c2e086d1a87f37c95ea42dca07c88da494654afd784a575fa66d84' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0x33dea01faa230910910e413814d61ec2999710671863904ba73bcb4f0878ddc4acad7b9f5ee2f79deb92cb6ba37f0a851624e71b9212e073740f' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0x00b1dee44a6cce3577fd05495edb4dee2e5032ed0b4d45fcb77318e2c7470cdfb3aad7f95003eda886e7be8472c98b1ebe8afdb9f824f274dee88904' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0xffd36e846b5cd809d34ef042ab106d439a71a30a33c3131dac83303f54cad5762817cae9c8b1e061ead2cbbe618764cd601ed8f63176a8b5de81de95' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0x7886f091ba3031064590d9c02137054cf22d7f07a4ee840738246b5d4ab5d64dd4daf2667d05d9466d72f6881067536d03ac0374852568736b788fb0' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0x922b062ef34f0538f56474a126557d52b8184e0b1b1e3cc2e74a7a636e1873184bd1b51bee81522f6912da201c5d099c14aec56cfc782e2b473729045d21e9e77fbc0c804b16d6215e738ae0ac1e3951dd670ae129b2e1b3f92cf6851f2da010e43b49d542224998f099ec46891976edf2dce87bd423' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0xea0d96ed14b5c9d6e2ca6179bdb5afb91097b857d2b7c3cd191ff9296ec2c4e36a7f9dba1d88fcf0f85ff7689030978b27d431ce3b249b0c7e3ec6ba324ff64bddcfe0d0e914c6cd6efee7143e28b1c2b942f16d27d1edd7bac91f060f6c8afaaaab462242e09d0d93fcb7664553a2ef0b7bf855f8ce' + tags: + - atomic + - uint + - wrong_length +- type: uint472 + valid: false + ssz: '0xf9d8ee7b3ccc5f2db9b6290a2fee89658700f2e59492f1058e67205f200a50bfd5257649d84b8e7b4a9b14a88ea9ca6e63dda6618880fb7e64632c32e62b0a2c9d539ecc836a42aceef54e2fcb13f468f4a09c4e67b36e012253b453a7ac9cee2da42cbe058c42f010f945d2010ef965a490981983c0' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x88d8d00aa6036baeda19e05ebcab21815a52c2a8d91642dc16b07cd5238c' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x9dd2aa41217ba3598280adb946272c979d75a14bb4a79bc37e1d97a94603' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x6d1ccea052aabaa28af1ac22a0cbafc26f84700607f2ee8ba88862c8ddfc' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x32471058b2b56dda87b15b7aae8fbe113d25c99abd3d9cd5c890d4c634f663dae24b99cfe7a1e7895bb400cff53d845c1fad09be544a158ef814a8' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x653dc7fbc71a4f70d57f155ac5116776ad54e997ab4b92acd33b787c88039b6182d426d6980b8f4d20d705a3ebbc0ca33e6e3c5a52512da7cd1b58' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0xb8a9c8c83df495abbdc5586148ea46adc9b3624c51b65ffed5e4b2b070b172e9904e740185f2883497fb7c4718ddf4a91cd02c2944b6f59acd5fd7' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x80cdc3b66a89179e1b51853e03c1cc30831e8cab0f830c025ba80ac6de38e74a83e2d0cefce86f550d58eb4504ad9e390a56a4ec4d8b4445454eb21333' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x6991054a30ea2d12e2915539ab83680e58ca3a7a046309e803c49f8826637d46dad4495da7b32d41a0e582d3ffdaeeda3e5ff576daca1854fc143aae66' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x84b7a287f508c3382610124822b5343b27a4ac3872a52e444e109162bdb518ffb95e565a908d2347d74686a61d0aab1fc049b64a86f14d429aca163574' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x860e441ab45e00dd0b73f762d90657d543ad7fefc1165161207872aa2c565d0ada3a1d479550b3e73464aef019663010dd2ce6b3d34c07c2772eaf78e6a150eb638cfab0737b66e36d8cbd750d0455d28d6961eb4d3366c9ec9a5bac51823f14ab2f6e0f17195514cdfbaf33f5596eea8dea96896e795bc4' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0x97aa14459f0cf84c9d56c56340db0d8c55839a11431e3b5b9a30308768ee846f1b696f2575bfa541d5fb9f548fc68e3c8ee6c70ebf638b0b95e08e85b705a651f125034463cfad7b945ba42f9469bf336a0008e59a66bf5cbf65d7c29c85518c552f2ff5f4e897d62b45397b63e57fd43be6193eb52369ff' + tags: + - atomic + - uint + - wrong_length +- type: uint480 + valid: false + ssz: '0xdd614c709ebdf9401a274a68ab50ca0cc86bc0bae02057f6e26d65fe30fc1dd46c8b1d0e95bd2ec4ebc7071d9360d7d635b4f53798c1759936ca84a100a8644c6b029693b1006df1d89112c3dbf2fb1c017a905ea313ef78b4a6a711df72ed6c1f2910800f2f99be43e6d55f5acaecdcc82e414468f250f1' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x2c1ae969495415d40601e573be6d7c60248a232ee6124cb350ad146b24f4' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x857ed937c0c071a5932336e069f6ef956e3bd6ef1a8c7fe2571a9387dfb0' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x589d2ce2c90dae0563a8e55a3947b0cd82375060214c23f299670c97020b' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x103010b6dafd70521d8b4984a190b1f0473e52e29cf7674d07aaa015eb8051767b16f078f1bde0edde3d4afca5287ccc69180471d52c9f53642f1ab9' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x485b750294e6f59ddf6bf3ccd552743325ca45a17454d722cda90a242a9901d57d63c0aaec3d427bfba1295304d9e68188eb5a3d02b5f6f0b26e8447' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0xd35f5825af775419035a5f901ad71f413d3a6abd4157a9818f044c9ba96aea588d529e69816469b2e00ce7481cd3b3137bcf7fce1e27e96e4c3669cf' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x9dae99e7aed4eb5e0f1c1f182f4d2b6140b0f4ddfac1f99fb89f653e25b9cbbe2c001925d90e529d0e0e0a82eb94b547a22cddbf1146c964ec6aba461272' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0xe683eff4c7d01b9ebbc4925e883d22405c307cc75b094245e29ff22743ff1af293001b306b263df2ad19e6b6a73b182c5fc8ab3bbfeb319470507c99f43f' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x56e567f860b545cf5c4f7e5f80b66b2e060ac81548abac4d5e7c63467e163954b9a2104d46c952c6e9dd10b1de40331deede056be19115dbe515e4d63d11' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0xebbbcf9c993304b455fb0ef360675e85b591dbcfdc8a29b91f818c2f00c3a90410ac32ca6998e0e030eaf3bc9f321aa21751849d894813bea316250ab8ac1b4292ef6dd5a365a358f84d000af041828deaa1b3d58083abe6b60fc4f30e1f757424a6b33c94003e340bc1081c67b83979859f6f635fcf69fe22f3' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x0e0794756b94f207cb13c1359c8203bb082d8477cd740d166f82d01edfb1b124b40d86986701682826d3256be45f9f21b4a08945ab8f71b0ba2788aa14c6aac6f6a1f37eeecdb980e509e164d9d832400d0f7b42ace1bb6b51344fa656e342449a8da37b37bc7fbfb33a815fd4627d239d20d5c4f6876cc65d87' + tags: + - atomic + - uint + - wrong_length +- type: uint488 + valid: false + ssz: '0x3d26084e33e1fa61de4259cc7dccfd5bb6db7aa5e7a80d24742d3cfe4c889aa716ace6b037898ce3a8e5fa622de76674b6b335995f89ac8f435a597ac594d6bbc27e3e37f7f62eca1cad16a351a35ffb5f30b7952e9587db74b76aa7f59a6a6a82d90b445c0641f5764dac34aef4385aba7aa803eb173469a932' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x9ef4c9ff14dcf2731c42c7eafd0b184f143dc2c83dcde12a7bea151cc4b51a' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x08b153782f6bb18623ceab623b78746acd7528a37bdac86fbece4abc1d685f' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x1841573ce1e9288ba545abc528b49c08e4229025673f49a19eed5496a172d8' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0xaa5ee7dafb07ba33337b1f510a1cf5eeddc88851159939867f134f879ad5fc8e828ce2f735190a06901ae1b742b722deafbe2a91825f461994432a8db4' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x96f50f3fdf375986ee04561dfe7bb709727352c7f9ddea2a58b582e131c9781bb20e59053c19b390862c1f1726e1a9c546952bb633a3c6871fb300eefc' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0xe34c5d22b1289367b1fc9b1d81c9eedc349c0447aa71a840fc8323f81c8f6820104a6192276d045efc85950215564d56685c070511aa9dffac14ee8ce6' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x46e7c618125004bb0874f1ab1c50ef7460108abc9745a8cd984f35999b899afd2fd62e1a540088083e594a502df0eaac36328b1953bdc750a80425d504f8e3' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x8eda7950b9677d015e16b5875da6e0c4d8a87fb3cb2d2833f376a5faa3610126227ce981dd64dc01796f6d01e387bf6d45109443ecadd82c1d78703cb46a8d' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x6e747676053fbe1cb13da5863fa81e1c9799908320d09063b3c2ecbf9c3880845b2365dc41fc579e3c2874b7819fce10ad45a690afe3e969e3df52be5138f7' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0xe2a7ce717907d3e02c7dd97efd4e50753c366c9d0f9cf33a0fcf81c1d2f184e1b649a88c16b239e21ad86d047a78e701b0d19899364fb168012fc164710ec4b74b613359630bb6bfdb75140f365e1da8e3327295d2d51f88e5c932f4cc53c23eaa70cc24865ab9d2df0bd93ac5c0a51a0e441a202c45f25207d457b9' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x0624561c85a3c3f5d69f9e5489e7ac65c422dc191a003f45780b3036ae03d32d345d28ca65ad5a261e7149f59d23ccc8f362915df2146fa0694dc76461ae6ea6df9cb467cb8f9932d94435ade1e9416b66c415583eff9b5417792206d74e779a06a7a8db5eb827102d13994cd12fcc9b28db23c3ec1b89a677f31922' + tags: + - atomic + - uint + - wrong_length +- type: uint496 + valid: false + ssz: '0x0c1a2f8070d047c502d87968c3fa2bd5ef096f89a3133110dbffef48d388584e3a85104326cc3ed77a337bab6cdac8c66cfe06e19b740aff1e56ce9a14472a100a25e86e46121dfd43e309006be59c047747e1c8b4342985754e524bb5e562abb33e3215f14734677f5e979eb8dbd3237b409b986a75ccdea1490115' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0x90738be8108c86c80cd6a1bf7ae6093ce3fe17a19b13b9e161de4a30341510' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0xacb7263816aa75ced357500ca9fa1f72ce94633ac5382b211b161e0df04eb9' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0x04e869da86c9b97cbf55c65df14afc41f5e7dc0997d96c3f1a695747066c5f' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0x7223b4131b39cd6c629a49db5a7e17d5ccf060f9ef543f6626a2e6dc3b423d9f9606037903cbc062c1b75970d021693c638d9952e3c5c463ab63a8892314' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0x720e906e8abc6ccb4ec34b773c634606a7cfcec66b2eedf4335974fbcce49ab1d70d396bf99650a5f4f4955fabfcf3542cc755c581f3cca5f758ed6f14bf' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0xd5293ea27b35ea5930de4cfe4a0ce16443ec87a7058ce48283acb720c9e43c3a0d4dfca2c2dc04bc5f13c0479a23c9e618f40aaf48151ea3b6a3d0d21dbe' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0x2f5c857ed43fe5ccbbe5bb4801f02551f51bd90482a249d37a31104e7e3fe2932c74f273f96f37b67dc97c2b5666f9f56e7b1a4ac3bffff593de8a280d32fc19' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0xa5e584da5152e494b7f516c41dd5b5eb08166b438090cbf1f54539ce3fc6ef3b9b411c59763abbfcb1a8a997a81116a089ba3ece4a76f8037047fde945af5b3d' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0xe3a07092b4efe0bf62b9bf9a040c1e5dca8708a2f7b162adffff5b27ec293755a80fd71faa9cb647e8a44b23ff9c894cb00156a8aee91b457390678dbf38a5a6' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0x1179279087af84216d885bcefd46f24beb0750d6e1dcff9bf91f5cdc773d33d4e8ee5318781dc952d6d5a3c37e75542e22ac364aa087330e6dc0d8d5cd77e0bc430c6239d132779f520df791c399e0aa2b2ba2575f6ab2aab4658f0cb83abb806a4fa2caf69815ab16d6b848daedf0c4995b4baa0cb5a06587ecf5e0ef56' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0xda1d320b32fa93a1937b72b8a51bd93ec118da946b715f6ee74957ea36cdea8297bd3347155399d7675634784f062a808ac957dc05d0b9a608341caca5a091e822f4d001e11ffd157c134de90ef4cad57871e067eb47057904d51c1b630ea0536e764080b768879d4d7db0b6e4b085405b3982d6cdb69755a4d572d7ca24' + tags: + - atomic + - uint + - wrong_length +- type: uint504 + valid: false + ssz: '0xb1a8d2b87426704af830ecdf8613f3df21f1cd6839859df7842042c7bed4809745d2f047da1fa177c1edfc0195908b50731637d326d5b50e56eed54e60095880ec9f73d311214d3d04674495f2b9e24fd724eed40abead71767374c0152dd3a24548b96c6726c2d3d5a386708302aac65d698a270a9cf5259dfe75cfc1b9' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: 0x + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x1d177ceeb995de8d0d71a521ccc893ebdcfc26fbfb945b20d80273623c8fc32a' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x4e02ea3b4dc3e64d8923410db1c810cb700d7c6c89892c7b783113c290ca5b35' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0xff1bfa097ffb1fcbe33c23809144f7e3e1c20e447f555d63cc2e1187bc916d8d' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x6e216a137acd8cd14a86269b3da22a02d1b94405b1ddd8bc47e51d32d353b9355f490cf821fe1bad91f01b020b122ee2810f102d5219846c228d8f8cbc7e1a' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x8f936f8bd5052680b061481e7d75ee916e670d68fe2e792f3a02bf2b7dae2dd52434d46c9a436109fc7ed8a4629e2f354c342d3895189215cd1e9b1de180eb' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x59a79108d5c925a7262163db635f283a195b7eaa2924dfd110ffd7f2f24668585641b146b9bd93bcb89b835e3583ec9c6696ec11e46ef1cdfebf47d3b2181f' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x679503f23962d8334d03a92cdee75db2b244d80f0d5d372d564789be0149bd964bf6e1f1abe6adb7b8e2dc0af930932b7fb20629fa0f8c6e4c7aeffc25b630402f' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0xd9e94ee316cd361b98334a03f6558d478d6d92bbeeb5ce2b1bfd3beb120f203e98b8e5a9592ef9ac7e5a8176632a4721052d60269c04cf40f49a374d4c2ae0a954' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x980d12dd06e63119756a3d13b3353e64d22ebb3a117cc50c20ce16507bb3cbd295947eb72278c61ef83e9b1acfea110fa1230dedcd90ede7c21b0cd4324a70ed83' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x1ed02bb4a5bc8d57fd1f6f416f4207d2fd6778bf1fe1a505ee54f9d7bda3cab67360a263360d04cc6dfcc2e7587e50a0e8298069e8904acb302b7ea5a12588dff6f32fb950019d554f58697d09f1555d74800530450b0fae1008ce1e92e32458d43c3bfb58e2753b0439ab0ceec66daa407af154f20b714f24207cef9f664838' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0xb472aa195c472b7210ec7668c40041d818d590007148183972e04cf2cd274528c7b766ac6889ff54008f920ac27b5ff576514f87558217fb94b9494919d795386e4492366288ab5d8fbb4a4bbaf6e27a6c9d994fc9be726a6c50762cc37e3d454d2dce087172586f7e861bd2d5066a76c92e41e923d51e01746798ca0e50757a' + tags: + - atomic + - uint + - wrong_length +- type: uint512 + valid: false + ssz: '0x88807daec4c1bc6698d6baa6663069709b54638406682db48b2736c38332b2efc40eb6963fa438d62f359926f390c0936b4c225693a1f3b25d01a01eead62192b3cac5256452f13cf96e451d5edb873bdd6044e8323187280a6de9c8f525399492bdada618e1eb7226586b488d32d14f335ddb3247cc311785c26510e282f52f' + tags: + - atomic + - uint + - wrong_length From 8f4a2fbde1cb53a90d98c17f7abbf3e363246d02 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 6 Mar 2019 14:46:12 +1100 Subject: [PATCH 006/106] Implement transaction pool basics --- Cargo.toml | 1 + eth2/operation_pool/Cargo.toml | 9 + eth2/operation_pool/src/lib.rs | 308 ++++++++++++++++++ .../src/per_block_processing.rs | 11 +- .../src/per_block_processing/errors.rs | 5 + .../per_block_processing/verify_deposit.rs | 6 +- .../src/per_block_processing/verify_exit.rs | 8 +- .../per_block_processing/verify_transfer.rs | 38 ++- eth2/types/Cargo.toml | 1 + eth2/types/src/transfer.rs | 5 +- 10 files changed, 377 insertions(+), 15 deletions(-) create mode 100644 eth2/operation_pool/Cargo.toml create mode 100644 eth2/operation_pool/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index cb070cc2d..00be99e32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "eth2/attester", "eth2/block_proposer", "eth2/fork_choice", + "eth2/operation_pool", "eth2/state_processing", "eth2/types", "eth2/utils/bls", diff --git a/eth2/operation_pool/Cargo.toml b/eth2/operation_pool/Cargo.toml new file mode 100644 index 000000000..e68d318b5 --- /dev/null +++ b/eth2/operation_pool/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "operation_pool" +version = "0.1.0" +authors = ["Michael Sproul "] +edition = "2018" + +[dependencies] +types = { path = "../types" } +state_processing = { path = "../../eth2/state_processing" } diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs new file mode 100644 index 000000000..7c2525099 --- /dev/null +++ b/eth2/operation_pool/src/lib.rs @@ -0,0 +1,308 @@ +use std::collections::{btree_map::Entry, BTreeMap, HashSet}; + +use state_processing::per_block_processing::{ + verify_deposit_merkle_proof, verify_exit, verify_proposer_slashing, verify_transfer, + verify_transfer_partial, +}; +use types::{ + AttesterSlashing, BeaconState, ChainSpec, Deposit, ProposerSlashing, Transfer, VoluntaryExit, +}; + +#[cfg(test)] +const VERIFY_DEPOSIT_PROOFS: bool = false; +#[cfg(not(test))] +const VERIFY_DEPOSIT_PROOFS: bool = true; + +#[derive(Default)] +pub struct OperationPool { + /// Map from deposit index to deposit data. + // NOTE: We assume that there is only one deposit per index + // because the Eth1 data is updated (at most) once per epoch, + // and the spec doesn't seem to accomodate for re-orgs on a time-frame + // longer than an epoch + deposits: BTreeMap, + /// Map from attester index to slashing. + attester_slashings: BTreeMap, + /// Map from proposer index to slashing. + proposer_slashings: BTreeMap, + /// Map from exiting validator to their exit data. + voluntary_exits: BTreeMap, + /// Set of transfers. + transfers: HashSet, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum DepositInsertStatus { + /// The deposit was not already in the pool. + Fresh, + /// The deposit already existed in the pool. + Duplicate, + /// The deposit conflicted with an existing deposit, which was replaced. + Replaced(Deposit), +} + +impl OperationPool { + /// Create a new operation pool. + pub fn new() -> Self { + Self::default() + } + + /// Add a deposit to the pool. + /// + /// No two distinct deposits should be added with the same index. + pub fn insert_deposit(&mut self, deposit: Deposit) -> DepositInsertStatus { + use DepositInsertStatus::*; + + match self.deposits.entry(deposit.index) { + Entry::Vacant(entry) => { + entry.insert(deposit); + Fresh + } + Entry::Occupied(mut entry) => { + if entry.get() == &deposit { + Duplicate + } else { + Replaced(entry.insert(deposit)) + } + } + } + } + + /// Get an ordered list of deposits for inclusion in a block. + /// + /// Take at most the maximum number of deposits, beginning from the current deposit index. + pub fn get_deposits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { + let start_idx = state.deposit_index; + (start_idx..start_idx + spec.max_deposits) + .map(|idx| self.deposits.get(&idx)) + .take_while(|deposit| { + // NOTE: we don't use verify_deposit, because it requires the + // deposit's index to match the state's, and we would like to return + // a batch with increasing indices + deposit.map_or(false, |deposit| { + !VERIFY_DEPOSIT_PROOFS || verify_deposit_merkle_proof(state, deposit, spec) + }) + }) + .flatten() + .cloned() + .collect() + } + + /// Remove all deposits with index less than the deposit index of the latest finalised block. + pub fn prune_deposits(&mut self, state: &BeaconState) -> BTreeMap { + let deposits_keep = self.deposits.split_off(&state.deposit_index); + std::mem::replace(&mut self.deposits, deposits_keep) + } + + /// Insert a proposer slashing into the pool. + pub fn insert_proposer_slashing( + &mut self, + slashing: ProposerSlashing, + state: &BeaconState, + spec: &ChainSpec, + ) -> Result<(), ()> { + // TODO: should maybe insert anyway if the proposer is unknown in the validator index, + // because they could *become* known later + // FIXME: error handling + verify_proposer_slashing(&slashing, state, spec).map_err(|_| ())?; + self.proposer_slashings + .insert(slashing.proposer_index, slashing); + Ok(()) + } + + /// Only check whether the implicated validator has already been slashed, because + /// all slashings in the pool were validated upon insertion. + // TODO: we need a mechanism to avoid including a proposer slashing and an attester + // slashing for the same validator in the same block + pub fn get_proposer_slashings( + &self, + state: &BeaconState, + spec: &ChainSpec, + ) -> Vec { + // We sort by validator index, which is safe, because a validator can only supply + // so many valid slashings for lower-indexed validators (and even that is unlikely) + filter_limit_operations( + self.proposer_slashings.values(), + |slashing| { + state + .validator_registry + .get(slashing.proposer_index as usize) + .map_or(false, |validator| !validator.slashed) + }, + spec.max_proposer_slashings, + ) + } + + /// Prune slashings for all slashed or withdrawn validators. + pub fn prune_proposer_slashings(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { + let to_prune = self + .proposer_slashings + .keys() + .flat_map(|&validator_index| { + finalized_state + .validator_registry + .get(validator_index as usize) + .filter(|validator| { + validator.slashed + || validator.is_withdrawable_at(finalized_state.current_epoch(spec)) + }) + .map(|_| validator_index) + }) + .collect::>(); + + for validator_index in to_prune { + self.proposer_slashings.remove(&validator_index); + } + } + + // TODO: copy ProposerSlashing code for AttesterSlashing + + /// Insert a voluntary exit, validating it almost-entirely (future exits are permitted). + pub fn insert_voluntary_exit( + &mut self, + exit: VoluntaryExit, + state: &BeaconState, + spec: &ChainSpec, + ) -> Result<(), ()> { + verify_exit(state, &exit, spec, false).map_err(|_| ())?; + self.voluntary_exits.insert(exit.validator_index, exit); + Ok(()) + } + + /// Get a list of voluntary exits for inclusion in a block. + // TODO: could optimise this by eliding the checks that have already been done on insert + pub fn get_voluntary_exits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { + filter_limit_operations( + self.voluntary_exits.values(), + |exit| verify_exit(state, exit, spec, true).is_ok(), + spec.max_voluntary_exits, + ) + } + + /// Prune if validator has already exited at the last finalized state. + pub fn prune_voluntary_exits(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { + let to_prune = self + .voluntary_exits + .keys() + .flat_map(|&validator_index| { + finalized_state + .validator_registry + .get(validator_index as usize) + .filter(|validator| validator.is_exited_at(finalized_state.current_epoch(spec))) + .map(|_| validator_index) + }) + .collect::>(); + + for validator_index in to_prune { + self.voluntary_exits.remove(&validator_index); + } + } + + /// Insert a transfer into the pool, checking it for validity in the process. + pub fn insert_transfer( + &mut self, + transfer: Transfer, + state: &BeaconState, + spec: &ChainSpec, + ) -> Result<(), ()> { + // The signature of the transfer isn't hashed, but because we check + // it before we insert into the HashSet, we can't end up with duplicate + // transactions. + verify_transfer_partial(state, &transfer, spec, true).map_err(|_| ())?; + self.transfers.insert(transfer); + Ok(()) + } + + /// Get a list of transfers for inclusion in a block. + // TODO: improve the economic optimality of this function by taking the transfer + // fees into account, and dependencies between transfers in the same block + // e.g. A pays B, B pays C + pub fn get_transfers(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { + filter_limit_operations( + &self.transfers, + |transfer| verify_transfer(state, transfer, spec).is_ok(), + spec.max_transfers, + ) + } + + /// Prune the set of transfers by removing all those whose slot has already passed. + pub fn prune_transfers(&mut self, finalized_state: &BeaconState) { + self.transfers = self + .transfers + .drain() + .filter(|transfer| transfer.slot > finalized_state.slot) + .collect(); + } +} + +/// Filter up to a maximum number of operations out of a slice. +fn filter_limit_operations<'a, T: 'a, I, F>(operations: I, filter: F, limit: u64) -> Vec +where + I: IntoIterator, + F: Fn(&T) -> bool, + T: Clone, +{ + operations + .into_iter() + .filter(|x| filter(*x)) + .take(limit as usize) + .cloned() + .collect() +} + +#[cfg(test)] +mod tests { + use super::DepositInsertStatus::*; + use super::*; + use types::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + + #[test] + fn insert_deposit() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let mut op_pool = OperationPool::new(); + let deposit1 = Deposit::random_for_test(&mut rng); + let mut deposit2 = Deposit::random_for_test(&mut rng); + deposit2.index = deposit1.index; + + assert_eq!(op_pool.insert_deposit(deposit1.clone()), Fresh); + assert_eq!(op_pool.insert_deposit(deposit1.clone()), Duplicate); + assert_eq!(op_pool.insert_deposit(deposit2), Replaced(deposit1)); + } + + #[test] + fn get_deposits_max() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let mut op_pool = OperationPool::new(); + let spec = ChainSpec::foundation(); + let start = 10000; + let max_deposits = spec.max_deposits; + let extra = 5; + let offset = 1; + assert!(offset <= extra); + + let proto_deposit = Deposit::random_for_test(&mut rng); + let deposits = (start..start + max_deposits + extra) + .map(|index| { + let mut deposit = proto_deposit.clone(); + deposit.index = index; + deposit + }) + .collect::>(); + + for deposit in &deposits { + assert_eq!(op_pool.insert_deposit(deposit.clone()), Fresh); + } + + let mut state = BeaconState::random_for_test(&mut rng); + state.deposit_index = start + offset; + let deposits_for_block = op_pool.get_deposits(&state, &spec); + + assert_eq!(deposits_for_block.len() as u64, max_deposits); + assert_eq!( + deposits_for_block[..], + deposits[offset as usize..(offset + max_deposits) as usize] + ); + } + + // TODO: more tests +} diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index dc83abb3f..e0e359552 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -1,4 +1,3 @@ -use self::verify_proposer_slashing::verify_proposer_slashing; use crate::common::slash_validator; use errors::{BlockInvalid as Invalid, BlockProcessingError as Error, IntoWithIndex}; use rayon::prelude::*; @@ -8,11 +7,15 @@ use types::*; pub use self::verify_attester_slashing::{ gather_attester_slashing_indices, verify_attester_slashing, }; +pub use self::verify_proposer_slashing::verify_proposer_slashing; pub use validate_attestation::{validate_attestation, validate_attestation_without_signature}; -pub use verify_deposit::{get_existing_validator_index, verify_deposit, verify_deposit_index}; +pub use verify_deposit::{ + get_existing_validator_index, verify_deposit, verify_deposit_index, + verify_deposit_merkle_proof, +}; pub use verify_exit::verify_exit; pub use verify_slashable_attestation::verify_slashable_attestation; -pub use verify_transfer::{execute_transfer, verify_transfer}; +pub use verify_transfer::{execute_transfer, verify_transfer, verify_transfer_partial}; pub mod errors; mod validate_attestation; @@ -426,7 +429,7 @@ pub fn process_exits( .par_iter() .enumerate() .try_for_each(|(i, exit)| { - verify_exit(&state, exit, spec).map_err(|e| e.into_with_index(i)) + verify_exit(&state, exit, spec, true).map_err(|e| e.into_with_index(i)) })?; // Update the state in series. diff --git a/eth2/state_processing/src/per_block_processing/errors.rs b/eth2/state_processing/src/per_block_processing/errors.rs index c0fe252de..6614f6f60 100644 --- a/eth2/state_processing/src/per_block_processing/errors.rs +++ b/eth2/state_processing/src/per_block_processing/errors.rs @@ -390,6 +390,11 @@ pub enum TransferInvalid { /// /// (state_slot, transfer_slot) StateSlotMismatch(Slot, Slot), + /// The `transfer.slot` is in the past relative to the state slot. + /// + /// + /// (state_slot, transfer_slot) + TransferSlotInPast(Slot, Slot), /// The `transfer.from` validator has been activated and is not withdrawable. /// /// (from_validator) diff --git a/eth2/state_processing/src/per_block_processing/verify_deposit.rs b/eth2/state_processing/src/per_block_processing/verify_deposit.rs index a3a0f5734..1b974d972 100644 --- a/eth2/state_processing/src/per_block_processing/verify_deposit.rs +++ b/eth2/state_processing/src/per_block_processing/verify_deposit.rs @@ -89,7 +89,11 @@ pub fn get_existing_validator_index( /// Verify that a deposit is included in the state's eth1 deposit root. /// /// Spec v0.5.0 -fn verify_deposit_merkle_proof(state: &BeaconState, deposit: &Deposit, spec: &ChainSpec) -> bool { +pub fn verify_deposit_merkle_proof( + state: &BeaconState, + deposit: &Deposit, + spec: &ChainSpec, +) -> bool { let leaf = hash(&get_serialized_deposit_data(deposit)); verify_merkle_proof( Hash256::from_slice(&leaf), diff --git a/eth2/state_processing/src/per_block_processing/verify_exit.rs b/eth2/state_processing/src/per_block_processing/verify_exit.rs index 7893cea96..14dad3442 100644 --- a/eth2/state_processing/src/per_block_processing/verify_exit.rs +++ b/eth2/state_processing/src/per_block_processing/verify_exit.rs @@ -7,11 +7,17 @@ use types::*; /// /// Returns `Ok(())` if the `Exit` is valid, otherwise indicates the reason for invalidity. /// +/// The `check_future_epoch` argument determines whether the exit's epoch should be checked +/// against the state's current epoch to ensure it doesn't occur in the future. +/// It should ordinarily be set to true, except for operations stored for +/// some time (such as in the OperationPool). +/// /// Spec v0.5.0 pub fn verify_exit( state: &BeaconState, exit: &VoluntaryExit, spec: &ChainSpec, + check_future_epoch: bool, ) -> Result<(), Error> { let validator = state .validator_registry @@ -32,7 +38,7 @@ pub fn verify_exit( // Exits must specify an epoch when they become valid; they are not valid before then. verify!( - state.current_epoch(spec) >= exit.epoch, + !check_future_epoch || state.current_epoch(spec) >= exit.epoch, Invalid::FutureEpoch { state: state.current_epoch(spec), exit: exit.epoch diff --git a/eth2/state_processing/src/per_block_processing/verify_transfer.rs b/eth2/state_processing/src/per_block_processing/verify_transfer.rs index f873cd850..4f3815797 100644 --- a/eth2/state_processing/src/per_block_processing/verify_transfer.rs +++ b/eth2/state_processing/src/per_block_processing/verify_transfer.rs @@ -15,6 +15,19 @@ pub fn verify_transfer( state: &BeaconState, transfer: &Transfer, spec: &ChainSpec, +) -> Result<(), Error> { + verify_transfer_partial(state, transfer, spec, false) +} + +/// Parametric version of `verify_transfer` that allows some checks to be skipped. +/// +/// In everywhere except the operation pool, `verify_transfer` should be preferred over this +/// function. +pub fn verify_transfer_partial( + state: &BeaconState, + transfer: &Transfer, + spec: &ChainSpec, + for_op_pool: bool, ) -> Result<(), Error> { let sender_balance = *state .validator_balances @@ -27,17 +40,18 @@ pub fn verify_transfer( .ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?; verify!( - sender_balance >= transfer.amount, + for_op_pool || sender_balance >= transfer.amount, Invalid::FromBalanceInsufficient(transfer.amount, sender_balance) ); verify!( - sender_balance >= transfer.fee, + for_op_pool || sender_balance >= transfer.fee, Invalid::FromBalanceInsufficient(transfer.fee, sender_balance) ); verify!( - (sender_balance == total_amount) + for_op_pool + || (sender_balance == total_amount) || (sender_balance >= (total_amount + spec.min_deposit_amount)), Invalid::InvalidResultingFromBalance( sender_balance - total_amount, @@ -45,10 +59,17 @@ pub fn verify_transfer( ) ); - verify!( - state.slot == transfer.slot, - Invalid::StateSlotMismatch(state.slot, transfer.slot) - ); + if for_op_pool { + verify!( + state.slot <= transfer.slot, + Invalid::TransferSlotInPast(state.slot, transfer.slot) + ); + } else { + verify!( + state.slot == transfer.slot, + Invalid::StateSlotMismatch(state.slot, transfer.slot) + ); + } let sender_validator = state .validator_registry @@ -57,7 +78,8 @@ pub fn verify_transfer( let epoch = state.slot.epoch(spec.slots_per_epoch); verify!( - sender_validator.is_withdrawable_at(epoch) + for_op_pool + || sender_validator.is_withdrawable_at(epoch) || sender_validator.activation_epoch == spec.far_future_epoch, Invalid::FromValidatorIneligableForTransfer(transfer.sender) ); diff --git a/eth2/types/Cargo.toml b/eth2/types/Cargo.toml index e4ccfd63e..8554b5c54 100644 --- a/eth2/types/Cargo.toml +++ b/eth2/types/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" bls = { path = "../utils/bls" } boolean-bitfield = { path = "../utils/boolean-bitfield" } dirs = "1.0" +derivative = "1.0" ethereum-types = "0.5" hashing = { path = "../utils/hashing" } hex = "0.3" diff --git a/eth2/types/src/transfer.rs b/eth2/types/src/transfer.rs index 2570d7b3f..4b10ce1ca 100644 --- a/eth2/types/src/transfer.rs +++ b/eth2/types/src/transfer.rs @@ -1,6 +1,7 @@ use super::Slot; use crate::test_utils::TestRandom; use bls::{PublicKey, Signature}; +use derivative::Derivative; use rand::RngCore; use serde_derive::{Deserialize, Serialize}; use ssz::TreeHash; @@ -12,7 +13,6 @@ use test_random_derive::TestRandom; /// Spec v0.5.0 #[derive( Debug, - PartialEq, Clone, Serialize, Deserialize, @@ -21,7 +21,9 @@ use test_random_derive::TestRandom; TreeHash, TestRandom, SignedRoot, + Derivative, )] +#[derivative(PartialEq, Eq, Hash)] pub struct Transfer { pub sender: u64, pub recipient: u64, @@ -29,6 +31,7 @@ pub struct Transfer { pub fee: u64, pub slot: Slot, pub pubkey: PublicKey, + #[derivative(Hash = "ignore")] pub signature: Signature, } From c2e5d3c45a5adf40c51206e7b04f1199986823ca Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 19 Mar 2019 10:22:14 +1100 Subject: [PATCH 007/106] BLS: fix description of AggregatePublicKey --- eth2/utils/bls/src/aggregate_public_key.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth2/utils/bls/src/aggregate_public_key.rs b/eth2/utils/bls/src/aggregate_public_key.rs index 2174a43cb..2e6ee7882 100644 --- a/eth2/utils/bls/src/aggregate_public_key.rs +++ b/eth2/utils/bls/src/aggregate_public_key.rs @@ -1,7 +1,7 @@ use super::PublicKey; use bls_aggregates::AggregatePublicKey as RawAggregatePublicKey; -/// A single BLS signature. +/// A BLS aggregate public key. /// /// This struct is a wrapper upon a base type and provides helper functions (e.g., SSZ /// serialization). @@ -17,7 +17,7 @@ impl AggregatePublicKey { self.0.add(public_key.as_raw()) } - /// Returns the underlying signature. + /// Returns the underlying public key. pub fn as_raw(&self) -> &RawAggregatePublicKey { &self.0 } From 1fca8a063c0118e84c82b69a8d800d109c65861b Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 19 Mar 2019 19:15:33 +1100 Subject: [PATCH 008/106] Operation pool: add attestation support --- eth2/operation_pool/Cargo.toml | 5 +- eth2/operation_pool/src/lib.rs | 128 +++++++++++++++++++++++++++++++-- eth2/types/src/attestation.rs | 19 +++++ 3 files changed, 146 insertions(+), 6 deletions(-) diff --git a/eth2/operation_pool/Cargo.toml b/eth2/operation_pool/Cargo.toml index e68d318b5..07cb61864 100644 --- a/eth2/operation_pool/Cargo.toml +++ b/eth2/operation_pool/Cargo.toml @@ -5,5 +5,8 @@ authors = ["Michael Sproul "] edition = "2018" [dependencies] +int_to_bytes = { path = "../utils/int_to_bytes" } +itertools = "0.8" types = { path = "../types" } -state_processing = { path = "../../eth2/state_processing" } +state_processing = { path = "../state_processing" } +ssz = { path = "../utils/ssz" } diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 7c2525099..7a647450c 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -1,11 +1,15 @@ -use std::collections::{btree_map::Entry, BTreeMap, HashSet}; - +use int_to_bytes::int_to_bytes8; +use itertools::Itertools; +use ssz::ssz_encode; use state_processing::per_block_processing::{ - verify_deposit_merkle_proof, verify_exit, verify_proposer_slashing, verify_transfer, - verify_transfer_partial, + validate_attestation, verify_deposit_merkle_proof, verify_exit, verify_proposer_slashing, + verify_transfer, verify_transfer_partial, }; +use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet}; +use types::chain_spec::Domain; use types::{ - AttesterSlashing, BeaconState, ChainSpec, Deposit, ProposerSlashing, Transfer, VoluntaryExit, + Attestation, AttestationData, AttesterSlashing, BeaconState, ChainSpec, Deposit, Epoch, + ProposerSlashing, Transfer, VoluntaryExit, }; #[cfg(test)] @@ -15,6 +19,8 @@ const VERIFY_DEPOSIT_PROOFS: bool = true; #[derive(Default)] pub struct OperationPool { + /// Map from attestation ID (see below) to vectors of attestations. + attestations: HashMap>, /// Map from deposit index to deposit data. // NOTE: We assume that there is only one deposit per index // because the Eth1 data is updated (at most) once per epoch, @@ -31,6 +37,54 @@ pub struct OperationPool { transfers: HashSet, } +/// Serialized `AttestationData` augmented with a domain to encode the fork info. +#[derive(PartialEq, Eq, Clone, Hash, Debug)] +struct AttestationId(Vec); + +/// Number of domain bytes that the end of an attestation ID is padded with. +const DOMAIN_BYTES_LEN: usize = 8; + +impl AttestationId { + fn from_data(attestation: &AttestationData, state: &BeaconState, spec: &ChainSpec) -> Self { + let mut bytes = ssz_encode(attestation); + let epoch = attestation.slot.epoch(spec.slots_per_epoch); + bytes.extend_from_slice(&AttestationId::compute_domain_bytes(epoch, state, spec)); + AttestationId(bytes) + } + + fn compute_domain_bytes(epoch: Epoch, state: &BeaconState, spec: &ChainSpec) -> Vec { + int_to_bytes8(spec.get_domain(epoch, Domain::Attestation, &state.fork)) + } + + fn domain_bytes_match(&self, domain_bytes: &[u8]) -> bool { + &self.0[self.0.len() - DOMAIN_BYTES_LEN..] == domain_bytes + } +} + +/// Compute a fitness score for an attestation. +/// +/// The score is calculated by determining the number of *new* attestations that +/// the aggregate attestation introduces, and is proportional to the size of the reward we will +/// receive for including it in a block. +// TODO: this could be optimised with a map from validator index to whether that validator has +// attested in the *current* epoch. Alternatively, we could cache an index that allows us to +// quickly look up the attestations in the current epoch for a given shard. +fn attestation_score(attestation: &Attestation, state: &BeaconState) -> usize { + // Bitfield of validators whose attestations are new/fresh. + let mut new_validators = attestation.aggregation_bitfield.clone(); + + state + .current_epoch_attestations + .iter() + .filter(|current_attestation| current_attestation.data.shard == attestation.data.shard) + .for_each(|current_attestation| { + // Remove the validators who have signed the existing attestation (they are not new) + new_validators.difference_inplace(¤t_attestation.aggregation_bitfield); + }); + + new_validators.num_set_bits() +} + #[derive(Debug, PartialEq, Clone)] pub enum DepositInsertStatus { /// The deposit was not already in the pool. @@ -47,6 +101,70 @@ impl OperationPool { Self::default() } + /// Insert an attestation into the pool, aggregating it with existing attestations if possible. + pub fn insert_attestation( + &mut self, + attestation: Attestation, + state: &BeaconState, + spec: &ChainSpec, + ) -> Result<(), ()> { + // Check that attestation signatures are valid. + // FIXME: should disable the time-dependent checks. + validate_attestation(state, &attestation, spec).map_err(|_| ())?; + + let id = AttestationId::from_data(&attestation.data, state, spec); + + let existing_attestations = match self.attestations.entry(id) { + hash_map::Entry::Vacant(entry) => { + entry.insert(vec![attestation]); + return Ok(()); + } + hash_map::Entry::Occupied(entry) => entry.into_mut(), + }; + + let mut aggregated = false; + for existing_attestation in existing_attestations.iter_mut() { + if existing_attestation.signers_disjoint_from(&attestation) { + existing_attestation.aggregate(&attestation); + aggregated = true; + } else if *existing_attestation == attestation { + aggregated = true; + } + } + + if !aggregated { + existing_attestations.push(attestation); + } + + Ok(()) + } + + /// Get a list of attestations for inclusion in a block. + pub fn get_attestations(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { + // Attestations for the current fork... + // TODO: should we also check domain bytes for the previous epoch? + let current_epoch = state.slot.epoch(spec.slots_per_epoch); + let domain_bytes = AttestationId::compute_domain_bytes(current_epoch, state, spec); + self.attestations + .iter() + .filter(|(key, _)| key.domain_bytes_match(&domain_bytes)) + .flat_map(|(_, attestations)| attestations) + // That are valid... + .filter(|attestation| validate_attestation(state, attestation, spec).is_ok()) + // Scored by the number of new attestations they introduce (descending) + .map(|att| (att, attestation_score(att, state))) + .sorted_by_key(|&(_, score)| std::cmp::Reverse(score)) + // Limited to the maximum number of attestations per block + .take(spec.max_attestations as usize) + .map(|(att, _)| att) + .cloned() + .collect() + } + + pub fn prune_attestations(&self, _finalized_state: &BeaconState, _spec: &ChainSpec) { + // TODO + } + /// Add a deposit to the pool. /// /// No two distinct deposits should be added with the same index. diff --git a/eth2/types/src/attestation.rs b/eth2/types/src/attestation.rs index 0b660466e..6c572c852 100644 --- a/eth2/types/src/attestation.rs +++ b/eth2/types/src/attestation.rs @@ -28,6 +28,25 @@ pub struct Attestation { pub aggregate_signature: AggregateSignature, } +impl Attestation { + /// Are the aggregation bitfields of these attestations disjoint? + pub fn signers_disjoint_from(&self, other: &Attestation) -> bool { + self.aggregation_bitfield.intersection(&other.aggregation_bitfield).is_zero() + } + + /// Aggregate another Attestation into this one. + /// + /// The aggregation bitfields must be disjoint, and the data must be the same. + pub fn aggregate(&mut self, other: &Attestation) { + debug_assert_eq!(self.data, other.data); + debug_assert!(self.signers_disjoint_from(other)); + + self.aggregation_bitfield.union_inplace(&other.aggregation_bitfield); + self.custody_bitfield.union_inplace(&other.custody_bitfield); + // FIXME: signature aggregation once our BLS library wraps it + } +} + #[cfg(test)] mod tests { use super::*; From 18a7bd243c1d5fe865ef954d3fc799f6d5b9cab7 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 19 Mar 2019 19:18:33 +1100 Subject: [PATCH 009/106] Bitfield: implement union/intersection/difference --- eth2/utils/boolean-bitfield/src/lib.rs | 92 ++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index 443cd06da..e37f2488d 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -89,6 +89,11 @@ impl BooleanBitfield { self.len() == 0 } + /// Returns true if all bits are set to 0. + pub fn is_zero(&self) -> bool { + self.0.none() + } + /// Returns the number of bytes required to represent this bitfield. pub fn num_bytes(&self) -> usize { self.to_bytes().len() @@ -104,6 +109,44 @@ impl BooleanBitfield { pub fn to_bytes(&self) -> Vec { self.0.to_bytes() } + + /// Compute the intersection (binary-and) of this bitfield with another. Lengths must match. + pub fn intersection(&self, other: &Self) -> Self { + let mut res = self.clone(); + res.intersection_inplace(other); + res + } + + /// Like `intersection` but in-place (updates `self`). + pub fn intersection_inplace(&mut self, other: &Self) { + self.0.intersect(&other.0); + } + + /// Compute the union (binary-or) of this bitfield with another. Lengths must match. + pub fn union(&self, other: &Self) -> Self { + let mut res = self.clone(); + res.union_inplace(other); + res + } + + /// Like `union` but in-place (updates `self`). + pub fn union_inplace(&mut self, other: &Self) { + self.0.union(&other.0); + } + + /// Compute the difference (binary-minus) of this bitfield with another. Lengths must match. + /// + /// Computes `self - other`. + pub fn difference(&self, other: &Self) -> Self { + let mut res = self.clone(); + res.difference_inplace(other); + res + } + + /// Like `difference` but in-place (updates `self`). + pub fn difference_inplace(&mut self, other: &Self) { + self.0.difference(&other.0); + } } impl default::Default for BooleanBitfield { @@ -427,4 +470,53 @@ mod tests { let c = BooleanBitfield::from_bytes(&vec![6, 8, 17][..]); assert_eq!(c, a & b); } + + #[test] + fn test_is_zero() { + let yes_data: &[&[u8]] = &[&[], &[0], &[0, 0], &[0, 0, 0]]; + for bytes in yes_data { + assert!(BooleanBitfield::from_bytes(bytes).is_zero()); + } + let no_data: &[&[u8]] = &[&[1], &[6], &[0, 1], &[0, 0, 1], &[0, 0, 255]]; + for bytes in no_data { + assert!(!BooleanBitfield::from_bytes(bytes).is_zero()); + } + } + + #[test] + fn test_intersection() { + let a = BooleanBitfield::from_bytes(&[0b1100, 0b0001]); + let b = BooleanBitfield::from_bytes(&[0b1011, 0b1001]); + let c = BooleanBitfield::from_bytes(&[0b1000, 0b0001]); + assert_eq!(a.intersection(&b), c); + assert_eq!(b.intersection(&a), c); + assert_eq!(a.intersection(&c), c); + assert_eq!(b.intersection(&c), c); + assert_eq!(a.intersection(&a), a); + assert_eq!(b.intersection(&b), b); + assert_eq!(c.intersection(&c), c); + } + + #[test] + fn test_union() { + let a = BooleanBitfield::from_bytes(&[0b1100, 0b0001]); + let b = BooleanBitfield::from_bytes(&[0b1011, 0b1001]); + let c = BooleanBitfield::from_bytes(&[0b1111, 0b1001]); + assert_eq!(a.union(&b), c); + assert_eq!(b.union(&a), c); + assert_eq!(a.union(&a), a); + assert_eq!(b.union(&b), b); + assert_eq!(c.union(&c), c); + } + + #[test] + fn test_difference() { + let a = BooleanBitfield::from_bytes(&[0b1100, 0b0001]); + let b = BooleanBitfield::from_bytes(&[0b1011, 0b1001]); + let a_b = BooleanBitfield::from_bytes(&[0b0100, 0b0000]); + let b_a = BooleanBitfield::from_bytes(&[0b0011, 0b1000]); + assert_eq!(a.difference(&b), a_b); + assert_eq!(b.difference(&a), b_a); + assert!(a.difference(&a).is_zero()); + } } From 8a7c51271ed06e75fc0f45894a54ab489b2561bc Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 19 Mar 2019 19:19:21 +1100 Subject: [PATCH 010/106] Bitfield: use BitOr instead of BitAnd for union Closes #314 --- eth2/utils/boolean-bitfield/src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index e37f2488d..cdd0bc3d7 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -168,10 +168,11 @@ impl cmp::PartialEq for BooleanBitfield { /// Create a new bitfield that is a union of two other bitfields. /// /// For example `union(0101, 1000) == 1101` -impl std::ops::BitAnd for BooleanBitfield { +// TODO: length-independent intersection for BitAnd +impl std::ops::BitOr for BooleanBitfield { type Output = Self; - fn bitand(self, other: Self) -> Self { + fn bitor(self, other: Self) -> Self { let (biggest, smallest) = if self.len() > other.len() { (&self, &other) } else { @@ -464,11 +465,11 @@ mod tests { } #[test] - fn test_bitand() { + fn test_bitor() { let a = BooleanBitfield::from_bytes(&vec![2, 8, 1][..]); let b = BooleanBitfield::from_bytes(&vec![4, 8, 16][..]); let c = BooleanBitfield::from_bytes(&vec![6, 8, 17][..]); - assert_eq!(c, a & b); + assert_eq!(c, a | b); } #[test] From a8224aa4ec05fe467abaf21d7b1a6f1a9239f584 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 20 Mar 2019 10:14:31 +1100 Subject: [PATCH 011/106] Operation pool: add prune_all --- eth2/operation_pool/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 7a647450c..93ff74652 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -351,6 +351,16 @@ impl OperationPool { .filter(|transfer| transfer.slot > finalized_state.slot) .collect(); } + + /// Prune all types of transactions given the latest finalized state. + pub fn prune_all(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { + self.prune_attestations(finalized_state, spec); + self.prune_deposits(finalized_state); + self.prune_proposer_slashings(finalized_state, spec); + // FIXME: add attester slashings + self.prune_voluntary_exits(finalized_state, spec); + self.prune_transfers(finalized_state); + } } /// Filter up to a maximum number of operations out of a slice. From 9c2dfba843c2210df161537f186eb87cb3c18bda Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 20 Mar 2019 10:47:19 +1100 Subject: [PATCH 012/106] Operation pool: prune attestations --- eth2/operation_pool/src/lib.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 93ff74652..4932a7e0a 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -161,8 +161,18 @@ impl OperationPool { .collect() } - pub fn prune_attestations(&self, _finalized_state: &BeaconState, _spec: &ChainSpec) { - // TODO + /// Remove attestations which are too old to be included in a block. + // TODO: we could probably prune other attestations here: + // - ones that are completely covered by attestations included in the state + // - maybe ones invalidated by the confirmation of one fork over another + pub fn prune_attestations(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { + self.attestations.retain(|_, attestations| { + // All the attestations in this bucket have the same data, so we only need to + // check the first one. + attestations.first().map_or(false, |att| { + finalized_state.slot < att.data.slot + spec.slots_per_epoch + }) + }); } /// Add a deposit to the pool. From 05dd936a97fbcc837e74ba35fc6e5972f7cadac2 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 20 Mar 2019 12:44:37 +1100 Subject: [PATCH 013/106] Operation pool: deposit pruning tests --- eth2/operation_pool/src/lib.rs | 91 ++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 4932a7e0a..938a3db0c 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -1,6 +1,7 @@ use int_to_bytes::int_to_bytes8; use itertools::Itertools; use ssz::ssz_encode; +use state_processing::per_block_processing::errors::ProposerSlashingValidationError; use state_processing::per_block_processing::{ validate_attestation, verify_deposit_merkle_proof, verify_exit, verify_proposer_slashing, verify_transfer, verify_transfer_partial, @@ -92,7 +93,7 @@ pub enum DepositInsertStatus { /// The deposit already existed in the pool. Duplicate, /// The deposit conflicted with an existing deposit, which was replaced. - Replaced(Deposit), + Replaced(Box), } impl OperationPool { @@ -190,7 +191,7 @@ impl OperationPool { if entry.get() == &deposit { Duplicate } else { - Replaced(entry.insert(deposit)) + Replaced(Box::new(entry.insert(deposit))) } } } @@ -222,17 +223,21 @@ impl OperationPool { std::mem::replace(&mut self.deposits, deposits_keep) } + /// The number of deposits stored in the pool. + pub fn num_deposits(&self) -> usize { + self.deposits.len() + } + /// Insert a proposer slashing into the pool. pub fn insert_proposer_slashing( &mut self, slashing: ProposerSlashing, state: &BeaconState, spec: &ChainSpec, - ) -> Result<(), ()> { + ) -> Result<(), ProposerSlashingValidationError> { // TODO: should maybe insert anyway if the proposer is unknown in the validator index, // because they could *become* known later - // FIXME: error handling - verify_proposer_slashing(&slashing, state, spec).map_err(|_| ())?; + verify_proposer_slashing(&slashing, state, spec)?; self.proposer_slashings .insert(slashing.proposer_index, slashing); Ok(()) @@ -404,7 +409,22 @@ mod tests { assert_eq!(op_pool.insert_deposit(deposit1.clone()), Fresh); assert_eq!(op_pool.insert_deposit(deposit1.clone()), Duplicate); - assert_eq!(op_pool.insert_deposit(deposit2), Replaced(deposit1)); + assert_eq!( + op_pool.insert_deposit(deposit2), + Replaced(Box::new(deposit1)) + ); + } + + // Create `count` dummy deposits with sequential deposit IDs beginning from `start`. + fn dummy_deposits(rng: &mut XorShiftRng, start: u64, count: u64) -> Vec { + let proto_deposit = Deposit::random_for_test(rng); + (start..start + count) + .map(|index| { + let mut deposit = proto_deposit.clone(); + deposit.index = index; + deposit + }) + .collect() } #[test] @@ -418,14 +438,7 @@ mod tests { let offset = 1; assert!(offset <= extra); - let proto_deposit = Deposit::random_for_test(&mut rng); - let deposits = (start..start + max_deposits + extra) - .map(|index| { - let mut deposit = proto_deposit.clone(); - deposit.index = index; - deposit - }) - .collect::>(); + let deposits = dummy_deposits(&mut rng, start, max_deposits + extra); for deposit in &deposits { assert_eq!(op_pool.insert_deposit(deposit.clone()), Fresh); @@ -442,5 +455,55 @@ mod tests { ); } + #[test] + fn prune_deposits() { + let rng = &mut XorShiftRng::from_seed([42; 16]); + let mut op_pool = OperationPool::new(); + let spec = ChainSpec::foundation(); + + let start1 = 100; + let count = 100; + let gap = 25; + let start2 = start1 + count + gap; + + let deposits1 = dummy_deposits(rng, start1, count); + let deposits2 = dummy_deposits(rng, start2, count); + + for d in deposits1.into_iter().chain(deposits2) { + op_pool.insert_deposit(d); + } + + assert_eq!(op_pool.num_deposits(), 2 * count as usize); + + let mut state = BeaconState::random_for_test(rng); + state.deposit_index = start1; + + // Pruning the first bunch of deposits in batches of 5 should work. + let step = 5; + let mut pool_size = step + 2 * count as usize; + for i in (start1..=(start1 + count)).step_by(step) { + state.deposit_index = i; + op_pool.prune_deposits(&state); + pool_size -= step; + assert_eq!(op_pool.num_deposits(), pool_size); + } + assert_eq!(pool_size, count as usize); + // Pruning in the gap should do nothing. + for i in (start1 + count..start2).step_by(step) { + state.deposit_index = i; + op_pool.prune_deposits(&state); + assert_eq!(op_pool.num_deposits(), count as usize); + } + // Same again for the later deposits. + pool_size += step; + for i in (start2..=(start2 + count)).step_by(step) { + state.deposit_index = i; + op_pool.prune_deposits(&state); + pool_size -= step; + assert_eq!(op_pool.num_deposits(), pool_size); + } + assert_eq!(op_pool.num_deposits(), 0); + } + // TODO: more tests } From 03c01c8a8db8313e8c7de6c6edb41c69eaace4ee Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 20 Mar 2019 13:06:06 +1100 Subject: [PATCH 014/106] Operation pool: HashMap instead of BTreeMap --- eth2/operation_pool/src/lib.rs | 75 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 938a3db0c..c625cdc83 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -10,7 +10,7 @@ use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet}; use types::chain_spec::Domain; use types::{ Attestation, AttestationData, AttesterSlashing, BeaconState, ChainSpec, Deposit, Epoch, - ProposerSlashing, Transfer, VoluntaryExit, + ProposerSlashing, Transfer, Validator, VoluntaryExit, }; #[cfg(test)] @@ -29,11 +29,11 @@ pub struct OperationPool { // longer than an epoch deposits: BTreeMap, /// Map from attester index to slashing. - attester_slashings: BTreeMap, + attester_slashings: HashMap, /// Map from proposer index to slashing. - proposer_slashings: BTreeMap, + proposer_slashings: HashMap, /// Map from exiting validator to their exit data. - voluntary_exits: BTreeMap, + voluntary_exits: HashMap, /// Set of transfers. transfers: HashSet, } @@ -268,24 +268,14 @@ impl OperationPool { /// Prune slashings for all slashed or withdrawn validators. pub fn prune_proposer_slashings(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { - let to_prune = self - .proposer_slashings - .keys() - .flat_map(|&validator_index| { - finalized_state - .validator_registry - .get(validator_index as usize) - .filter(|validator| { - validator.slashed - || validator.is_withdrawable_at(finalized_state.current_epoch(spec)) - }) - .map(|_| validator_index) - }) - .collect::>(); - - for validator_index in to_prune { - self.proposer_slashings.remove(&validator_index); - } + prune_validator_hash_map( + &mut self.proposer_slashings, + |validator| { + validator.slashed + || validator.is_withdrawable_at(finalized_state.current_epoch(spec)) + }, + finalized_state, + ); } // TODO: copy ProposerSlashing code for AttesterSlashing @@ -314,21 +304,11 @@ impl OperationPool { /// Prune if validator has already exited at the last finalized state. pub fn prune_voluntary_exits(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { - let to_prune = self - .voluntary_exits - .keys() - .flat_map(|&validator_index| { - finalized_state - .validator_registry - .get(validator_index as usize) - .filter(|validator| validator.is_exited_at(finalized_state.current_epoch(spec))) - .map(|_| validator_index) - }) - .collect::>(); - - for validator_index in to_prune { - self.voluntary_exits.remove(&validator_index); - } + prune_validator_hash_map( + &mut self.voluntary_exits, + |validator| validator.is_exited_at(finalized_state.current_epoch(spec)), + finalized_state, + ); } /// Insert a transfer into the pool, checking it for validity in the process. @@ -393,6 +373,26 @@ where .collect() } +/// Remove all entries from the given hash map for which `prune_if` returns true. +/// +/// The keys in the map should be validator indices, which will be looked up +/// in the state's validator registry and then passed to `prune_if`. +/// Entries for unknown validators will be kept. +fn prune_validator_hash_map( + map: &mut HashMap, + prune_if: F, + finalized_state: &BeaconState, +) where + F: Fn(&Validator) -> bool, +{ + map.retain(|&validator_index, _| { + finalized_state + .validator_registry + .get(validator_index as usize) + .map_or(true, |validator| !prune_if(validator)) + }); +} + #[cfg(test)] mod tests { use super::DepositInsertStatus::*; @@ -459,7 +459,6 @@ mod tests { fn prune_deposits() { let rng = &mut XorShiftRng::from_seed([42; 16]); let mut op_pool = OperationPool::new(); - let spec = ChainSpec::foundation(); let start1 = 100; let count = 100; From b2fe14e12c23304241a6e57252ced39920f45c5c Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 20 Mar 2019 15:57:41 +1100 Subject: [PATCH 015/106] Operation pool: refactor verify_deposit/exit --- eth2/operation_pool/src/lib.rs | 134 ++++++++++++------ .../src/per_block_processing.rs | 5 +- .../per_block_processing/verify_deposit.rs | 6 +- .../src/per_block_processing/verify_exit.rs | 27 +++- eth2/types/src/attestation.rs | 7 +- 5 files changed, 118 insertions(+), 61 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index c625cdc83..ecf4e41e7 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -3,8 +3,8 @@ use itertools::Itertools; use ssz::ssz_encode; use state_processing::per_block_processing::errors::ProposerSlashingValidationError; use state_processing::per_block_processing::{ - validate_attestation, verify_deposit_merkle_proof, verify_exit, verify_proposer_slashing, - verify_transfer, verify_transfer_partial, + validate_attestation, verify_deposit, verify_exit, verify_exit_time_independent_only, + verify_proposer_slashing, verify_transfer, verify_transfer_partial, }; use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet}; use types::chain_spec::Domain; @@ -179,19 +179,27 @@ impl OperationPool { /// Add a deposit to the pool. /// /// No two distinct deposits should be added with the same index. - pub fn insert_deposit(&mut self, deposit: Deposit) -> DepositInsertStatus { + pub fn insert_deposit( + &mut self, + deposit: Deposit, + state: &BeaconState, + spec: &ChainSpec, + ) -> Result { use DepositInsertStatus::*; match self.deposits.entry(deposit.index) { Entry::Vacant(entry) => { + // FIXME: error prop + verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec).map_err(|_| ())?; entry.insert(deposit); - Fresh + Ok(Fresh) } Entry::Occupied(mut entry) => { if entry.get() == &deposit { - Duplicate + Ok(Duplicate) } else { - Replaced(Box::new(entry.insert(deposit))) + verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec).map_err(|_| ())?; + Ok(Replaced(Box::new(entry.insert(deposit)))) } } } @@ -204,14 +212,7 @@ impl OperationPool { let start_idx = state.deposit_index; (start_idx..start_idx + spec.max_deposits) .map(|idx| self.deposits.get(&idx)) - .take_while(|deposit| { - // NOTE: we don't use verify_deposit, because it requires the - // deposit's index to match the state's, and we would like to return - // a batch with increasing indices - deposit.map_or(false, |deposit| { - !VERIFY_DEPOSIT_PROOFS || verify_deposit_merkle_proof(state, deposit, spec) - }) - }) + .take_while(Option::is_some) .flatten() .cloned() .collect() @@ -287,7 +288,7 @@ impl OperationPool { state: &BeaconState, spec: &ChainSpec, ) -> Result<(), ()> { - verify_exit(state, &exit, spec, false).map_err(|_| ())?; + verify_exit_time_independent_only(state, &exit, spec).map_err(|_| ())?; self.voluntary_exits.insert(exit.validator_index, exit); Ok(()) } @@ -297,7 +298,7 @@ impl OperationPool { pub fn get_voluntary_exits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { filter_limit_operations( self.voluntary_exits.values(), - |exit| verify_exit(state, exit, spec, true).is_ok(), + |exit| verify_exit(state, exit, spec).is_ok(), spec.max_voluntary_exits, ) } @@ -398,53 +399,51 @@ mod tests { use super::DepositInsertStatus::*; use super::*; use types::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + use types::*; #[test] fn insert_deposit() { - let mut rng = XorShiftRng::from_seed([42; 16]); + let rng = &mut XorShiftRng::from_seed([42; 16]); + let (ref spec, ref state) = test_state(rng); let mut op_pool = OperationPool::new(); - let deposit1 = Deposit::random_for_test(&mut rng); - let mut deposit2 = Deposit::random_for_test(&mut rng); + let deposit1 = make_deposit(rng, state, spec); + let mut deposit2 = make_deposit(rng, state, spec); deposit2.index = deposit1.index; - assert_eq!(op_pool.insert_deposit(deposit1.clone()), Fresh); - assert_eq!(op_pool.insert_deposit(deposit1.clone()), Duplicate); assert_eq!( - op_pool.insert_deposit(deposit2), - Replaced(Box::new(deposit1)) + op_pool.insert_deposit(deposit1.clone(), state, spec), + Ok(Fresh) + ); + assert_eq!( + op_pool.insert_deposit(deposit1.clone(), state, spec), + Ok(Duplicate) + ); + assert_eq!( + op_pool.insert_deposit(deposit2, state, spec), + Ok(Replaced(Box::new(deposit1))) ); - } - - // Create `count` dummy deposits with sequential deposit IDs beginning from `start`. - fn dummy_deposits(rng: &mut XorShiftRng, start: u64, count: u64) -> Vec { - let proto_deposit = Deposit::random_for_test(rng); - (start..start + count) - .map(|index| { - let mut deposit = proto_deposit.clone(); - deposit.index = index; - deposit - }) - .collect() } #[test] fn get_deposits_max() { - let mut rng = XorShiftRng::from_seed([42; 16]); + let rng = &mut XorShiftRng::from_seed([42; 16]); + let (spec, mut state) = test_state(rng); let mut op_pool = OperationPool::new(); - let spec = ChainSpec::foundation(); let start = 10000; let max_deposits = spec.max_deposits; let extra = 5; let offset = 1; assert!(offset <= extra); - let deposits = dummy_deposits(&mut rng, start, max_deposits + extra); + let deposits = dummy_deposits(rng, &state, &spec, start, max_deposits + extra); for deposit in &deposits { - assert_eq!(op_pool.insert_deposit(deposit.clone()), Fresh); + assert_eq!( + op_pool.insert_deposit(deposit.clone(), &state, &spec), + Ok(Fresh) + ); } - let mut state = BeaconState::random_for_test(&mut rng); state.deposit_index = start + offset; let deposits_for_block = op_pool.get_deposits(&state, &spec); @@ -458,18 +457,20 @@ mod tests { #[test] fn prune_deposits() { let rng = &mut XorShiftRng::from_seed([42; 16]); + let (spec, state) = test_state(rng); let mut op_pool = OperationPool::new(); let start1 = 100; - let count = 100; + // test is super slow in debug mode if this parameter is too high + let count = 5; let gap = 25; let start2 = start1 + count + gap; - let deposits1 = dummy_deposits(rng, start1, count); - let deposits2 = dummy_deposits(rng, start2, count); + let deposits1 = dummy_deposits(rng, &state, &spec, start1, count); + let deposits2 = dummy_deposits(rng, &state, &spec, start2, count); for d in deposits1.into_iter().chain(deposits2) { - op_pool.insert_deposit(d); + assert!(op_pool.insert_deposit(d, &state, &spec).is_ok()); } assert_eq!(op_pool.num_deposits(), 2 * count as usize); @@ -504,5 +505,50 @@ mod tests { assert_eq!(op_pool.num_deposits(), 0); } + // Create a random deposit (with a valid proof of posession) + fn make_deposit(rng: &mut XorShiftRng, state: &BeaconState, spec: &ChainSpec) -> Deposit { + let keypair = Keypair::random(); + let mut deposit = Deposit::random_for_test(rng); + let mut deposit_input = DepositInput { + pubkey: keypair.pk.clone(), + withdrawal_credentials: Hash256::zero(), + proof_of_possession: Signature::empty_signature(), + }; + deposit_input.proof_of_possession = deposit_input.create_proof_of_possession( + &keypair.sk, + state.slot.epoch(spec.slots_per_epoch), + &state.fork, + spec, + ); + deposit.deposit_data.deposit_input = deposit_input; + deposit + } + + // Create `count` dummy deposits with sequential deposit IDs beginning from `start`. + fn dummy_deposits( + rng: &mut XorShiftRng, + state: &BeaconState, + spec: &ChainSpec, + start: u64, + count: u64, + ) -> Vec { + let proto_deposit = make_deposit(rng, state, spec); + (start..start + count) + .map(|index| { + let mut deposit = proto_deposit.clone(); + deposit.index = index; + deposit + }) + .collect() + } + + fn test_state(rng: &mut XorShiftRng) -> (ChainSpec, BeaconState) { + let spec = ChainSpec::foundation(); + let mut state = BeaconState::random_for_test(rng); + state.fork = Fork::genesis(&spec); + + (spec, state) + } + // TODO: more tests } diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index e0e359552..617da00d4 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -11,9 +11,8 @@ pub use self::verify_proposer_slashing::verify_proposer_slashing; pub use validate_attestation::{validate_attestation, validate_attestation_without_signature}; pub use verify_deposit::{ get_existing_validator_index, verify_deposit, verify_deposit_index, - verify_deposit_merkle_proof, }; -pub use verify_exit::verify_exit; +pub use verify_exit::{verify_exit, verify_exit_time_independent_only}; pub use verify_slashable_attestation::verify_slashable_attestation; pub use verify_transfer::{execute_transfer, verify_transfer, verify_transfer_partial}; @@ -429,7 +428,7 @@ pub fn process_exits( .par_iter() .enumerate() .try_for_each(|(i, exit)| { - verify_exit(&state, exit, spec, true).map_err(|e| e.into_with_index(i)) + verify_exit(&state, exit, spec).map_err(|e| e.into_with_index(i)) })?; // Update the state in series. diff --git a/eth2/state_processing/src/per_block_processing/verify_deposit.rs b/eth2/state_processing/src/per_block_processing/verify_deposit.rs index 1b974d972..a3a0f5734 100644 --- a/eth2/state_processing/src/per_block_processing/verify_deposit.rs +++ b/eth2/state_processing/src/per_block_processing/verify_deposit.rs @@ -89,11 +89,7 @@ pub fn get_existing_validator_index( /// Verify that a deposit is included in the state's eth1 deposit root. /// /// Spec v0.5.0 -pub fn verify_deposit_merkle_proof( - state: &BeaconState, - deposit: &Deposit, - spec: &ChainSpec, -) -> bool { +fn verify_deposit_merkle_proof(state: &BeaconState, deposit: &Deposit, spec: &ChainSpec) -> bool { let leaf = hash(&get_serialized_deposit_data(deposit)); verify_merkle_proof( Hash256::from_slice(&leaf), diff --git a/eth2/state_processing/src/per_block_processing/verify_exit.rs b/eth2/state_processing/src/per_block_processing/verify_exit.rs index 14dad3442..a3b694395 100644 --- a/eth2/state_processing/src/per_block_processing/verify_exit.rs +++ b/eth2/state_processing/src/per_block_processing/verify_exit.rs @@ -7,17 +7,30 @@ use types::*; /// /// Returns `Ok(())` if the `Exit` is valid, otherwise indicates the reason for invalidity. /// -/// The `check_future_epoch` argument determines whether the exit's epoch should be checked -/// against the state's current epoch to ensure it doesn't occur in the future. -/// It should ordinarily be set to true, except for operations stored for -/// some time (such as in the OperationPool). -/// /// Spec v0.5.0 pub fn verify_exit( state: &BeaconState, exit: &VoluntaryExit, spec: &ChainSpec, - check_future_epoch: bool, +) -> Result<(), Error> { + verify_exit_parametric(state, exit, spec, false) +} + +/// Like `verify_exit` but doesn't run checks which may become true in future states. +pub fn verify_exit_time_independent_only( + state: &BeaconState, + exit: &VoluntaryExit, + spec: &ChainSpec, +) -> Result<(), Error> { + verify_exit_parametric(state, exit, spec, true) +} + +/// Parametric version of `verify_exit` that skips some checks if `time_independent_only` is true. +fn verify_exit_parametric( + state: &BeaconState, + exit: &VoluntaryExit, + spec: &ChainSpec, + time_independent_only: bool, ) -> Result<(), Error> { let validator = state .validator_registry @@ -38,7 +51,7 @@ pub fn verify_exit( // Exits must specify an epoch when they become valid; they are not valid before then. verify!( - !check_future_epoch || state.current_epoch(spec) >= exit.epoch, + time_independent_only || state.current_epoch(spec) >= exit.epoch, Invalid::FutureEpoch { state: state.current_epoch(spec), exit: exit.epoch diff --git a/eth2/types/src/attestation.rs b/eth2/types/src/attestation.rs index 6c572c852..043711015 100644 --- a/eth2/types/src/attestation.rs +++ b/eth2/types/src/attestation.rs @@ -31,7 +31,9 @@ pub struct Attestation { impl Attestation { /// Are the aggregation bitfields of these attestations disjoint? pub fn signers_disjoint_from(&self, other: &Attestation) -> bool { - self.aggregation_bitfield.intersection(&other.aggregation_bitfield).is_zero() + self.aggregation_bitfield + .intersection(&other.aggregation_bitfield) + .is_zero() } /// Aggregate another Attestation into this one. @@ -41,7 +43,8 @@ impl Attestation { debug_assert_eq!(self.data, other.data); debug_assert!(self.signers_disjoint_from(other)); - self.aggregation_bitfield.union_inplace(&other.aggregation_bitfield); + self.aggregation_bitfield + .union_inplace(&other.aggregation_bitfield); self.custody_bitfield.union_inplace(&other.custody_bitfield); // FIXME: signature aggregation once our BLS library wraps it } From 95ed40222827c5aba0259ce4a128ab51af54631b Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 20 Mar 2019 16:13:06 +1100 Subject: [PATCH 016/106] op-pool: rename to verify_*_time_independent_only --- eth2/operation_pool/src/lib.rs | 4 +-- .../src/per_block_processing.rs | 8 ++--- .../per_block_processing/verify_transfer.rs | 30 +++++++++++-------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index ecf4e41e7..ff5a7416b 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -4,7 +4,7 @@ use ssz::ssz_encode; use state_processing::per_block_processing::errors::ProposerSlashingValidationError; use state_processing::per_block_processing::{ validate_attestation, verify_deposit, verify_exit, verify_exit_time_independent_only, - verify_proposer_slashing, verify_transfer, verify_transfer_partial, + verify_proposer_slashing, verify_transfer, verify_transfer_time_independent_only, }; use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet}; use types::chain_spec::Domain; @@ -322,7 +322,7 @@ impl OperationPool { // The signature of the transfer isn't hashed, but because we check // it before we insert into the HashSet, we can't end up with duplicate // transactions. - verify_transfer_partial(state, &transfer, spec, true).map_err(|_| ())?; + verify_transfer_time_independent_only(state, &transfer, spec).map_err(|_| ())?; self.transfers.insert(transfer); Ok(()) } diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index 617da00d4..55e2c29d0 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -9,12 +9,12 @@ pub use self::verify_attester_slashing::{ }; pub use self::verify_proposer_slashing::verify_proposer_slashing; pub use validate_attestation::{validate_attestation, validate_attestation_without_signature}; -pub use verify_deposit::{ - get_existing_validator_index, verify_deposit, verify_deposit_index, -}; +pub use verify_deposit::{get_existing_validator_index, verify_deposit, verify_deposit_index}; pub use verify_exit::{verify_exit, verify_exit_time_independent_only}; pub use verify_slashable_attestation::verify_slashable_attestation; -pub use verify_transfer::{execute_transfer, verify_transfer, verify_transfer_partial}; +pub use verify_transfer::{ + execute_transfer, verify_transfer, verify_transfer_time_independent_only, +}; pub mod errors; mod validate_attestation; diff --git a/eth2/state_processing/src/per_block_processing/verify_transfer.rs b/eth2/state_processing/src/per_block_processing/verify_transfer.rs index 4f3815797..ac9e9aa09 100644 --- a/eth2/state_processing/src/per_block_processing/verify_transfer.rs +++ b/eth2/state_processing/src/per_block_processing/verify_transfer.rs @@ -16,18 +16,24 @@ pub fn verify_transfer( transfer: &Transfer, spec: &ChainSpec, ) -> Result<(), Error> { - verify_transfer_partial(state, transfer, spec, false) + verify_transfer_parametric(state, transfer, spec, false) } -/// Parametric version of `verify_transfer` that allows some checks to be skipped. -/// -/// In everywhere except the operation pool, `verify_transfer` should be preferred over this -/// function. -pub fn verify_transfer_partial( +/// Like `verify_transfer` but doesn't run checks which may become true in future states. +pub fn verify_transfer_time_independent_only( state: &BeaconState, transfer: &Transfer, spec: &ChainSpec, - for_op_pool: bool, +) -> Result<(), Error> { + verify_transfer_parametric(state, transfer, spec, true) +} + +/// Parametric version of `verify_transfer` that allows some checks to be skipped. +fn verify_transfer_parametric( + state: &BeaconState, + transfer: &Transfer, + spec: &ChainSpec, + time_independent_only: bool, ) -> Result<(), Error> { let sender_balance = *state .validator_balances @@ -40,17 +46,17 @@ pub fn verify_transfer_partial( .ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?; verify!( - for_op_pool || sender_balance >= transfer.amount, + time_independent_only || sender_balance >= transfer.amount, Invalid::FromBalanceInsufficient(transfer.amount, sender_balance) ); verify!( - for_op_pool || sender_balance >= transfer.fee, + time_independent_only || sender_balance >= transfer.fee, Invalid::FromBalanceInsufficient(transfer.fee, sender_balance) ); verify!( - for_op_pool + time_independent_only || (sender_balance == total_amount) || (sender_balance >= (total_amount + spec.min_deposit_amount)), Invalid::InvalidResultingFromBalance( @@ -59,7 +65,7 @@ pub fn verify_transfer_partial( ) ); - if for_op_pool { + if time_independent_only { verify!( state.slot <= transfer.slot, Invalid::TransferSlotInPast(state.slot, transfer.slot) @@ -78,7 +84,7 @@ pub fn verify_transfer_partial( let epoch = state.slot.epoch(spec.slots_per_epoch); verify!( - for_op_pool + time_independent_only || sender_validator.is_withdrawable_at(epoch) || sender_validator.activation_epoch == spec.far_future_epoch, Invalid::FromValidatorIneligableForTransfer(transfer.sender) From 3396f2f08e05d82485b2317db04bce54831f29da Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 20 Mar 2019 16:28:04 +1100 Subject: [PATCH 017/106] op-pool: propagate errors, sort by transfer fee --- eth2/operation_pool/src/lib.rs | 46 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index ff5a7416b..c6af777e6 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -1,7 +1,10 @@ use int_to_bytes::int_to_bytes8; use itertools::Itertools; use ssz::ssz_encode; -use state_processing::per_block_processing::errors::ProposerSlashingValidationError; +use state_processing::per_block_processing::errors::{ + AttestationValidationError, DepositValidationError, ExitValidationError, + ProposerSlashingValidationError, TransferValidationError, +}; use state_processing::per_block_processing::{ validate_attestation, verify_deposit, verify_exit, verify_exit_time_independent_only, verify_proposer_slashing, verify_transfer, verify_transfer_time_independent_only, @@ -108,10 +111,10 @@ impl OperationPool { attestation: Attestation, state: &BeaconState, spec: &ChainSpec, - ) -> Result<(), ()> { + ) -> Result<(), AttestationValidationError> { // Check that attestation signatures are valid. // FIXME: should disable the time-dependent checks. - validate_attestation(state, &attestation, spec).map_err(|_| ())?; + validate_attestation(state, &attestation, spec)?; let id = AttestationId::from_data(&attestation.data, state, spec); @@ -143,7 +146,7 @@ impl OperationPool { /// Get a list of attestations for inclusion in a block. pub fn get_attestations(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { // Attestations for the current fork... - // TODO: should we also check domain bytes for the previous epoch? + // FIXME: should we also check domain bytes for the previous epoch? let current_epoch = state.slot.epoch(spec.slots_per_epoch); let domain_bytes = AttestationId::compute_domain_bytes(current_epoch, state, spec); self.attestations @@ -184,13 +187,12 @@ impl OperationPool { deposit: Deposit, state: &BeaconState, spec: &ChainSpec, - ) -> Result { + ) -> Result { use DepositInsertStatus::*; match self.deposits.entry(deposit.index) { Entry::Vacant(entry) => { - // FIXME: error prop - verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec).map_err(|_| ())?; + verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec)?; entry.insert(deposit); Ok(Fresh) } @@ -198,7 +200,7 @@ impl OperationPool { if entry.get() == &deposit { Ok(Duplicate) } else { - verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec).map_err(|_| ())?; + verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec)?; Ok(Replaced(Box::new(entry.insert(deposit)))) } } @@ -279,7 +281,7 @@ impl OperationPool { ); } - // TODO: copy ProposerSlashing code for AttesterSlashing + // FIXME: copy ProposerSlashing code for AttesterSlashing /// Insert a voluntary exit, validating it almost-entirely (future exits are permitted). pub fn insert_voluntary_exit( @@ -287,14 +289,13 @@ impl OperationPool { exit: VoluntaryExit, state: &BeaconState, spec: &ChainSpec, - ) -> Result<(), ()> { - verify_exit_time_independent_only(state, &exit, spec).map_err(|_| ())?; + ) -> Result<(), ExitValidationError> { + verify_exit_time_independent_only(state, &exit, spec)?; self.voluntary_exits.insert(exit.validator_index, exit); Ok(()) } /// Get a list of voluntary exits for inclusion in a block. - // TODO: could optimise this by eliding the checks that have already been done on insert pub fn get_voluntary_exits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { filter_limit_operations( self.voluntary_exits.values(), @@ -318,25 +319,26 @@ impl OperationPool { transfer: Transfer, state: &BeaconState, spec: &ChainSpec, - ) -> Result<(), ()> { + ) -> Result<(), TransferValidationError> { // The signature of the transfer isn't hashed, but because we check // it before we insert into the HashSet, we can't end up with duplicate // transactions. - verify_transfer_time_independent_only(state, &transfer, spec).map_err(|_| ())?; + verify_transfer_time_independent_only(state, &transfer, spec)?; self.transfers.insert(transfer); Ok(()) } /// Get a list of transfers for inclusion in a block. - // TODO: improve the economic optimality of this function by taking the transfer - // fees into account, and dependencies between transfers in the same block - // e.g. A pays B, B pays C + // TODO: improve the economic optimality of this function by accounting for + // dependencies between transfers in the same block e.g. A pays B, B pays C pub fn get_transfers(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { - filter_limit_operations( - &self.transfers, - |transfer| verify_transfer(state, transfer, spec).is_ok(), - spec.max_transfers, - ) + self.transfers + .iter() + .filter(|transfer| verify_transfer(state, transfer, spec).is_ok()) + .sorted_by_key(|transfer| std::cmp::Reverse(transfer.fee)) + .take(spec.max_transfers as usize) + .cloned() + .collect() } /// Prune the set of transfers by removing all those whose slot has already passed. From e512f7c0e1cc0d836e1aac2adcea4bc5b2b7af23 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 20 Mar 2019 16:52:58 +1100 Subject: [PATCH 018/106] op-pool: validate_attestation_time_independent_only --- eth2/operation_pool/src/lib.rs | 8 +- .../src/per_block_processing.rs | 5 +- .../validate_attestation.rs | 108 +++++++++++------- 3 files changed, 75 insertions(+), 46 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index c6af777e6..6d276600a 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -6,8 +6,9 @@ use state_processing::per_block_processing::errors::{ ProposerSlashingValidationError, TransferValidationError, }; use state_processing::per_block_processing::{ - validate_attestation, verify_deposit, verify_exit, verify_exit_time_independent_only, - verify_proposer_slashing, verify_transfer, verify_transfer_time_independent_only, + validate_attestation, validate_attestation_time_independent_only, verify_deposit, verify_exit, + verify_exit_time_independent_only, verify_proposer_slashing, verify_transfer, + verify_transfer_time_independent_only, }; use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet}; use types::chain_spec::Domain; @@ -113,8 +114,7 @@ impl OperationPool { spec: &ChainSpec, ) -> Result<(), AttestationValidationError> { // Check that attestation signatures are valid. - // FIXME: should disable the time-dependent checks. - validate_attestation(state, &attestation, spec)?; + validate_attestation_time_independent_only(state, &attestation, spec)?; let id = AttestationId::from_data(&attestation.data, state, spec); diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index 55e2c29d0..031b919c1 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -8,7 +8,10 @@ pub use self::verify_attester_slashing::{ gather_attester_slashing_indices, verify_attester_slashing, }; pub use self::verify_proposer_slashing::verify_proposer_slashing; -pub use validate_attestation::{validate_attestation, validate_attestation_without_signature}; +pub use validate_attestation::{ + validate_attestation, validate_attestation_time_independent_only, + validate_attestation_without_signature, +}; pub use verify_deposit::{get_existing_validator_index, verify_deposit, verify_deposit_index}; pub use verify_exit::{verify_exit, verify_exit_time_independent_only}; pub use verify_slashable_attestation::verify_slashable_attestation; diff --git a/eth2/state_processing/src/per_block_processing/validate_attestation.rs b/eth2/state_processing/src/per_block_processing/validate_attestation.rs index 2143988a4..3b89bec99 100644 --- a/eth2/state_processing/src/per_block_processing/validate_attestation.rs +++ b/eth2/state_processing/src/per_block_processing/validate_attestation.rs @@ -14,7 +14,16 @@ pub fn validate_attestation( attestation: &Attestation, spec: &ChainSpec, ) -> Result<(), Error> { - validate_attestation_signature_optional(state, attestation, spec, true) + validate_attestation_parametric(state, attestation, spec, true, false) +} + +/// Like `validate_attestation` but doesn't run checks which may become true in future states. +pub fn validate_attestation_time_independent_only( + state: &BeaconState, + attestation: &Attestation, + spec: &ChainSpec, +) -> Result<(), Error> { + validate_attestation_parametric(state, attestation, spec, true, true) } /// Indicates if an `Attestation` is valid to be included in a block in the current epoch of the @@ -28,7 +37,7 @@ pub fn validate_attestation_without_signature( attestation: &Attestation, spec: &ChainSpec, ) -> Result<(), Error> { - validate_attestation_signature_optional(state, attestation, spec, false) + validate_attestation_parametric(state, attestation, spec, false, false) } /// Indicates if an `Attestation` is valid to be included in a block in the current epoch of the @@ -36,15 +45,13 @@ pub fn validate_attestation_without_signature( /// /// /// Spec v0.5.0 -fn validate_attestation_signature_optional( +fn validate_attestation_parametric( state: &BeaconState, attestation: &Attestation, spec: &ChainSpec, verify_signature: bool, + time_independent_only: bool, ) -> Result<(), Error> { - let state_epoch = state.slot.epoch(spec.slots_per_epoch); - let attestation_epoch = attestation.data.slot.epoch(spec.slots_per_epoch); - // Can't submit pre-historic attestations. verify!( attestation.data.slot >= spec.genesis_slot, @@ -65,7 +72,8 @@ fn validate_attestation_signature_optional( // Can't submit attestation too quickly. verify!( - attestation.data.slot + spec.min_attestation_inclusion_delay <= state.slot, + time_independent_only + || attestation.data.slot + spec.min_attestation_inclusion_delay <= state.slot, Invalid::IncludedTooEarly { state: state.slot, delay: spec.min_attestation_inclusion_delay, @@ -74,40 +82,8 @@ fn validate_attestation_signature_optional( ); // Verify the justified epoch and root is correct. - if attestation_epoch >= state_epoch { - verify!( - attestation.data.source_epoch == state.current_justified_epoch, - Invalid::WrongJustifiedEpoch { - state: state.current_justified_epoch, - attestation: attestation.data.source_epoch, - is_current: true, - } - ); - verify!( - attestation.data.source_root == state.current_justified_root, - Invalid::WrongJustifiedRoot { - state: state.current_justified_root, - attestation: attestation.data.source_root, - is_current: true, - } - ); - } else { - verify!( - attestation.data.source_epoch == state.previous_justified_epoch, - Invalid::WrongJustifiedEpoch { - state: state.previous_justified_epoch, - attestation: attestation.data.source_epoch, - is_current: false, - } - ); - verify!( - attestation.data.source_root == state.previous_justified_root, - Invalid::WrongJustifiedRoot { - state: state.previous_justified_root, - attestation: attestation.data.source_root, - is_current: true, - } - ); + if !time_independent_only { + verify_justified_epoch_and_root(attestation, state, spec)?; } // Check that the crosslink data is valid. @@ -188,6 +164,56 @@ fn validate_attestation_signature_optional( Ok(()) } +/// Verify that the `source_epoch` and `source_root` of an `Attestation` correctly +/// match the current (or previous) justified epoch and root from the state. +/// +/// Spec v0.5.0 +fn verify_justified_epoch_and_root( + attestation: &Attestation, + state: &BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { + let state_epoch = state.slot.epoch(spec.slots_per_epoch); + let attestation_epoch = attestation.data.slot.epoch(spec.slots_per_epoch); + + if attestation_epoch >= state_epoch { + verify!( + attestation.data.source_epoch == state.current_justified_epoch, + Invalid::WrongJustifiedEpoch { + state: state.current_justified_epoch, + attestation: attestation.data.source_epoch, + is_current: true, + } + ); + verify!( + attestation.data.source_root == state.current_justified_root, + Invalid::WrongJustifiedRoot { + state: state.current_justified_root, + attestation: attestation.data.source_root, + is_current: true, + } + ); + } else { + verify!( + attestation.data.source_epoch == state.previous_justified_epoch, + Invalid::WrongJustifiedEpoch { + state: state.previous_justified_epoch, + attestation: attestation.data.source_epoch, + is_current: false, + } + ); + verify!( + attestation.data.source_root == state.previous_justified_root, + Invalid::WrongJustifiedRoot { + state: state.previous_justified_root, + attestation: attestation.data.source_root, + is_current: true, + } + ); + } + Ok(()) +} + /// Verifies an aggregate signature for some given `AttestationData`, returning `true` if the /// `aggregate_signature` is valid. /// From 22a90a0224c38c7b7913d520d9c90bc0fa5005c1 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 25 Mar 2019 11:56:30 +1100 Subject: [PATCH 019/106] op-pool: check previous epoch in get_attestations --- eth2/operation_pool/src/lib.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 6d276600a..fc894da27 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -145,13 +145,17 @@ impl OperationPool { /// Get a list of attestations for inclusion in a block. pub fn get_attestations(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { - // Attestations for the current fork... - // FIXME: should we also check domain bytes for the previous epoch? - let current_epoch = state.slot.epoch(spec.slots_per_epoch); - let domain_bytes = AttestationId::compute_domain_bytes(current_epoch, state, spec); + // Attestations for the current fork, which may be from the current or previous epoch. + let prev_epoch = state.previous_epoch(spec); + let current_epoch = state.current_epoch(spec); + let prev_domain_bytes = AttestationId::compute_domain_bytes(prev_epoch, state, spec); + let curr_domain_bytes = AttestationId::compute_domain_bytes(current_epoch, state, spec); self.attestations .iter() - .filter(|(key, _)| key.domain_bytes_match(&domain_bytes)) + .filter(|(key, _)| { + key.domain_bytes_match(&prev_domain_bytes) + || key.domain_bytes_match(&curr_domain_bytes) + }) .flat_map(|(_, attestations)| attestations) // That are valid... .filter(|attestation| validate_attestation(state, attestation, spec).is_ok()) From 0bf8cb953eeaa86662455e0025be0e7f1f4b4808 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 25 Mar 2019 12:44:30 +1100 Subject: [PATCH 020/106] BLS: wrap AggregateSignature::add_aggregate --- eth2/utils/bls/src/aggregate_signature.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/eth2/utils/bls/src/aggregate_signature.rs b/eth2/utils/bls/src/aggregate_signature.rs index 7b80d3bbf..44eafdcdf 100644 --- a/eth2/utils/bls/src/aggregate_signature.rs +++ b/eth2/utils/bls/src/aggregate_signature.rs @@ -27,6 +27,11 @@ impl AggregateSignature { self.0.add(signature.as_raw()) } + /// Add (aggregate) another `AggregateSignature`. + pub fn add_aggregate(&mut self, agg_signature: &AggregateSignature) { + self.0.add_aggregate(&agg_signature.0) + } + /// Verify the `AggregateSignature` against an `AggregatePublicKey`. /// /// Only returns `true` if the set of keys in the `AggregatePublicKey` match the set of keys From bde7ab79c800203a1624a014db656017155ff381 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 25 Mar 2019 12:45:24 +1100 Subject: [PATCH 021/106] types: aggregate signatures in attestations --- eth2/types/src/attestation.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth2/types/src/attestation.rs b/eth2/types/src/attestation.rs index 043711015..dabccfde7 100644 --- a/eth2/types/src/attestation.rs +++ b/eth2/types/src/attestation.rs @@ -46,7 +46,8 @@ impl Attestation { self.aggregation_bitfield .union_inplace(&other.aggregation_bitfield); self.custody_bitfield.union_inplace(&other.custody_bitfield); - // FIXME: signature aggregation once our BLS library wraps it + self.aggregate_signature + .add_aggregate(&other.aggregate_signature); } } From 518359e89845a7d16f99253b07560fa8a667e101 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 25 Mar 2019 16:58:20 +1100 Subject: [PATCH 022/106] op-pool: implement attester slashings --- eth2/operation_pool/src/lib.rs | 120 +++++++++++++++--- .../src/per_block_processing.rs | 3 +- .../verify_attester_slashing.rs | 21 ++- 3 files changed, 122 insertions(+), 22 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index fc894da27..fadbf449d 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -2,12 +2,13 @@ use int_to_bytes::int_to_bytes8; use itertools::Itertools; use ssz::ssz_encode; use state_processing::per_block_processing::errors::{ - AttestationValidationError, DepositValidationError, ExitValidationError, - ProposerSlashingValidationError, TransferValidationError, + AttestationValidationError, AttesterSlashingValidationError, DepositValidationError, + ExitValidationError, ProposerSlashingValidationError, TransferValidationError, }; use state_processing::per_block_processing::{ - validate_attestation, validate_attestation_time_independent_only, verify_deposit, verify_exit, - verify_exit_time_independent_only, verify_proposer_slashing, verify_transfer, + gather_attester_slashing_indices_modular, validate_attestation, + validate_attestation_time_independent_only, verify_attester_slashing, verify_deposit, + verify_exit, verify_exit_time_independent_only, verify_proposer_slashing, verify_transfer, verify_transfer_time_independent_only, }; use std::collections::{btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet}; @@ -32,8 +33,8 @@ pub struct OperationPool { // and the spec doesn't seem to accomodate for re-orgs on a time-frame // longer than an epoch deposits: BTreeMap, - /// Map from attester index to slashing. - attester_slashings: HashMap, + /// Map from two attestation IDs to a slashing for those IDs. + attester_slashings: HashMap<(AttestationId, AttestationId), AttesterSlashing>, /// Map from proposer index to slashing. proposer_slashings: HashMap, /// Map from exiting validator to their exit data. @@ -250,18 +251,44 @@ impl OperationPool { Ok(()) } - /// Only check whether the implicated validator has already been slashed, because - /// all slashings in the pool were validated upon insertion. - // TODO: we need a mechanism to avoid including a proposer slashing and an attester - // slashing for the same validator in the same block - pub fn get_proposer_slashings( + /// Compute the tuple ID that is used to identify an attester slashing. + /// + /// Depends on the fork field of the state, but not on the state's epoch. + fn attester_slashing_id( + slashing: &AttesterSlashing, + state: &BeaconState, + spec: &ChainSpec, + ) -> (AttestationId, AttestationId) { + ( + AttestationId::from_data(&slashing.slashable_attestation_1.data, state, spec), + AttestationId::from_data(&slashing.slashable_attestation_2.data, state, spec), + ) + } + + /// Insert an attester slashing into the pool. + pub fn insert_attester_slashing( + &mut self, + slashing: AttesterSlashing, + state: &BeaconState, + spec: &ChainSpec, + ) -> Result<(), AttesterSlashingValidationError> { + verify_attester_slashing(state, &slashing, true, spec)?; + let id = Self::attester_slashing_id(&slashing, state, spec); + self.attester_slashings.insert(id, slashing); + Ok(()) + } + + /// Get proposer and attester slashings for inclusion in a block. + /// + /// This function computes both types of slashings together, because + /// attester slashings may be invalidated by proposer slashings included + /// earlier in the block. + pub fn get_slashings( &self, state: &BeaconState, spec: &ChainSpec, - ) -> Vec { - // We sort by validator index, which is safe, because a validator can only supply - // so many valid slashings for lower-indexed validators (and even that is unlikely) - filter_limit_operations( + ) -> (Vec, Vec) { + let proposer_slashings = filter_limit_operations( self.proposer_slashings.values(), |slashing| { state @@ -270,10 +297,48 @@ impl OperationPool { .map_or(false, |validator| !validator.slashed) }, spec.max_proposer_slashings, - ) + ); + + // Set of validators to be slashed, so we don't attempt to construct invalid attester + // slashings. + let mut to_be_slashed = proposer_slashings + .iter() + .map(|s| s.proposer_index) + .collect::>(); + + let attester_slashings = self + .attester_slashings + .iter() + .filter(|(id, slashing)| { + // Check the fork. + Self::attester_slashing_id(slashing, state, spec) == **id + }) + .filter(|(_, slashing)| { + // Take all slashings that will slash 1 or more validators. + let slashed_validators = gather_attester_slashing_indices_modular( + state, + slashing, + |index, validator| validator.slashed || to_be_slashed.contains(&index), + spec, + ); + + // Extend the `to_be_slashed` set so subsequent iterations don't try to include + // useless slashings. + if let Ok(validators) = slashed_validators { + to_be_slashed.extend(validators); + true + } else { + false + } + }) + .take(spec.max_attester_slashings as usize) + .map(|(_, slashing)| slashing.clone()) + .collect(); + + (proposer_slashings, attester_slashings) } - /// Prune slashings for all slashed or withdrawn validators. + /// Prune proposer slashings for all slashed or withdrawn validators. pub fn prune_proposer_slashings(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { prune_validator_hash_map( &mut self.proposer_slashings, @@ -285,7 +350,22 @@ impl OperationPool { ); } - // FIXME: copy ProposerSlashing code for AttesterSlashing + /// Prune attester slashings for all slashed or withdrawn validators, or attestations on another + /// fork. + pub fn prune_attester_slashings(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { + self.attester_slashings.retain(|id, slashing| { + let fork_ok = &Self::attester_slashing_id(slashing, finalized_state, spec) == id; + let curr_epoch = finalized_state.current_epoch(spec); + let slashing_ok = gather_attester_slashing_indices_modular( + finalized_state, + slashing, + |_, validator| validator.slashed || validator.is_withdrawable_at(curr_epoch), + spec, + ) + .is_ok(); + fork_ok && slashing_ok + }); + } /// Insert a voluntary exit, validating it almost-entirely (future exits are permitted). pub fn insert_voluntary_exit( @@ -359,13 +439,13 @@ impl OperationPool { self.prune_attestations(finalized_state, spec); self.prune_deposits(finalized_state); self.prune_proposer_slashings(finalized_state, spec); - // FIXME: add attester slashings + self.prune_attester_slashings(finalized_state, spec); self.prune_voluntary_exits(finalized_state, spec); self.prune_transfers(finalized_state); } } -/// Filter up to a maximum number of operations out of a slice. +/// Filter up to a maximum number of operations out of an iterator. fn filter_limit_operations<'a, T: 'a, I, F>(operations: I, filter: F, limit: u64) -> Vec where I: IntoIterator, diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index 031b919c1..e79f5f08c 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -5,7 +5,8 @@ use ssz::{SignedRoot, TreeHash}; use types::*; pub use self::verify_attester_slashing::{ - gather_attester_slashing_indices, verify_attester_slashing, + gather_attester_slashing_indices, gather_attester_slashing_indices_modular, + verify_attester_slashing, }; pub use self::verify_proposer_slashing::verify_proposer_slashing; pub use validate_attestation::{ diff --git a/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs b/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs index a198d2a3e..abf99da64 100644 --- a/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs +++ b/eth2/state_processing/src/per_block_processing/verify_attester_slashing.rs @@ -47,6 +47,25 @@ pub fn gather_attester_slashing_indices( attester_slashing: &AttesterSlashing, spec: &ChainSpec, ) -> Result, Error> { + gather_attester_slashing_indices_modular( + state, + attester_slashing, + |_, validator| validator.slashed, + spec, + ) +} + +/// Same as `gather_attester_slashing_indices` but allows the caller to specify the criteria +/// for determining whether a given validator should be considered slashed. +pub fn gather_attester_slashing_indices_modular( + state: &BeaconState, + attester_slashing: &AttesterSlashing, + is_slashed: F, + spec: &ChainSpec, +) -> Result, Error> +where + F: Fn(u64, &Validator) -> bool, +{ let slashable_attestation_1 = &attester_slashing.slashable_attestation_1; let slashable_attestation_2 = &attester_slashing.slashable_attestation_2; @@ -57,7 +76,7 @@ pub fn gather_attester_slashing_indices( .get(*i as usize) .ok_or_else(|| Error::Invalid(Invalid::UnknownValidator(*i)))?; - if slashable_attestation_2.validator_indices.contains(&i) & !validator.slashed { + if slashable_attestation_2.validator_indices.contains(&i) & !is_slashed(*i, validator) { // TODO: verify that we should reject any slashable attestation which includes a // withdrawn validator. PH has asked the question on gitter, awaiting response. verify!( From d76baa1cc1aa6e9e9982d0bc799e95bdb0a4da4e Mon Sep 17 00:00:00 2001 From: Kirk Baird Date: Mon, 25 Mar 2019 18:02:37 +1100 Subject: [PATCH 023/106] Allow downloading of large tests from EF github and fix issues with serde --- .gitignore | 1 + Cargo.toml | 1 + eth2/state_processing/Cargo.toml | 1 + eth2/state_processing/specs/example.yml | 708 -------------------- eth2/state_processing/tests/tests.rs | 23 +- eth2/state_processing/yaml_utils/Cargo.toml | 15 + eth2/state_processing/yaml_utils/build.rs | 28 + eth2/state_processing/yaml_utils/src/lib.rs | 1 + eth2/types/src/test_utils/serde_utils.rs | 10 +- eth2/utils/bls/src/aggregate_signature.rs | 95 ++- eth2/utils/bls/src/lib.rs | 1 + eth2/utils/bls/src/signature.rs | 14 +- eth2/utils/boolean-bitfield/src/lib.rs | 6 +- 13 files changed, 166 insertions(+), 738 deletions(-) delete mode 100644 eth2/state_processing/specs/example.yml create mode 100644 eth2/state_processing/yaml_utils/Cargo.toml create mode 100644 eth2/state_processing/yaml_utils/build.rs create mode 100644 eth2/state_processing/yaml_utils/src/lib.rs diff --git a/.gitignore b/.gitignore index 346ef9afa..ad0c3c152 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Cargo.lock *.pk *.sk *.raw_keypairs +eth2/state_processing/yaml_utils/specs/*.yaml diff --git a/Cargo.toml b/Cargo.toml index cb070cc2d..94b2af017 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "eth2/block_proposer", "eth2/fork_choice", "eth2/state_processing", + "eth2/state_processing/yaml_utils", "eth2/types", "eth2/utils/bls", "eth2/utils/boolean-bitfield", diff --git a/eth2/state_processing/Cargo.toml b/eth2/state_processing/Cargo.toml index 4e37fce0c..62722aac8 100644 --- a/eth2/state_processing/Cargo.toml +++ b/eth2/state_processing/Cargo.toml @@ -14,6 +14,7 @@ env_logger = "0.6.0" serde = "1.0" serde_derive = "1.0" serde_yaml = "0.8" +yaml-utils = { path = "yaml_utils" } [dependencies] bls = { path = "../utils/bls" } diff --git a/eth2/state_processing/specs/example.yml b/eth2/state_processing/specs/example.yml deleted file mode 100644 index 982f0b0dd..000000000 --- a/eth2/state_processing/specs/example.yml +++ /dev/null @@ -1,708 +0,0 @@ -title: Sanity tests -- small config -- 32 validators -summary: Basic sanity checks from phase 0 spec pythonization using a small state configuration and 32 validators. - All tests are run with `verify_signatures` as set to False. - Tests generated via https://github.com/ethereum/research/blob/master/spec_pythonizer/sanity_check.py -test_suite: beacon_state -fork: phase0-0.5.0 -test_cases: -- name: test_empty_block_transition - config: - SHARD_COUNT: 8 - TARGET_COMMITTEE_SIZE: 4 - MAX_BALANCE_CHURN_QUOTIENT: 32 - MAX_INDICES_PER_SLASHABLE_VOTE: 4096 - MAX_EXIT_DEQUEUES_PER_EPOCH: 4 - SHUFFLE_ROUND_COUNT: 90 - DEPOSIT_CONTRACT_TREE_DEPTH: 32 - MIN_DEPOSIT_AMOUNT: 1000000000 - MAX_DEPOSIT_AMOUNT: 32000000000 - FORK_CHOICE_BALANCE_INCREMENT: 1000000000 - EJECTION_BALANCE: 16000000000 - GENESIS_FORK_VERSION: 0 - GENESIS_SLOT: 4294967296 - GENESIS_EPOCH: 536870912 - GENESIS_START_SHARD: 0 - BLS_WITHDRAWAL_PREFIX_BYTE: '0x00' - SECONDS_PER_SLOT: 6 - MIN_ATTESTATION_INCLUSION_DELAY: 2 - SLOTS_PER_EPOCH: 8 - MIN_SEED_LOOKAHEAD: 1 - ACTIVATION_EXIT_DELAY: 4 - EPOCHS_PER_ETH1_VOTING_PERIOD: 16 - SLOTS_PER_HISTORICAL_ROOT: 64 - MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 - PERSISTENT_COMMITTEE_PERIOD: 2048 - LATEST_RANDAO_MIXES_LENGTH: 64 - LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 64 - LATEST_SLASHED_EXIT_LENGTH: 64 - BASE_REWARD_QUOTIENT: 32 - WHISTLEBLOWER_REWARD_QUOTIENT: 512 - ATTESTATION_INCLUSION_REWARD_QUOTIENT: 8 - INACTIVITY_PENALTY_QUOTIENT: 16777216 - MIN_PENALTY_QUOTIENT: 32 - MAX_PROPOSER_SLASHINGS: 16 - MAX_ATTESTER_SLASHINGS: 1 - MAX_ATTESTATIONS: 128 - MAX_DEPOSITS: 16 - MAX_VOLUNTARY_EXITS: 16 - MAX_TRANSFERS: 16 - DOMAIN_BEACON_BLOCK: 0 - DOMAIN_RANDAO: 1 - DOMAIN_ATTESTATION: 2 - DOMAIN_DEPOSIT: 3 - DOMAIN_VOLUNTARY_EXIT: 4 - DOMAIN_TRANSFER: 5 - verify_signatures: false - initial_state: - slot: 4294967296 - genesis_time: 0 - fork: - previous_version: '0x00000000' - current_version: '0x00000000' - epoch: 536870912 - validator_registry: - - pubkey: '0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000001' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000002' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x89ece308f9d1f0131765212deca99697b112d61f9be9a5f1f3780a51335b3ff981747a0b2ca2179b96d2c0c9024e5224' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000003' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xac9b60d5afcbd5663a8a44b7c5a02f19e9a77ab0a35bd65809bb5c67ec582c897feb04decc694b13e08587f3ff9b5b60' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000004' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xb0e7791fb972fe014159aa33a98622da3cdc98ff707965e536d8636b5fcc5ac7a91a8c46e59a00dca575af0f18fb13dc' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000005' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xa6e82f6da4520f85c5d27d8f329eccfa05944fd1096b20734c894966d12a9e2a9a9744529d7212d33883113a0cadb909' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000006' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xb928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000007' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xa85ae765588126f5e860d019c0e26235f567a9c0c0b2d8ff30f3e8d436b1082596e5e7462d20f5be3764fd473e57f9cf' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000008' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x99cdf3807146e68e041314ca93e1fee0991224ec2a74beb2866816fd0826ce7b6263ee31e953a86d1b72cc2215a57793' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000009' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xaf81da25ecf1c84b577fefbedd61077a81dc43b00304015b2b596ab67f00e41c86bb00ebd0f90d4b125eb0539891aeed' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000000a' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x80fd75ebcc0a21649e3177bcce15426da0e4f25d6828fbf4038d4d7ed3bd4421de3ef61d70f794687b12b2d571971a55' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000000b' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x8345dd80ffef0eaec8920e39ebb7f5e9ae9c1d6179e9129b705923df7830c67f3690cbc48649d4079eadf5397339580c' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000000c' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x851f8a0b82a6d86202a61cbc3b0f3db7d19650b914587bde4715ccd372e1e40cab95517779d840416e1679c84a6db24e' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000000d' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x99bef05aaba1ea467fcbc9c420f5e3153c9d2b5f9bf2c7e2e7f6946f854043627b45b008607b9a9108bb96f3c1c089d3' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000000e' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x8d9e19b3f4c7c233a6112e5397309f9812a4f61f754f11dd3dcb8b07d55a7b1dfea65f19a1488a14fef9a41495083582' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000000f' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xa73eb991aa22cdb794da6fcde55a427f0a4df5a4a70de23a988b5e5fc8c4d844f66d990273267a54dd21579b7ba6a086' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000010' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xb098f178f84fc753a76bb63709e9be91eec3ff5f7f3a5f4836f34fe8a1a6d6c5578d8fd820573cef3a01e2bfef3eaf3a' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000011' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x9252a4ac3529f8b2b6e8189b95a60b8865f07f9a9b73f98d5df708511d3f68632c4c7d1e2b03e6b1d1e2c01839752ada' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000012' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xb271205227c7aa27f45f20b3ba380dfea8b51efae91fd32e552774c99e2a1237aa59c0c43f52aad99bba3783ea2f36a4' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000013' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xa272e9d1d50a4aea7d8f0583948090d0888be5777f2846800b8281139cd4aa9eee05f89b069857a3e77ccfaae1615f9c' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000014' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x9780e853f8ce7eda772c6691d25e220ca1d2ab0db51a7824b700620f7ac94c06639e91c98bb6abd78128f0ec845df8ef' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000015' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xab48aa2cc6f4a0bb63b5d67be54ac3aed10326dda304c5aeb9e942b40d6e7610478377680ab90e092ef1895e62786008' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000016' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x8c8b694b04d98a749a0763c72fc020ef61b2bb3f63ebb182cb2e568f6a8b9ca3ae013ae78317599e7e7ba2a528ec754a' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000017' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x9717182463fbe215168e6762abcbb55c5c65290f2b5a2af616f8a6f50d625b46164178a11622d21913efdfa4b800648d' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000018' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xacb58c81ae0cae2e9d4d446b730922239923c345744eee58efaadb36e9a0925545b18a987acf0bad469035b291e37269' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000019' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x81ccc19e3b938ec2405099e90022a4218baa5082a3ca0974b24be0bc8b07e5fffaed64bef0d02c4dbfb6a307829afc5c' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000001a' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xab83dfefb120fab7665a607d749ef1765fbb3cc0ba5827a20a135402c09d987c701ddb5b60f0f5495026817e8ab6ea2e' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000001b' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xb6ad11e5d15f77c1143b1697344911b9c590110fdd8dd09df2e58bfd757269169deefe8be3544d4e049fb3776fb0bcfb' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000001c' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0x8515e7f61ca0470e165a44d247a23f17f24bf6e37185467bedb7981c1003ea70bbec875703f793dd8d11e56afa7f74ba' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000001d' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xad84464b3966ec5bede84aa487facfca7823af383715078da03b387cc2f5d5597cdd7d025aa07db00a38b953bdeb6e3f' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000001e' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xb29043a7273d0a2dbc2b747dcf6a5eccbd7ccb44b2d72e985537b117929bc3fd3a99001481327788ad040b4077c47c0d' - withdrawal_credentials: '0x000000000000000000000000000000000000000000000000000000000000001f' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - - pubkey: '0xa72841987e4f219d54f2b6a9eac5fe6e78704644753c3579e776a3691bc123743f8c63770ed0f72a71e9e964dbf58f43' - withdrawal_credentials: '0x0000000000000000000000000000000000000000000000000000000000000020' - activation_epoch: 536870912 - exit_epoch: 18446744073709551615 - withdrawable_epoch: 18446744073709551615 - initiated_exit: false - slashed: false - validator_balances: - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - - 32000000000 - validator_registry_update_epoch: 536870912 - latest_randao_mixes: - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - previous_shuffling_start_shard: 0 - current_shuffling_start_shard: 0 - previous_shuffling_epoch: 536870912 - current_shuffling_epoch: 536870912 - previous_shuffling_seed: '0x0000000000000000000000000000000000000000000000000000000000000000' - current_shuffling_seed: '0x7a81d831e99dc63f9f10d4abce84c26473d4c2f65ec4acf9000684059473b072' - previous_epoch_attestations: [] - current_epoch_attestations: [] - previous_justified_epoch: 536870912 - current_justified_epoch: 536870912 - previous_justified_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - current_justified_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - justification_bitfield: 0 - finalized_epoch: 536870912 - finalized_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - latest_crosslinks: - - epoch: 536870912 - crosslink_data_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - - epoch: 536870912 - crosslink_data_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - - epoch: 536870912 - crosslink_data_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - - epoch: 536870912 - crosslink_data_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - - epoch: 536870912 - crosslink_data_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - - epoch: 536870912 - crosslink_data_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - - epoch: 536870912 - crosslink_data_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - - epoch: 536870912 - crosslink_data_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - latest_block_roots: - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - latest_state_roots: - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - - '0x0000000000000000000000000000000000000000000000000000000000000000' - latest_active_index_roots: - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - - '0x429a7560eb31fa5d1192496997a78ffc590e70f5b39220abff4420298061501a' - latest_slashed_balances: - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - latest_block_header: - slot: 4294967296 - previous_block_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - state_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - block_body_root: '0x13f2001ff0ee4a528b3c43f63d70a997aefca990ed8eada2223ee6ec3807f7cc' - signature: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - historical_roots: [] - latest_eth1_data: - deposit_root: '0x826d25bfcb9161aabc799844c5176f7b3444dc5288856f65e0b8060560488912' - block_hash: '0x0000000000000000000000000000000000000000000000000000000000000000' - eth1_data_votes: [] - deposit_index: 32 - blocks: - - slot: 4294967297 - previous_block_root: '0x2befbd4b4fe8c91f3059082c8048e3376a9b7fb309e93044fac32b7cc8849773' - state_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - body: - randao_reveal: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - eth1_data: - deposit_root: '0x0000000000000000000000000000000000000000000000000000000000000000' - block_hash: '0x0000000000000000000000000000000000000000000000000000000000000000' - proposer_slashings: [] - attester_slashings: [] - attestations: [] - deposits: [] - voluntary_exits: [] - transfers: [] - signature: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - expected_state: - slot: 4294967297 diff --git a/eth2/state_processing/tests/tests.rs b/eth2/state_processing/tests/tests.rs index b6aa3e76f..39882cafb 100644 --- a/eth2/state_processing/tests/tests.rs +++ b/eth2/state_processing/tests/tests.rs @@ -1,5 +1,7 @@ use serde_derive::Deserialize; use types::*; +#[allow(unused_imports)] +use yaml_utils; #[derive(Debug, Deserialize)] pub struct TestCase { @@ -23,9 +25,10 @@ fn yaml() { use serde_yaml; use std::{fs::File, io::prelude::*, path::PathBuf}; + // Test sanity-check_small-config_32-vals.yaml let mut file = { let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push("specs/example.yml"); + file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml"); File::open(file_path_buf).unwrap() }; @@ -34,7 +37,23 @@ fn yaml() { file.read_to_string(&mut yaml_str).unwrap(); - let yaml_str = yaml_str.to_lowercase(); + yaml_str = yaml_str.to_lowercase(); + + let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap(); + + // Test sanity-check_default-config_100-vals.yaml + file = { + let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + file_path_buf.push("yaml_utils/specs/sanity-check_default-config_100-vals.yaml"); + + File::open(file_path_buf).unwrap() + }; + + yaml_str = String::new(); + + file.read_to_string(&mut yaml_str).unwrap(); + + yaml_str = yaml_str.to_lowercase(); let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap(); } diff --git a/eth2/state_processing/yaml_utils/Cargo.toml b/eth2/state_processing/yaml_utils/Cargo.toml new file mode 100644 index 000000000..4a7ae5b89 --- /dev/null +++ b/eth2/state_processing/yaml_utils/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "yaml-utils" +version = "0.1.0" +authors = ["Kirk Baird "] +edition = "2018" + +[build-dependencies] +reqwest = "0.9" +tempdir = "0.3" + +[dependencies] + +[lib] +name = "yaml_utils" +path = "src/lib.rs" diff --git a/eth2/state_processing/yaml_utils/build.rs b/eth2/state_processing/yaml_utils/build.rs new file mode 100644 index 000000000..3b7f31471 --- /dev/null +++ b/eth2/state_processing/yaml_utils/build.rs @@ -0,0 +1,28 @@ +extern crate reqwest; +extern crate tempdir; + +use std::fs::File; +use std::io::copy; + +fn main() { + // These test files are not to be stored in the lighthouse repo as they are quite large (32MB). + // They will be downloaded at build time by yaml-utils crate (in build.rs) + let git_path = "https://raw.githubusercontent.com/ethereum/eth2.0-tests/master/state/"; + let test_names = vec![ + "sanity-check_default-config_100-vals.yaml", + "sanity-check_small-config_32-vals.yaml", + ]; + + for test in test_names { + let mut target = String::from(git_path); + target.push_str(test); + let mut response = reqwest::get(target.as_str()).unwrap(); + + let mut dest = { + let mut file_name = String::from("specs/"); + file_name.push_str(test); + File::create(file_name).unwrap() + }; + copy(&mut response, &mut dest).unwrap(); + } +} diff --git a/eth2/state_processing/yaml_utils/src/lib.rs b/eth2/state_processing/yaml_utils/src/lib.rs new file mode 100644 index 000000000..644ea434b --- /dev/null +++ b/eth2/state_processing/yaml_utils/src/lib.rs @@ -0,0 +1 @@ +// This is a place holder such that yaml-utils is now a crate hence build.rs will be run when 'cargo test' is called diff --git a/eth2/types/src/test_utils/serde_utils.rs b/eth2/types/src/test_utils/serde_utils.rs index e0e88fbec..761aee523 100644 --- a/eth2/types/src/test_utils/serde_utils.rs +++ b/eth2/types/src/test_utils/serde_utils.rs @@ -1,6 +1,8 @@ use serde::de::Error; use serde::{Deserialize, Deserializer}; +pub const FORK_BYTES_LEN: usize = 4; + pub fn u8_from_hex_str<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -10,14 +12,18 @@ where u8::from_str_radix(&s.as_str()[2..], 16).map_err(D::Error::custom) } -pub fn fork_from_hex_str<'de, D>(deserializer: D) -> Result<[u8; 4], D::Error> +pub fn fork_from_hex_str<'de, D>(deserializer: D) -> Result<[u8; FORK_BYTES_LEN], D::Error> where D: Deserializer<'de>, { let s: String = Deserialize::deserialize(deserializer)?; - let mut array = [0 as u8; 4]; + let mut array = [0 as u8; FORK_BYTES_LEN]; let decoded: Vec = hex::decode(&s.as_str()[2..]).map_err(D::Error::custom)?; + if decoded.len() > FORK_BYTES_LEN { + return Err(D::Error::custom("Fork length too long")); + } + for (i, item) in array.iter_mut().enumerate() { if i > decoded.len() { break; diff --git a/eth2/utils/bls/src/aggregate_signature.rs b/eth2/utils/bls/src/aggregate_signature.rs index 7b80d3bbf..922fae4f6 100644 --- a/eth2/utils/bls/src/aggregate_signature.rs +++ b/eth2/utils/bls/src/aggregate_signature.rs @@ -1,30 +1,39 @@ -use super::{AggregatePublicKey, Signature}; +use super::{AggregatePublicKey, Signature, BLS_AGG_SIG_BYTE_SIZE}; use bls_aggregates::{ AggregatePublicKey as RawAggregatePublicKey, AggregateSignature as RawAggregateSignature, }; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode as hex_encode, PrefixedHexVisitor}; -use ssz::{ - decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, -}; +use ssz::{decode_ssz_list, hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; /// A BLS aggregate signature. /// /// This struct is a wrapper upon a base type and provides helper functions (e.g., SSZ /// serialization). #[derive(Debug, PartialEq, Clone, Default, Eq)] -pub struct AggregateSignature(RawAggregateSignature); +pub struct AggregateSignature { + aggregate_signature: RawAggregateSignature, + is_empty: bool, +} impl AggregateSignature { /// Instantiate a new AggregateSignature. + /// + /// is_empty is false + /// AggregateSiganture is point at infinity pub fn new() -> Self { - AggregateSignature(RawAggregateSignature::new()) + Self { + aggregate_signature: RawAggregateSignature::new(), + is_empty: false, + } } /// Add (aggregate) a signature to the `AggregateSignature`. pub fn add(&mut self, signature: &Signature) { - self.0.add(signature.as_raw()) + if !self.is_empty { + self.aggregate_signature.add(signature.as_raw()) + } } /// Verify the `AggregateSignature` against an `AggregatePublicKey`. @@ -37,7 +46,11 @@ impl AggregateSignature { domain: u64, aggregate_public_key: &AggregatePublicKey, ) -> bool { - self.0.verify(msg, domain, aggregate_public_key.as_raw()) + if self.is_empty { + return false; + } + self.aggregate_signature + .verify(msg, domain, aggregate_public_key.as_raw()) } /// Verify this AggregateSignature against multiple AggregatePublickeys with multiple Messages. @@ -50,6 +63,9 @@ impl AggregateSignature { domain: u64, aggregate_public_keys: &[&AggregatePublicKey], ) -> bool { + if self.is_empty { + return false; + } let aggregate_public_keys: Vec<&RawAggregatePublicKey> = aggregate_public_keys.iter().map(|pk| pk.as_raw()).collect(); @@ -59,14 +75,53 @@ impl AggregateSignature { msg.extend_from_slice(message); } - self.0 + self.aggregate_signature .verify_multiple(&msg[..], domain, &aggregate_public_keys[..]) } + + /// Return AggregateSiganture as bytes + pub fn as_bytes(&self) -> Vec { + if self.is_empty { + return vec![0; BLS_AGG_SIG_BYTE_SIZE]; + } + self.aggregate_signature.as_bytes() + } + + /// Convert bytes to AggregateSiganture + pub fn from_bytes(bytes: &[u8]) -> Result { + for byte in bytes { + if *byte != 0 { + let sig = + RawAggregateSignature::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?; + return Ok(Self { + aggregate_signature: sig, + is_empty: false, + }); + } + } + Ok(Self::empty_signature()) + } + + /// Returns if the AggregateSiganture `is_empty` + pub fn is_empty(&self) -> bool { + self.is_empty + } + + /// Creates a new AggregateSignature + /// + /// aggregate_signature set to the point infinity + /// is_empty set to true + pub fn empty_signature() -> Self { + Self { + aggregate_signature: RawAggregateSignature::new(), + is_empty: true, + } + } } impl Encodable for AggregateSignature { fn ssz_append(&self, s: &mut SszStream) { - s.append_vec(&self.0.as_bytes()); + s.append_vec(&self.as_bytes()); } } @@ -74,35 +129,43 @@ impl Decodable for AggregateSignature { fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { let (sig_bytes, i) = decode_ssz_list(bytes, i)?; let raw_sig = - RawAggregateSignature::from_bytes(&sig_bytes).map_err(|_| DecodeError::TooShort)?; - Ok((AggregateSignature(raw_sig), i)) + RawAggregateSignature::from_bytes(&sig_bytes).map_err(|_| DecodeError::Invalid)?; + Ok(( + Self { + aggregate_signature: raw_sig, + is_empty: false, + }, + i, + )) } } impl Serialize for AggregateSignature { + /// Serde serialization is compliant the Ethereum YAML test format. fn serialize(&self, serializer: S) -> Result where S: Serializer, { - serializer.serialize_str(&hex_encode(ssz_encode(self))) + serializer.serialize_str(&hex_encode(self.as_bytes())) } } impl<'de> Deserialize<'de> for AggregateSignature { + /// Serde serialization is compliant the Ethereum YAML test format. fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; - let (obj, _) = <_>::ssz_decode(&bytes[..], 0) + let agg_sig = AggregateSignature::from_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; - Ok(obj) + Ok(agg_sig) } } impl TreeHash for AggregateSignature { fn hash_tree_root(&self) -> Vec { - hash(&self.0.as_bytes()) + hash(&self.as_bytes()) } } diff --git a/eth2/utils/bls/src/lib.rs b/eth2/utils/bls/src/lib.rs index 38a129908..77fd531f7 100644 --- a/eth2/utils/bls/src/lib.rs +++ b/eth2/utils/bls/src/lib.rs @@ -17,6 +17,7 @@ pub use crate::secret_key::SecretKey; pub use crate::signature::Signature; pub const BLS_AGG_SIG_BYTE_SIZE: usize = 96; +pub const BLS_SIG_BYTE_SIZE: usize = 96; use hashing::hash; use ssz::ssz_encode; diff --git a/eth2/utils/bls/src/signature.rs b/eth2/utils/bls/src/signature.rs index 8a080e56d..42c307cbe 100644 --- a/eth2/utils/bls/src/signature.rs +++ b/eth2/utils/bls/src/signature.rs @@ -1,5 +1,5 @@ use super::serde_vistors::HexVisitor; -use super::{PublicKey, SecretKey}; +use super::{PublicKey, SecretKey, BLS_SIG_BYTE_SIZE}; use bls_aggregates::Signature as RawSignature; use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; @@ -63,7 +63,7 @@ impl Signature { /// Returns a new empty signature. pub fn empty_signature() -> Self { // Set RawSignature = infinity - let mut empty: Vec = vec![0; 96]; + let mut empty: Vec = vec![0; BLS_SIG_BYTE_SIZE]; empty[0] += u8::pow(2, 6) + u8::pow(2, 7); Signature { signature: RawSignature::from_bytes(&empty).unwrap(), @@ -121,6 +121,7 @@ impl TreeHash for Signature { } impl Serialize for Signature { + /// Serde serialization is compliant the Ethereum YAML test format. fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -130,14 +131,15 @@ impl Serialize for Signature { } impl<'de> Deserialize<'de> for Signature { + /// Serde serialization is compliant the Ethereum YAML test format. fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - let bytes = deserializer.deserialize_str(HexVisitor)?; - let (pubkey, _) = <_>::ssz_decode(&bytes[..], 0) + let bytes: Vec = deserializer.deserialize_str(HexVisitor)?; + let signature = Signature::from_bytes(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; - Ok(pubkey) + Ok(signature) } } @@ -165,7 +167,7 @@ mod tests { let sig_as_bytes: Vec = sig.as_raw().as_bytes(); - assert_eq!(sig_as_bytes.len(), 96); + assert_eq!(sig_as_bytes.len(), BLS_SIG_BYTE_SIZE); for (i, one_byte) in sig_as_bytes.iter().enumerate() { if i == 0 { assert_eq!(*one_byte, u8::pow(2, 6) + u8::pow(2, 7)); diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index 443cd06da..161b365bb 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -186,7 +186,7 @@ impl Serialize for BooleanBitfield { where S: Serializer, { - serializer.serialize_str(&encode(&ssz::ssz_encode(self))) + serializer.serialize_str(&encode(&self.to_bytes())) } } @@ -197,9 +197,7 @@ impl<'de> Deserialize<'de> for BooleanBitfield { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; - let (bitfield, _) = <_>::ssz_decode(&bytes[..], 0) - .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; - Ok(bitfield) + Ok(BooleanBitfield::from_bytes(&bytes)) } } From 9d65ee130da7d454f4ee5162832338f6e7edf514 Mon Sep 17 00:00:00 2001 From: Kirk Baird Date: Mon, 25 Mar 2019 18:42:41 +1100 Subject: [PATCH 024/106] Include yaml-utils/specs folder --- .gitignore | 1 - eth2/state_processing/yaml_utils/specs/.gitignore | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 eth2/state_processing/yaml_utils/specs/.gitignore diff --git a/.gitignore b/.gitignore index ad0c3c152..346ef9afa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ Cargo.lock *.pk *.sk *.raw_keypairs -eth2/state_processing/yaml_utils/specs/*.yaml diff --git a/eth2/state_processing/yaml_utils/specs/.gitignore b/eth2/state_processing/yaml_utils/specs/.gitignore new file mode 100644 index 000000000..1e82fc7de --- /dev/null +++ b/eth2/state_processing/yaml_utils/specs/.gitignore @@ -0,0 +1 @@ +*.yaml From 299dfe43aa78a59540eabacd95f16be549896b47 Mon Sep 17 00:00:00 2001 From: Kirk Baird Date: Tue, 26 Mar 2019 15:16:55 +1100 Subject: [PATCH 025/106] Add .gitignore to make .../yaml_utils/specs a valid directory again --- .gitignore | 1 - eth2/state_processing/yaml_utils/specs/.gitignore | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 eth2/state_processing/yaml_utils/specs/.gitignore diff --git a/.gitignore b/.gitignore index ad0c3c152..346ef9afa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ Cargo.lock *.pk *.sk *.raw_keypairs -eth2/state_processing/yaml_utils/specs/*.yaml diff --git a/eth2/state_processing/yaml_utils/specs/.gitignore b/eth2/state_processing/yaml_utils/specs/.gitignore new file mode 100644 index 000000000..1e82fc7de --- /dev/null +++ b/eth2/state_processing/yaml_utils/specs/.gitignore @@ -0,0 +1 @@ +*.yaml From fd2f9d0d15b3f0ab8b2f31551679822ed5a372d5 Mon Sep 17 00:00:00 2001 From: Kirk Baird Date: Tue, 26 Mar 2019 16:45:25 +1100 Subject: [PATCH 026/106] Remove ssz encoding of length from; Signature, AggregateSiganture, PublicKey, SecretKey --- eth2/utils/bls/src/aggregate_signature.rs | 26 ++++++++++------------- eth2/utils/bls/src/lib.rs | 2 ++ eth2/utils/bls/src/public_key.rs | 24 ++++++++++----------- eth2/utils/bls/src/secret_key.rs | 16 ++++++++------ eth2/utils/bls/src/signature.rs | 17 +++++++-------- eth2/utils/boolean-bitfield/src/lib.rs | 3 --- eth2/utils/ssz/src/decode.rs | 1 + 7 files changed, 43 insertions(+), 46 deletions(-) diff --git a/eth2/utils/bls/src/aggregate_signature.rs b/eth2/utils/bls/src/aggregate_signature.rs index 783a86ebb..585584545 100644 --- a/eth2/utils/bls/src/aggregate_signature.rs +++ b/eth2/utils/bls/src/aggregate_signature.rs @@ -4,8 +4,8 @@ use bls_aggregates::{ }; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; -use serde_hex::{encode as hex_encode, PrefixedHexVisitor}; -use ssz::{decode_ssz_list, hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use serde_hex::{encode as hex_encode, HexVisitor}; +use ssz::{decode, hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; /// A BLS aggregate signature. /// @@ -121,22 +121,18 @@ impl AggregateSignature { impl Encodable for AggregateSignature { fn ssz_append(&self, s: &mut SszStream) { - s.append_vec(&self.as_bytes()); + s.append_encoded_raw(&self.as_bytes()); } } impl Decodable for AggregateSignature { fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - let (sig_bytes, i) = decode_ssz_list(bytes, i)?; - let raw_sig = - RawAggregateSignature::from_bytes(&sig_bytes).map_err(|_| DecodeError::Invalid)?; - Ok(( - Self { - aggregate_signature: raw_sig, - is_empty: false, - }, - i, - )) + if bytes.len() - i < BLS_AGG_SIG_BYTE_SIZE { + return Err(DecodeError::TooShort); + } + let agg_sig = AggregateSignature::from_bytes(&bytes[i..(i + BLS_AGG_SIG_BYTE_SIZE)]) + .map_err(|_| DecodeError::Invalid)?; + Ok((agg_sig, i + BLS_AGG_SIG_BYTE_SIZE)) } } @@ -156,8 +152,8 @@ impl<'de> Deserialize<'de> for AggregateSignature { where D: Deserializer<'de>, { - let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; - let agg_sig = AggregateSignature::from_bytes(&bytes[..]) + let bytes = deserializer.deserialize_str(HexVisitor)?; + let agg_sig = decode(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(agg_sig) } diff --git a/eth2/utils/bls/src/lib.rs b/eth2/utils/bls/src/lib.rs index b8fb2157f..57c463ace 100644 --- a/eth2/utils/bls/src/lib.rs +++ b/eth2/utils/bls/src/lib.rs @@ -17,6 +17,8 @@ pub use crate::signature::Signature; pub const BLS_AGG_SIG_BYTE_SIZE: usize = 96; pub const BLS_SIG_BYTE_SIZE: usize = 96; +pub const BLS_SECRET_KEY_BYTE_SIZE: usize = 48; +pub const BLS_PUBLIC_KEY_BYTE_SIZE: usize = 48; use hashing::hash; use ssz::ssz_encode; diff --git a/eth2/utils/bls/src/public_key.rs b/eth2/utils/bls/src/public_key.rs index 346bb7de3..98ff40d71 100644 --- a/eth2/utils/bls/src/public_key.rs +++ b/eth2/utils/bls/src/public_key.rs @@ -1,12 +1,9 @@ -use super::SecretKey; +use super::{SecretKey, BLS_PUBLIC_KEY_BYTE_SIZE}; use bls_aggregates::PublicKey as RawPublicKey; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; -use serde_hex::{encode as hex_encode, PrefixedHexVisitor}; -use ssz::{ - decode, decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, - TreeHash, -}; +use serde_hex::{encode as hex_encode, HexVisitor}; +use ssz::{decode, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use std::default; use std::hash::{Hash, Hasher}; @@ -64,15 +61,18 @@ impl default::Default for PublicKey { impl Encodable for PublicKey { fn ssz_append(&self, s: &mut SszStream) { - s.append_vec(&self.0.as_bytes()); + s.append_encoded_raw(&self.0.as_bytes()); } } impl Decodable for PublicKey { fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - let (sig_bytes, i) = decode_ssz_list(bytes, i)?; - let raw_sig = RawPublicKey::from_bytes(&sig_bytes).map_err(|_| DecodeError::TooShort)?; - Ok((PublicKey(raw_sig), i)) + if bytes.len() - i < BLS_PUBLIC_KEY_BYTE_SIZE { + return Err(DecodeError::TooShort); + } + let raw_sig = RawPublicKey::from_bytes(&bytes[i..(i + BLS_PUBLIC_KEY_BYTE_SIZE)]) + .map_err(|_| DecodeError::TooShort)?; + Ok((PublicKey(raw_sig), i + BLS_PUBLIC_KEY_BYTE_SIZE)) } } @@ -90,8 +90,8 @@ impl<'de> Deserialize<'de> for PublicKey { where D: Deserializer<'de>, { - let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; - let pubkey = PublicKey::from_bytes(&bytes[..]) + let bytes = deserializer.deserialize_str(HexVisitor)?; + let pubkey = decode(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid pubkey ({:?})", e)))?; Ok(pubkey) } diff --git a/eth2/utils/bls/src/secret_key.rs b/eth2/utils/bls/src/secret_key.rs index 6e57f8e1e..40c469513 100644 --- a/eth2/utils/bls/src/secret_key.rs +++ b/eth2/utils/bls/src/secret_key.rs @@ -1,11 +1,10 @@ +use super::BLS_SECRET_KEY_BYTE_SIZE; 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 serde_hex::HexVisitor; -use ssz::{ - decode, decode_ssz_list, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, -}; +use ssz::{decode, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; /// A single BLS signature. /// @@ -34,15 +33,18 @@ impl SecretKey { impl Encodable for SecretKey { fn ssz_append(&self, s: &mut SszStream) { - s.append_vec(&self.0.as_bytes()); + s.append_encoded_raw(&self.0.as_bytes()); } } impl Decodable for SecretKey { fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - let (sig_bytes, i) = decode_ssz_list(bytes, i)?; - let raw_sig = RawSecretKey::from_bytes(&sig_bytes).map_err(|_| DecodeError::TooShort)?; - Ok((SecretKey(raw_sig), i)) + if bytes.len() - i < BLS_SECRET_KEY_BYTE_SIZE { + return Err(DecodeError::TooShort); + } + let raw_sig = RawSecretKey::from_bytes(&bytes[i..(i + BLS_SECRET_KEY_BYTE_SIZE)]) + .map_err(|_| DecodeError::TooShort)?; + Ok((SecretKey(raw_sig), i + BLS_SECRET_KEY_BYTE_SIZE)) } } diff --git a/eth2/utils/bls/src/signature.rs b/eth2/utils/bls/src/signature.rs index e1a146981..d19af545f 100644 --- a/eth2/utils/bls/src/signature.rs +++ b/eth2/utils/bls/src/signature.rs @@ -4,10 +4,7 @@ use hex::encode as hex_encode; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::HexVisitor; -use ssz::{ - decode, decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, - TreeHash, -}; +use ssz::{decode, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; /// A single BLS signature. /// @@ -103,15 +100,17 @@ impl Signature { impl Encodable for Signature { fn ssz_append(&self, s: &mut SszStream) { - s.append_vec(&self.as_bytes()); + s.append_encoded_raw(&self.as_bytes()); } } impl Decodable for Signature { fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - let (sig_bytes, i) = decode_ssz_list(bytes, i)?; - let signature = Signature::from_bytes(&sig_bytes)?; - Ok((signature, i)) + if bytes.len() - i < BLS_SIG_BYTE_SIZE { + return Err(DecodeError::TooShort); + } + let signature = Signature::from_bytes(&bytes[i..(i + BLS_SIG_BYTE_SIZE)])?; + Ok((signature, i + BLS_SIG_BYTE_SIZE)) } } @@ -138,7 +137,7 @@ impl<'de> Deserialize<'de> for Signature { D: Deserializer<'de>, { let bytes = deserializer.deserialize_str(HexVisitor)?; - let signature = Signature::from_bytes(&bytes[..]) + let signature = decode(&bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; Ok(signature) } diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index 78e502073..ac637b3aa 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -145,10 +145,7 @@ impl std::ops::BitAnd for BooleanBitfield { } impl Encodable for BooleanBitfield { -<<<<<<< HEAD -======= // ssz_append encodes Self according to the `ssz` spec. ->>>>>>> v0.5.0-state-transition-tests fn ssz_append(&self, s: &mut ssz::SszStream) { s.append_vec(&self.to_bytes()) } diff --git a/eth2/utils/ssz/src/decode.rs b/eth2/utils/ssz/src/decode.rs index efc8c38db..7ed6fe491 100644 --- a/eth2/utils/ssz/src/decode.rs +++ b/eth2/utils/ssz/src/decode.rs @@ -15,6 +15,7 @@ pub trait Decodable: Sized { /// /// The single ssz encoded value/container/list will be decoded as the given type, /// by recursively calling `ssz_decode`. +/// Check on totality for underflowing the length of bytes and overflow checks done per container pub fn decode(ssz_bytes: &[u8]) -> Result<(T), DecodeError> where T: Decodable, From 1584469b7c754da9c45f36bf944ea14a21292da7 Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Tue, 26 Mar 2019 17:41:43 +1100 Subject: [PATCH 027/106] Renamed attestation -> attestation_data for fetch, but not publish, to acknowledge the difference in the spec. Also started implementing the gRPC get_attestation_data functionality in the BeaconNode. --- .../validator_harness/direct_beacon_node.rs | 2 +- beacon_node/rpc/src/beacon_attester.rs | 59 +++++++++++++------ eth2/attester/src/lib.rs | 2 +- .../src/test_utils/simulated_beacon_node.rs | 2 +- eth2/attester/src/traits.rs | 2 +- protos/src/services.proto | 12 ++-- .../attestation_grpc_client.rs | 6 +- 7 files changed, 53 insertions(+), 32 deletions(-) diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs index fde8211ab..17630833b 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs @@ -50,7 +50,7 @@ impl DirectBeaconNode { } impl AttesterBeaconNode for DirectBeaconNode { - fn produce_attestation( + fn produce_attestation_data( &self, _slot: Slot, shard: u64, diff --git a/beacon_node/rpc/src/beacon_attester.rs b/beacon_node/rpc/src/beacon_attester.rs index 36b6a40b2..88caacdd0 100644 --- a/beacon_node/rpc/src/beacon_attester.rs +++ b/beacon_node/rpc/src/beacon_attester.rs @@ -1,45 +1,66 @@ +use crate::beacon_chain::BeaconChain; use futures::Future; -use grpcio::{RpcContext, UnarySink}; +use grpcio::{RpcContext, UnarySink, RpcStatus, RpcStatusCode}; use protos::services::{ - Attestation as AttestationProto, ProduceAttestation, ProduceAttestationResponse, - ProduceAttestationRequest, PublishAttestationResponse, PublishAttestationRequest, + AttestationData as AttestationDataProto, ProduceAttestationData, ProduceAttestationDataResponse, + ProduceAttestationDataRequest, PublishAttestationResponse, PublishAttestationRequest, PublishAttestation }; use protos::services_grpc::BeaconBlockService; -use slog::Logger; +use slog::{Logger, info, warn, error}; #[derive(Clone)] pub struct AttestationServiceInstance { + pub chain: Arc, pub log: Logger, } impl AttestationService for AttestationServiceInstance { - /// Produce a `BeaconBlock` for signing by a validator. - fn produce_attestation( + /// Produce the `AttestationData` for signing by a validator. + fn produce_attestation_data( &mut self, ctx: RpcContext, - req: ProduceAttestationRequest, - sink: UnarySink, + req: ProduceAttestationDataRequest, + sink: UnarySink, ) { - println!("producing attestation at slot {}", req.get_slot()); + info!(&self.log, "Attempting to produce attestation at slot {}", req.get_slot()); - // TODO: build a legit block. - let mut attestation = AttestationProto::new(); - attestation.set_slot(req.get_slot()); - // TODO Set the shard to something legit. - attestation.set_shard(0); - attestation.set_block_root(b"cats".to_vec()); + // get the chain spec & state + let spec = self.chain.get_spec(); + let state = self.chain.get_state(); - let mut resp = ProduceAttestationResponse::new(); - resp.set_attestation_data(attestation); + // Start by performing some checks + // Check that the the AttestionData is for the current slot (otherwise it will not be valid) + if req.get_slot() != state.slot { + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::OutOfRange, + "AttestationData request for a slot that is not the current slot." + )) + .map_err(move |e| error!(&self.log, "Failed to reply with failure {:?}: {:?}", req, e)); + } + + // Then collect the data we need for the AttesatationData object + //let beacon_block_root = state.latest_block_roots.first().ok_or_else(|e| ) + + // And finally build the AttestationData object + let mut attestation_data = AttestationDataProto::new(); + attestation_data.set_slot(state.slot.as_u64()); + attestation_data.set_shard(spec.genesis_start_shard); + attestation_data.set_beacon_block_root(b"cats".to_vec()); + //attestation_data. + + let mut resp = ProduceAttestationDataResponse::new(); + resp.set_attestation_data(attestation_data); let f = sink .success(resp) - .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e)); + .map_err(move |e| error!("Failed to reply with success {:?}: {:?}", req, e)); ctx.spawn(f) } - /// Accept some fully-formed `BeaconBlock`, process and publish it. + /// Accept some fully-formed `FreeAttestation` from the validator, + /// store it, and aggregate it into an `Attestation`. fn publish_attestation( &mut self, ctx: RpcContext, diff --git a/eth2/attester/src/lib.rs b/eth2/attester/src/lib.rs index 065fdc923..3f13555e3 100644 --- a/eth2/attester/src/lib.rs +++ b/eth2/attester/src/lib.rs @@ -94,7 +94,7 @@ impl Attester Result { - let attestation_data = match self.beacon_node.produce_attestation(slot, shard)? { + let attestation_data = match self.beacon_node.produce_attestation_data(slot, shard)? { Some(attestation_data) => attestation_data, None => return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation(slot)), }; diff --git a/eth2/attester/src/test_utils/simulated_beacon_node.rs b/eth2/attester/src/test_utils/simulated_beacon_node.rs index 84a203cdb..d19f43422 100644 --- a/eth2/attester/src/test_utils/simulated_beacon_node.rs +++ b/eth2/attester/src/test_utils/simulated_beacon_node.rs @@ -26,7 +26,7 @@ impl SimulatedBeaconNode { } impl BeaconNode for SimulatedBeaconNode { - fn produce_attestation(&self, slot: Slot, shard: u64) -> ProduceResult { + fn produce_attestation_data(&self, slot: Slot, shard: u64) -> ProduceResult { *self.produce_input.write().unwrap() = Some((slot, shard)); match *self.produce_result.read().unwrap() { Some(ref r) => r.clone(), diff --git a/eth2/attester/src/traits.rs b/eth2/attester/src/traits.rs index 749c6e1a2..2fd6940af 100644 --- a/eth2/attester/src/traits.rs +++ b/eth2/attester/src/traits.rs @@ -14,7 +14,7 @@ pub enum PublishOutcome { /// Defines the methods required to produce and publish blocks on a Beacon Node. pub trait BeaconNode: Send + Sync { - fn produce_attestation( + fn produce_attestation_data( &self, slot: Slot, shard: u64, diff --git a/protos/src/services.proto b/protos/src/services.proto index 80d512c54..35b9c32af 100644 --- a/protos/src/services.proto +++ b/protos/src/services.proto @@ -33,7 +33,7 @@ service ValidatorService { /// Service that handles validator attestations service AttestationService { - rpc ProduceAttestation(ProduceAttestationRequest) returns (ProduceAttestationResponse); + rpc ProduceAttestation(ProduceAttestationDataRequest) returns (ProduceAttestationDataResponse); rpc PublishAttestation(PublishAttestationRequest) returns (PublishAttestationResponse); } @@ -138,13 +138,13 @@ message ProposeBlockSlotResponse { * Attestation Service Messages */ -message ProduceAttestationRequest { +message ProduceAttestationDataRequest { uint64 slot = 1; uint64 shard = 2; } -message ProduceAttestationResponse { - Attestation attestation_data = 1; +message ProduceAttestationDataResponse { + AttestationData attestation_data = 1; } message PublishAttestationRequest { @@ -162,7 +162,7 @@ message Crosslink { } -message Attestation { +message AttestationData { uint64 slot = 1; uint64 shard = 2; bytes beacon_block_root = 3; @@ -175,7 +175,7 @@ message Attestation { } message FreeAttestation { - Attestation attestation_data = 1; + AttestationData data = 1; bytes signature = 2; uint64 validator_index = 3; } diff --git a/validator_client/src/attester_service/attestation_grpc_client.rs b/validator_client/src/attester_service/attestation_grpc_client.rs index 5a4701ba9..f55acc4f7 100644 --- a/validator_client/src/attester_service/attestation_grpc_client.rs +++ b/validator_client/src/attester_service/attestation_grpc_client.rs @@ -2,7 +2,7 @@ use protos::services_grpc::AttestationServiceClient; use std::sync::Arc; use attester::{BeaconNode, BeaconNodeError, PublishOutcome}; -use protos::services::ProduceAttestationRequest; +use protos::services::ProduceAttestationDataRequest; use types::{AttestationData, FreeAttestation, Slot}; pub struct AttestationGrpcClient { @@ -16,12 +16,12 @@ impl AttestationGrpcClient { } impl BeaconNode for AttestationGrpcClient { - fn produce_attestation( + fn produce_attestation_data( &self, slot: Slot, shard: u64, ) -> Result, BeaconNodeError> { - let mut req = ProduceAttestationRequest::new(); + let mut req = ProduceAttestationDataRequest::new(); req.set_slot(slot.as_u64()); req.set_shard(shard); From 99dbed86f150e27aed61206c2683553183b56d43 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 26 Mar 2019 18:20:01 +1100 Subject: [PATCH 028/106] types: PendingAttestation::from_attestation --- eth2/state_processing/src/per_block_processing.rs | 8 +------- eth2/types/src/pending_attestation.rs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index e79f5f08c..6c52a2676 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -322,13 +322,7 @@ pub fn process_attestations( // Update the state in series. for attestation in attestations { - let pending_attestation = PendingAttestation { - data: attestation.data.clone(), - aggregation_bitfield: attestation.aggregation_bitfield.clone(), - custody_bitfield: attestation.custody_bitfield.clone(), - inclusion_slot: state.slot, - }; - + let pending_attestation = PendingAttestation::from_attestation(attestation, state.slot); let attestation_epoch = attestation.data.slot.epoch(spec.slots_per_epoch); if attestation_epoch == state.current_epoch(spec) { diff --git a/eth2/types/src/pending_attestation.rs b/eth2/types/src/pending_attestation.rs index ca50b6d1c..938e59bef 100644 --- a/eth2/types/src/pending_attestation.rs +++ b/eth2/types/src/pending_attestation.rs @@ -1,5 +1,5 @@ use crate::test_utils::TestRandom; -use crate::{AttestationData, Bitfield, Slot}; +use crate::{Attestation, AttestationData, Bitfield, Slot}; use rand::RngCore; use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode, TreeHash}; @@ -16,6 +16,18 @@ pub struct PendingAttestation { pub inclusion_slot: Slot, } +impl PendingAttestation { + /// Create a `PendingAttestation` from an `Attestation`, at the given `inclusion_slot`. + pub fn from_attestation(attestation: &Attestation, inclusion_slot: Slot) -> Self { + PendingAttestation { + data: attestation.data.clone(), + aggregation_bitfield: attestation.aggregation_bitfield.clone(), + custody_bitfield: attestation.custody_bitfield.clone(), + inclusion_slot, + } + } +} + #[cfg(test)] mod tests { use super::*; From 033ae1b7478c98b3f0828001e2cbddc92d80ce97 Mon Sep 17 00:00:00 2001 From: Kirk Baird Date: Tue, 26 Mar 2019 18:28:29 +1100 Subject: [PATCH 029/106] WIP begin testing --- eth2/state_processing/tests/tests.rs | 48 +++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/eth2/state_processing/tests/tests.rs b/eth2/state_processing/tests/tests.rs index 39882cafb..0363da810 100644 --- a/eth2/state_processing/tests/tests.rs +++ b/eth2/state_processing/tests/tests.rs @@ -1,4 +1,7 @@ +use state_processing::{per_block_processing, per_block_processing_without_verifying_block_signature, per_slot_processing}; use serde_derive::Deserialize; +use serde_yaml; +use std::{fs::File, io::prelude::*, path::PathBuf}; use types::*; #[allow(unused_imports)] use yaml_utils; @@ -21,10 +24,7 @@ pub struct TestDoc { } #[test] -fn yaml() { - use serde_yaml; - use std::{fs::File, io::prelude::*, path::PathBuf}; - +fn test_read_yaml() { // Test sanity-check_small-config_32-vals.yaml let mut file = { let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -57,3 +57,43 @@ fn yaml() { let _doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap(); } + +#[test] +fn run_state_transition_tests_small() { + // Test sanity-check_small-config_32-vals.yaml + let mut file = { + let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + file_path_buf.push("yaml_utils/specs/sanity-check_small-config_32-vals.yaml"); + + File::open(file_path_buf).unwrap() + }; + let mut yaml_str = String::new(); + file.read_to_string(&mut yaml_str).unwrap(); + yaml_str = yaml_str.to_lowercase(); + + let doc: TestDoc = serde_yaml::from_str(&yaml_str.as_str()).unwrap(); + + // Run Tests + for (i, test_case) in doc.test_cases.iter().enumerate() { + let mut state = test_case.initial_state.clone(); + for block in test_case.blocks.iter() { + while block.slot > state.slot { + let latest_block_header = state.latest_block_header.clone(); + let res = per_slot_processing(&mut state, &latest_block_header, &test_case.config).unwrap(); + } + if test_case.verify_signatures { + let res = per_block_processing(&mut state, &block, &test_case.config); + if res.is_err() { + println!("{:?}", i); + println!("{:?}", res); + }; + } else { + let res = per_block_processing_without_verifying_block_signature(&mut state, &block, &test_case.config); + if res.is_err() { + println!("{:?}", i); + println!("{:?}", res); + } + } + } + } +} From e5a3b3dd067773ae1c31d9bfa27c888e9505b669 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 26 Mar 2019 18:29:02 +1100 Subject: [PATCH 030/106] op-pool: attestation tests --- eth2/operation_pool/src/lib.rs | 290 ++++++++++++++++++++++++++++++++- 1 file changed, 289 insertions(+), 1 deletion(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index fadbf449d..e67a201c7 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -144,6 +144,11 @@ impl OperationPool { Ok(()) } + /// Total number of attestations in the pool, including attestations for the same data. + pub fn num_attestations(&self) -> usize { + self.attestations.values().map(|atts| atts.len()).sum() + } + /// Get a list of attestations for inclusion in a block. pub fn get_attestations(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { // Attestations for the current fork, which may be from the current or previous epoch. @@ -161,6 +166,7 @@ impl OperationPool { // That are valid... .filter(|attestation| validate_attestation(state, attestation, spec).is_ok()) // Scored by the number of new attestations they introduce (descending) + // TODO: need to consider attestations introduced in THIS block .map(|att| (att, attestation_score(att, state))) .sorted_by_key(|&(_, score)| std::cmp::Reverse(score)) // Limited to the maximum number of attestations per block @@ -484,7 +490,7 @@ fn prune_validator_hash_map( mod tests { use super::DepositInsertStatus::*; use super::*; - use types::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + use types::test_utils::*; use types::*; #[test] @@ -636,5 +642,287 @@ mod tests { (spec, state) } + /// Create a signed attestation for use in tests. + /// Signed by all validators in `committee[signing_range]` and `committee[extra_signer]`. + fn signed_attestation>( + committee: &CrosslinkCommittee, + keypairs: &[Keypair], + signing_range: R, + slot: Slot, + state: &BeaconState, + spec: &ChainSpec, + extra_signer: Option, + ) -> Attestation { + let mut builder = TestingAttestationBuilder::new( + state, + &committee.committee, + slot, + committee.shard, + spec, + ); + let signers = &committee.committee[signing_range]; + let committee_keys = signers.iter().map(|&i| &keypairs[i].sk).collect::>(); + builder.sign(signers, &committee_keys, &state.fork, spec); + extra_signer.map(|c_idx| { + let validator_index = committee.committee[c_idx]; + builder.sign( + &[validator_index], + &[&keypairs[validator_index].sk], + &state.fork, + spec, + ) + }); + builder.build() + } + + /// Test state for attestation-related tests. + fn attestation_test_state( + spec: &ChainSpec, + num_committees: usize, + ) -> (BeaconState, Vec) { + let num_validators = + num_committees * (spec.slots_per_epoch * spec.target_committee_size) as usize; + let mut state_builder = + TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(num_validators, spec); + let slot_offset = 100000; + let slot = spec.genesis_slot + slot_offset; + state_builder.teleport_to_slot(slot, spec); + state_builder.build_caches(spec).unwrap(); + state_builder.build() + } + + /// Set the latest crosslink in the state to match the attestation. + fn fake_latest_crosslink(att: &Attestation, state: &mut BeaconState, spec: &ChainSpec) { + state.latest_crosslinks[att.data.shard as usize] = Crosslink { + crosslink_data_root: att.data.crosslink_data_root, + epoch: att.data.slot.epoch(spec.slots_per_epoch), + }; + } + + #[test] + fn test_attestation_score() { + let spec = &ChainSpec::foundation(); + let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); + + for committee in committees { + let att1 = signed_attestation(&committee, keypairs, ..2, slot, state, spec, None); + let att2 = signed_attestation(&committee, keypairs, .., slot, state, spec, None); + + assert_eq!( + att1.aggregation_bitfield.num_set_bits(), + attestation_score(&att1, state) + ); + + state + .current_epoch_attestations + .push(PendingAttestation::from_attestation(&att1, state.slot)); + + assert_eq!( + committee.committee.len() - 2, + attestation_score(&att2, &state) + ); + } + } + + /// End-to-end test of basic attestation handling. + #[test] + fn attestation_aggregation_insert_get_prune() { + let spec = &ChainSpec::foundation(); + let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); + let mut op_pool = OperationPool::new(); + + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); + + assert_eq!( + committees.len(), + 1, + "we expect just one committee with this many validators" + ); + + for committee in &committees { + let step_size = 2; + for i in (0..committee.committee.len()).step_by(step_size) { + let att = signed_attestation( + committee, + keypairs, + i..i + step_size, + slot, + state, + spec, + None, + ); + fake_latest_crosslink(&att, state, spec); + op_pool.insert_attestation(att, state, spec).unwrap(); + } + } + + assert_eq!(op_pool.attestations.len(), committees.len()); + assert_eq!(op_pool.num_attestations(), committees.len()); + + // Before the min attestation inclusion delay, get_attestations shouldn't return anything. + assert_eq!(op_pool.get_attestations(state, spec).len(), 0); + + // Then once the delay has elapsed, we should get a single aggregated attestation. + state.slot += spec.min_attestation_inclusion_delay; + + let block_attestations = op_pool.get_attestations(state, spec); + assert_eq!(block_attestations.len(), committees.len()); + + let agg_att = &block_attestations[0]; + assert_eq!( + agg_att.aggregation_bitfield.num_set_bits(), + spec.target_committee_size as usize + ); + + // Prune attestations shouldn't do anything at this point. + op_pool.prune_attestations(state, spec); + assert_eq!(op_pool.num_attestations(), committees.len()); + + // But once we advance to an epoch after the attestation, it should prune it out of + // existence. + state.slot = slot + spec.slots_per_epoch; + op_pool.prune_attestations(state, spec); + assert_eq!(op_pool.num_attestations(), 0); + } + + /// Adding an attestation already in the pool should not increase the size of the pool. + #[test] + fn attestation_duplicate() { + let spec = &ChainSpec::foundation(); + let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); + let mut op_pool = OperationPool::new(); + + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); + + for committee in &committees { + let att = signed_attestation(committee, keypairs, .., slot, state, spec, None); + fake_latest_crosslink(&att, state, spec); + op_pool + .insert_attestation(att.clone(), state, spec) + .unwrap(); + op_pool.insert_attestation(att, state, spec).unwrap(); + } + + assert_eq!(op_pool.num_attestations(), committees.len()); + } + + /// Adding lots of attestations that only intersect pairwise should lead to two aggregate + /// attestations. + #[test] + fn attestation_pairwise_overlapping() { + let spec = &ChainSpec::foundation(); + let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); + let mut op_pool = OperationPool::new(); + + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); + + let step_size = 2; + for committee in &committees { + // Create attestations that overlap on `step_size` validators, like: + // {0,1,2,3}, {2,3,4,5}, {4,5,6,7}, ... + for i in (0..committee.committee.len() - step_size).step_by(step_size) { + let att = signed_attestation( + committee, + keypairs, + i..i + 2 * step_size, + slot, + state, + spec, + None, + ); + fake_latest_crosslink(&att, state, spec); + op_pool.insert_attestation(att, state, spec).unwrap(); + } + } + + // The attestations should get aggregated into two attestations that comprise all + // validators. + assert_eq!(op_pool.attestations.len(), committees.len()); + assert_eq!(op_pool.num_attestations(), 2 * committees.len()); + } + + /// Create a bunch of attestations signed by a small number of validators, and another + /// bunch signed by a larger number, such that there are at least `max_attestations` + /// signed by the larger number. Then, check that `get_attestations` only returns the + /// high-quality attestations. To ensure that no aggregation occurs, ALL attestations + /// are also signed by the 0th member of the committee. + #[test] + fn attestation_get_max() { + let spec = &ChainSpec::foundation(); + let small_step_size = 2; + let big_step_size = 4; + let (ref mut state, ref keypairs) = attestation_test_state(spec, big_step_size); + let mut op_pool = OperationPool::new(); + + let slot = state.slot - 1; + let committees = state + .get_crosslink_committees_at_slot(slot, spec) + .unwrap() + .clone(); + + let max_attestations = spec.max_attestations as usize; + let target_committee_size = spec.target_committee_size as usize; + + let mut insert_attestations = |committee, step_size| { + for i in (0..target_committee_size).step_by(step_size) { + let att = signed_attestation( + committee, + keypairs, + i..i + step_size, + slot, + state, + spec, + if i == 0 { None } else { Some(0) }, + ); + fake_latest_crosslink(&att, state, spec); + op_pool.insert_attestation(att, state, spec).unwrap(); + } + }; + + for committee in &committees { + assert_eq!(committee.committee.len(), target_committee_size); + // Attestations signed by only 2-3 validators + insert_attestations(committee, small_step_size); + // Attestations signed by 4+ validators + insert_attestations(committee, big_step_size); + } + + let num_small = target_committee_size / small_step_size; + let num_big = target_committee_size / big_step_size; + + assert_eq!(op_pool.attestations.len(), committees.len()); + assert_eq!( + op_pool.num_attestations(), + (num_small + num_big) * committees.len() + ); + assert!(op_pool.num_attestations() > max_attestations); + + state.slot += spec.min_attestation_inclusion_delay; + let best_attestations = op_pool.get_attestations(state, spec); + assert_eq!(best_attestations.len(), max_attestations); + + // All the best attestations should be signed by at least `big_step_size` (4) validators. + for att in &best_attestations { + assert!(att.aggregation_bitfield.num_set_bits() >= big_step_size); + } + } + // TODO: more tests } From c9a7977d6998183458ab7a5d365ac08d8fa69257 Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Wed, 27 Mar 2019 14:30:09 +1100 Subject: [PATCH 031/106] Renamed some functions, trying to get beaconnode attestation stuff to work. --- beacon_node/beacon_chain/src/beacon_chain.rs | 2 +- beacon_node/rpc/src/beacon_attester.rs | 17 +++++++---------- protos/src/services.proto | 2 +- .../attester_service/attestation_grpc_client.rs | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 61b5fb58b..110d1a99d 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -280,7 +280,7 @@ where } /// Produce an `AttestationData` that is valid for the present `slot` and given `shard`. - pub fn produce_attestation(&self, shard: u64) -> Result { + pub fn produce_attestation_data(&self, shard: u64) -> Result { trace!("BeaconChain::produce_attestation: shard: {}", shard); let source_epoch = self.state.read().current_justified_epoch; let source_root = *self.state.read().get_block_root( diff --git a/beacon_node/rpc/src/beacon_attester.rs b/beacon_node/rpc/src/beacon_attester.rs index 88caacdd0..4166c30d4 100644 --- a/beacon_node/rpc/src/beacon_attester.rs +++ b/beacon_node/rpc/src/beacon_attester.rs @@ -9,6 +9,8 @@ use protos::services::{ use protos::services_grpc::BeaconBlockService; use slog::{Logger, info, warn, error}; +const TEST_SHARD_PHASE_ZERO: u8 = 0; + #[derive(Clone)] pub struct AttestationServiceInstance { pub chain: Arc, @@ -29,9 +31,11 @@ impl AttestationService for AttestationServiceInstance { let spec = self.chain.get_spec(); let state = self.chain.get_state(); + let slot_requested = req.get_slot(); + // Start by performing some checks // Check that the the AttestionData is for the current slot (otherwise it will not be valid) - if req.get_slot() != state.slot { + if slot_requested != state.slot { let f = sink .fail(RpcStatus::new( RpcStatusCode::OutOfRange, @@ -40,15 +44,8 @@ impl AttestationService for AttestationServiceInstance { .map_err(move |e| error!(&self.log, "Failed to reply with failure {:?}: {:?}", req, e)); } - // Then collect the data we need for the AttesatationData object - //let beacon_block_root = state.latest_block_roots.first().ok_or_else(|e| ) - - // And finally build the AttestationData object - let mut attestation_data = AttestationDataProto::new(); - attestation_data.set_slot(state.slot.as_u64()); - attestation_data.set_shard(spec.genesis_start_shard); - attestation_data.set_beacon_block_root(b"cats".to_vec()); - //attestation_data. + // Then get the AttestationData from the beacon chain (for shard 0 for now) + let attestation_data = self.chain.produce_attestation_data(TEST_SHARD_PHASE_ZERO); let mut resp = ProduceAttestationDataResponse::new(); resp.set_attestation_data(attestation_data); diff --git a/protos/src/services.proto b/protos/src/services.proto index 35b9c32af..1dfb53c06 100644 --- a/protos/src/services.proto +++ b/protos/src/services.proto @@ -33,7 +33,7 @@ service ValidatorService { /// Service that handles validator attestations service AttestationService { - rpc ProduceAttestation(ProduceAttestationDataRequest) returns (ProduceAttestationDataResponse); + rpc ProduceAttestationData(ProduceAttestationDataRequest) returns (ProduceAttestationDataResponse); rpc PublishAttestation(PublishAttestationRequest) returns (PublishAttestationResponse); } diff --git a/validator_client/src/attester_service/attestation_grpc_client.rs b/validator_client/src/attester_service/attestation_grpc_client.rs index f55acc4f7..bfb7f67c6 100644 --- a/validator_client/src/attester_service/attestation_grpc_client.rs +++ b/validator_client/src/attester_service/attestation_grpc_client.rs @@ -27,7 +27,7 @@ impl BeaconNode for AttestationGrpcClient { let reply = self .client - .produce_attestation(&req) + .produce_attestation_data(&req) .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; // TODO: return correct Attestation From bda381a2648fa21d420b14703bffa55539fc44d7 Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Thu, 28 Mar 2019 09:38:39 +1100 Subject: [PATCH 032/106] More progress towards getting the attester working. --- eth2/attester/src/lib.rs | 2 + validator_client/src/service.rs | 164 +++++++++++++++++--------------- 2 files changed, 87 insertions(+), 79 deletions(-) diff --git a/eth2/attester/src/lib.rs b/eth2/attester/src/lib.rs index 3f13555e3..7b1d26145 100644 --- a/eth2/attester/src/lib.rs +++ b/eth2/attester/src/lib.rs @@ -99,6 +99,8 @@ impl Attester return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation(slot)), }; + dbg!(&attestation_data); + if !self.safe_to_produce(&attestation_data) { return Ok(PollOutcome::SlashableAttestationNotProduced(slot)); } diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 8a7e90d10..4c6a49997 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -25,9 +25,12 @@ use tokio::runtime::Builder; use tokio::timer::Interval; use tokio_timer::clock::Clock; use types::{Epoch, Fork, Slot}; +use std::thread; //TODO: This service should be simplified in the future. Can be made more steamlined. +const POLL_INTERVAL_MILLIS: u64 = 100; + /// The validator service. This is the main thread that executes and maintains validator /// duties. pub struct Service { @@ -217,7 +220,10 @@ impl Service { // TODO: keypairs are randomly generated; they should be loaded from a file or generated. // https://github.com/sigp/lighthouse/issues/160 - let keypairs = Arc::new(vec![Keypair::random()]); + let keypairs = match config.fetch_keys(&log) { + Some(kps) => kps, + None => panic!("No key pairs found, cannot start validator client without. Try running ./account_manager generate first.") + }; // build requisite objects to pass to core thread. let duties_map = Arc::new(EpochDutiesMap::new(config.spec.slots_per_epoch)); @@ -272,87 +278,87 @@ impl Service { Ok(()) })) .map_err(|e| format!("Service thread failed: {:?}", e))?; + + let mut threads = vec![]; + + for keypair in keypairs { + info!(log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id()); + + /* + // Spawn a new thread to maintain the validator's `EpochDuties`. + let duties_manager_thread = { + let spec = spec.clone(); + let duties_map = duties_map.clone(); + let slot_clock = self.slot_clock.clone(); + let log = self.log.clone(); + let beacon_node = self.validator_client.clone(); + let pubkey = keypair.pk.clone(); + thread::spawn(move || { + let manager = DutiesManager { + duties_map, + pubkey, + spec, + slot_clock, + beacon_node, + }; + let mut duties_manager_service = DutiesManagerService { + manager, + poll_interval_millis, + log, + }; + + duties_manager_service.run(); + }) + }; + + // Spawn a new thread to perform block production for the validator. + let producer_thread = { + let spec = spec.clone(); + let signer = Arc::new(BlockProposerLocalSigner::new(keypair.clone())); + let duties_map = duties_map.clone(); + let slot_clock = slot_clock.clone(); + let log = log.clone(); + let client = Arc::new(BeaconBlockGrpcClient::new(beacon_block_grpc_client.clone())); + thread::spawn(move || { + let block_producer = + BlockProducer::new(spec, duties_map, slot_clock, client, signer); + let mut block_producer_service = BlockProducerService { + block_producer, + poll_interval_millis, + log, + }; + + block_producer_service.run(); + }) + }; + */ + + // Spawn a new thread for attestation for the validator. + let attester_thread = { + let signer = Arc::new(AttesterLocalSigner::new(keypair.clone())); + let slot_clock = service.slot_clock.clone(); + let log = log.clone(); + let attester_grpc_client = Arc::new(AttestationGrpcClient::new(attester_client.clone())); + thread::spawn(move || { + let attester = Attester::new(epoch_map_for_attester, slot_clock, attester_grpc_client, signer); + let mut attester_service = AttesterService { + attester, + poll_interval_millis, + log, + }; + + attester_service.run(); + }) + }; + + //threads.push((duties_manager_thread, producer_thread, attester_thread)); + threads.push((attester_thread)); + } + Ok(()) - } + } /* - - let duties_map = Arc::new(EpochDutiesMap::new(spec.slots_per_epoch)); - let epoch_map_for_attester = Arc::new(EpochMap::new(spec.slots_per_epoch)); - - - for keypair in keypairs { - info!(self.log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id()); - - // Spawn a new thread to maintain the validator's `EpochDuties`. - let duties_manager_thread = { - let spec = spec.clone(); - let duties_map = duties_map.clone(); - let slot_clock = self.slot_clock.clone(); - let log = self.log.clone(); - let beacon_node = self.validator_client.clone(); - let pubkey = keypair.pk.clone(); - thread::spawn(move || { - let manager = DutiesManager { - duties_map, - pubkey, - spec, - slot_clock, - beacon_node, - }; - let mut duties_manager_service = DutiesManagerService { - manager, - poll_interval_millis, - log, - }; - - duties_manager_service.run(); - }) - }; - - // Spawn a new thread to perform block production for the validator. - let producer_thread = { - let spec = spec.clone(); - let signer = Arc::new(BlockProposerLocalSigner::new(keypair.clone())); - let duties_map = duties_map.clone(); - let slot_clock = slot_clock.clone(); - let log = log.clone(); - let client = Arc::new(BeaconBlockGrpcClient::new(beacon_block_grpc_client.clone())); - thread::spawn(move || { - let block_producer = - BlockProducer::new(spec, duties_map, slot_clock, client, signer); - let mut block_producer_service = BlockProducerService { - block_producer, - poll_interval_millis, - log, - }; - - block_producer_service.run(); - }) - }; - - // Spawn a new thread for attestation for the validator. - let attester_thread = { - let signer = Arc::new(AttesterLocalSigner::new(keypair.clone())); - let epoch_map = epoch_map_for_attester.clone(); - let slot_clock = slot_clock.clone(); - let log = log.clone(); - let client = Arc::new(AttestationGrpcClient::new(attester_grpc_client.clone())); - thread::spawn(move || { - let attester = Attester::new(epoch_map, slot_clock, client, signer); - let mut attester_service = AttesterService { - attester, - poll_interval_millis, - log, - }; - - attester_service.run(); - }) - }; - - threads.push((duties_manager_thread, producer_thread, attester_thread)); - } - // Naively wait for all the threads to complete. for tuple in threads { let (manager, producer, attester) = tuple; From ba71e8adca2a6f1e899492bdcd776dc45f981cc3 Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Thu, 28 Mar 2019 20:55:07 +1100 Subject: [PATCH 033/106] Merged age-validator-client into luke's changes on validator_client, and fixed all the merge conflicts. --- Jenkinsfile | 22 ++- beacon_node/Cargo.toml | 1 + beacon_node/beacon_chain/src/beacon_chain.rs | 23 +++ beacon_node/beacon_chain/src/initialise.rs | 20 +- beacon_node/client/Cargo.toml | 1 + beacon_node/client/src/lib.rs | 101 +++++++++- beacon_node/client/src/notifier.rs | 4 +- beacon_node/eth2-libp2p/src/behaviour.rs | 33 +++- beacon_node/network/src/sync/simple_sync.rs | 8 +- beacon_node/rpc/src/beacon_block.rs | 110 ++++++++--- beacon_node/rpc/src/beacon_chain.rs | 13 +- beacon_node/rpc/src/beacon_node.rs | 7 +- beacon_node/rpc/src/lib.rs | 1 + beacon_node/rpc/src/validator.rs | 135 ++++++++------ beacon_node/src/run.rs | 2 + eth2/attester/src/lib.rs | 3 +- .../src/per_slot_processing.rs | 1 - .../testing_beacon_state_builder.rs | 4 +- eth2/utils/slot_clock/src/lib.rs | 3 + .../slot_clock/src/system_time_slot_clock.rs | 39 +++- .../slot_clock/src/testing_slot_clock.rs | 6 + protos/src/services.proto | 13 +- .../beacon_block_grpc_client.rs | 38 +--- validator_client/src/config.rs | 3 +- validator_client/src/duties/grpc.rs | 7 +- validator_client/src/duties/mod.rs | 23 ++- validator_client/src/main.rs | 4 +- validator_client/src/service.rs | 173 ++++++++---------- 28 files changed, 540 insertions(+), 258 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 42755d5f7..1a3afad87 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,20 +1,22 @@ pipeline { - agent { + agent { dockerfile { filename 'Dockerfile' args '-v cargo-cache:/cargocache:rw -e "CARGO_HOME=/cargocache"' } } - stages { - stage('Build') { - steps { - sh 'cargo build' - } - } - stage('Test') { + stages { + stage('Build') { steps { - sh 'cargo test --all' + sh 'cargo build --verbose --all' + sh 'cargo build --verbose --all --release' } } - } + stage('Test') { + steps { + sh 'cargo test --verbose --all' + sh 'cargo test --verbose --all --release' + } + } + } } diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index e7aaf938d..a090c1cc5 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -14,6 +14,7 @@ slog-term = "^2.4.0" slog-async = "^2.3.0" ctrlc = { version = "3.1.1", features = ["termination"] } tokio = "0.1.15" +tokio-timer = "0.2.10" futures = "0.1.25" exit-future = "0.1.3" state_processing = { path = "../eth2/state_processing" } diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 9323d1334..a9a28ea39 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -342,8 +342,17 @@ where // If required, transition the new state to the present slot. for _ in state.slot.as_u64()..present_slot.as_u64() { + // Ensure the next epoch state caches are built in case of an epoch transition. + state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, &self.spec)?; + state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, &self.spec)?; + per_slot_processing(&mut *state, &latest_block_header, &self.spec)?; } + state.build_epoch_cache(RelativeEpoch::Previous, &self.spec)?; + state.build_epoch_cache(RelativeEpoch::Current, &self.spec)?; + state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, &self.spec)?; + state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, &self.spec)?; + state.update_pubkey_cache()?; Ok(()) } @@ -405,6 +414,20 @@ where } } + /// Reads the slot clock (see `self.read_slot_clock()` and returns the number of slots since + /// genesis. + pub fn slots_since_genesis(&self) -> Option { + let now = self.read_slot_clock()?; + + if now < self.spec.genesis_slot { + None + } else { + Some(SlotHeight::from( + now.as_u64() - self.spec.genesis_slot.as_u64(), + )) + } + } + /// Returns slot of the present state. /// /// This is distinct to `read_slot_clock`, which reads from the actual system clock. If diff --git a/beacon_node/beacon_chain/src/initialise.rs b/beacon_node/beacon_chain/src/initialise.rs index 7d3c87965..0951e06fb 100644 --- a/beacon_node/beacon_chain/src/initialise.rs +++ b/beacon_node/beacon_chain/src/initialise.rs @@ -28,15 +28,19 @@ pub fn initialise_beacon_chain( let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone())); - let state_builder = TestingBeaconStateBuilder::from_deterministic_keypairs(8, &spec); + let state_builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(8, &spec); let (genesis_state, _keypairs) = state_builder.build(); let mut genesis_block = BeaconBlock::empty(&spec); genesis_block.state_root = Hash256::from_slice(&genesis_state.hash_tree_root()); // Slot clock - let slot_clock = SystemTimeSlotClock::new(genesis_state.genesis_time, spec.seconds_per_slot) - .expect("Unable to load SystemTimeSlotClock"); + let slot_clock = SystemTimeSlotClock::new( + spec.genesis_slot, + genesis_state.genesis_time, + spec.seconds_per_slot, + ) + .expect("Unable to load SystemTimeSlotClock"); // Choose the fork choice let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); @@ -65,15 +69,19 @@ pub fn initialise_test_beacon_chain( let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone())); - let state_builder = TestingBeaconStateBuilder::from_deterministic_keypairs(8, spec); + let state_builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(8, spec); let (genesis_state, _keypairs) = state_builder.build(); let mut genesis_block = BeaconBlock::empty(spec); genesis_block.state_root = Hash256::from_slice(&genesis_state.hash_tree_root()); // Slot clock - let slot_clock = SystemTimeSlotClock::new(genesis_state.genesis_time, spec.seconds_per_slot) - .expect("Unable to load SystemTimeSlotClock"); + let slot_clock = SystemTimeSlotClock::new( + spec.genesis_slot, + genesis_state.genesis_time, + spec.seconds_per_slot, + ) + .expect("Unable to load SystemTimeSlotClock"); // Choose the fork choice let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone()); diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 12c1b5c80..8956dbb07 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -14,6 +14,7 @@ types = { path = "../../eth2/types" } slot_clock = { path = "../../eth2/utils/slot_clock" } error-chain = "0.12.0" slog = "^2.2.3" +ssz = { path = "../../eth2/utils/ssz" } tokio = "0.1.15" clap = "2.32.0" dirs = "1.0.3" diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index b24d2cb7f..807fd9301 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -8,12 +8,20 @@ pub mod notifier; use beacon_chain::BeaconChain; pub use client_config::ClientConfig; pub use client_types::ClientTypes; +use db::ClientDB; use exit_future::Signal; +use fork_choice::ForkChoice; +use futures::{future::Future, Stream}; use network::Service as NetworkService; -use slog::o; +use slog::{error, info, o}; +use slot_clock::SlotClock; +use ssz::TreeHash; use std::marker::PhantomData; use std::sync::Arc; +use std::time::{Duration, Instant}; use tokio::runtime::TaskExecutor; +use tokio::timer::Interval; +use types::Hash256; /// Main beacon node client service. This provides the connection and initialisation of the clients /// sub-services in multiple threads. @@ -26,6 +34,8 @@ pub struct Client { pub network: Arc, /// Signal to terminate the RPC server. pub rpc_exit_signal: Option, + /// Signal to terminate the slot timer. + pub slot_timer_exit_signal: Option, /// The clients logger. log: slog::Logger, /// Marker to pin the beacon chain generics. @@ -42,6 +52,35 @@ impl Client { // generate a beacon chain let beacon_chain = TClientType::initialise_beacon_chain(&config); + if beacon_chain.read_slot_clock().is_none() { + panic!("Cannot start client before genesis!") + } + + // Block starting the client until we have caught the state up to the current slot. + // + // If we don't block here we create an initial scenario where we're unable to process any + // blocks and we're basically useless. + { + let state_slot = beacon_chain.state.read().slot; + let wall_clock_slot = beacon_chain.read_slot_clock().unwrap(); + let slots_since_genesis = beacon_chain.slots_since_genesis().unwrap(); + info!( + log, + "Initializing state"; + "state_slot" => state_slot, + "wall_clock_slot" => wall_clock_slot, + "slots_since_genesis" => slots_since_genesis, + "catchup_distance" => wall_clock_slot - state_slot, + ); + } + do_state_catchup(&beacon_chain, &log); + info!( + log, + "State initialized"; + "state_slot" => beacon_chain.state.read().slot, + "wall_clock_slot" => beacon_chain.read_slot_clock().unwrap(), + ); + // Start the network service, libp2p and syncing threads // TODO: Add beacon_chain reference to network parameters let network_config = &config.net_conf; @@ -65,13 +104,73 @@ impl Client { )); } + let (slot_timer_exit_signal, exit) = exit_future::signal(); + if let Ok(Some(duration_to_next_slot)) = beacon_chain.slot_clock.duration_to_next_slot() { + // set up the validator work interval - start at next slot and proceed every slot + let interval = { + // Set the interval to start at the next slot, and every slot after + let slot_duration = Duration::from_secs(config.spec.seconds_per_slot); + //TODO: Handle checked add correctly + Interval::new(Instant::now() + duration_to_next_slot, slot_duration) + }; + + let chain = beacon_chain.clone(); + let log = log.new(o!("Service" => "SlotTimer")); + executor.spawn( + exit.until( + interval + .for_each(move |_| { + do_state_catchup(&chain, &log); + + Ok(()) + }) + .map_err(|_| ()), + ) + .map(|_| ()), + ); + } + Ok(Client { config, beacon_chain, rpc_exit_signal, + slot_timer_exit_signal: Some(slot_timer_exit_signal), log, network, phantom: PhantomData, }) } } + +fn do_state_catchup(chain: &Arc>, log: &slog::Logger) +where + T: ClientDB, + U: SlotClock, + F: ForkChoice, +{ + if let Some(genesis_height) = chain.slots_since_genesis() { + let result = chain.catchup_state(); + + let common = o!( + "best_slot" => chain.head().beacon_block.slot, + "latest_block_root" => format!("{}", chain.head().beacon_block_root), + "wall_clock_slot" => chain.read_slot_clock().unwrap(), + "state_slot" => chain.state.read().slot, + "slots_since_genesis" => genesis_height, + ); + + match result { + Ok(_) => info!( + log, + "NewSlot"; + common + ), + Err(e) => error!( + log, + "StateCatchupFailed"; + "error" => format!("{:?}", e), + common + ), + }; + } +} diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 335183c7d..91a9f3a26 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -2,7 +2,7 @@ use crate::Client; use crate::ClientTypes; use exit_future::Exit; use futures::{Future, Stream}; -use slog::{debug, info, o}; +use slog::{debug, o}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use tokio::runtime::TaskExecutor; @@ -22,7 +22,7 @@ pub fn run(client: &Client, executor: TaskExecutor, exit: Exi // build heartbeat logic here let heartbeat = move |_| { - info!(log, "Temp heartbeat output"); + debug!(log, "Temp heartbeat output"); //TODO: Remove this logic. Testing only let mut count = counter.lock().unwrap(); *count += 1; diff --git a/beacon_node/eth2-libp2p/src/behaviour.rs b/beacon_node/eth2-libp2p/src/behaviour.rs index 41b7c8965..286597183 100644 --- a/beacon_node/eth2-libp2p/src/behaviour.rs +++ b/beacon_node/eth2-libp2p/src/behaviour.rs @@ -49,12 +49,15 @@ impl NetworkBehaviourEventProcess { + debug!(self.log, "Received GossipEvent"; "msg" => format!("{:?}", gs_msg)); + let pubsub_message = match PubsubMessage::ssz_decode(&gs_msg.data, 0) { //TODO: Punish peer on error Err(e) => { warn!( self.log, - "Received undecodable message from Peer {:?}", gs_msg.source + "Received undecodable message from Peer {:?} error", gs_msg.source; + "error" => format!("{:?}", e) ); return; } @@ -192,7 +195,7 @@ pub enum BehaviourEvent { } /// Messages that are passed to and from the pubsub (Gossipsub) behaviour. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum PubsubMessage { /// Gossipsub message providing notification of a new block. Block(BlockRootSlot), @@ -220,11 +223,11 @@ impl Decodable for PubsubMessage { fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { let (id, index) = u32::ssz_decode(bytes, index)?; match id { - 1 => { + 0 => { let (block, index) = BlockRootSlot::ssz_decode(bytes, index)?; Ok((PubsubMessage::Block(block), index)) } - 2 => { + 1 => { let (attestation, index) = Attestation::ssz_decode(bytes, index)?; Ok((PubsubMessage::Attestation(attestation), index)) } @@ -232,3 +235,25 @@ impl Decodable for PubsubMessage { } } } + +#[cfg(test)] +mod test { + use super::*; + use types::*; + + #[test] + fn ssz_encoding() { + let original = PubsubMessage::Block(BlockRootSlot { + block_root: Hash256::from_slice(&[42; 32]), + slot: Slot::new(4), + }); + + let encoded = ssz_encode(&original); + + println!("{:?}", encoded); + + let (decoded, _i) = PubsubMessage::ssz_decode(&encoded, 0).unwrap(); + + assert_eq!(original, decoded); + } +} diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 2aa0a1d7d..85949fa98 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -523,9 +523,9 @@ impl SimpleSync { msg: BlockRootSlot, network: &mut NetworkContext, ) { - debug!( + info!( self.log, - "BlockSlot"; + "NewGossipBlock"; "peer" => format!("{:?}", peer_id), ); // TODO: filter out messages that a prior to the finalized slot. @@ -557,9 +557,9 @@ impl SimpleSync { msg: Attestation, _network: &mut NetworkContext, ) { - debug!( + info!( self.log, - "Attestation"; + "NewAttestationGossip"; "peer" => format!("{:?}", peer_id), ); diff --git a/beacon_node/rpc/src/beacon_block.rs b/beacon_node/rpc/src/beacon_block.rs index 4e1875665..f6b426c18 100644 --- a/beacon_node/rpc/src/beacon_block.rs +++ b/beacon_node/rpc/src/beacon_block.rs @@ -1,3 +1,4 @@ +use crate::beacon_chain::BeaconChain; use crossbeam_channel; use eth2_libp2p::rpc::methods::BlockRootSlot; use eth2_libp2p::PubsubMessage; @@ -10,10 +11,14 @@ use protos::services::{ }; use protos::services_grpc::BeaconBlockService; use slog::Logger; -use types::{Hash256, Slot}; +use slog::{debug, error, info, warn}; +use ssz::{Decodable, TreeHash}; +use std::sync::Arc; +use types::{BeaconBlock, Hash256, Slot}; #[derive(Clone)] pub struct BeaconBlockServiceInstance { + pub chain: Arc, pub network_chan: crossbeam_channel::Sender, pub log: Logger, } @@ -30,8 +35,7 @@ impl BeaconBlockService for BeaconBlockServiceInstance { // TODO: build a legit block. let mut block = BeaconBlockProto::new(); - block.set_slot(req.get_slot()); - block.set_block_root(b"cats".to_vec()); + block.set_ssz(b"cats".to_vec()); let mut resp = ProduceBeaconBlockResponse::new(); resp.set_block(block); @@ -49,26 +53,88 @@ impl BeaconBlockService for BeaconBlockServiceInstance { req: PublishBeaconBlockRequest, sink: UnarySink, ) { - let block = req.get_block(); - let block_root = Hash256::from_slice(block.get_block_root()); - let block_slot = BlockRootSlot { - block_root, - slot: Slot::from(block.get_slot()), - }; - println!("publishing block with root {:?}", block_root); - - // TODO: Obtain topics from the network service properly. - let topic = types::TopicBuilder::new("beacon_chain".to_string()).build(); - let message = PubsubMessage::Block(block_slot); - println!("Sending beacon block to gossipsub"); - self.network_chan.send(NetworkMessage::Publish { - topics: vec![topic], - message, - }); - - // TODO: actually process the block. let mut resp = PublishBeaconBlockResponse::new(); - resp.set_success(true); + + let ssz_serialized_block = req.get_block().get_ssz(); + + match BeaconBlock::ssz_decode(ssz_serialized_block, 0) { + Ok((block, _i)) => { + let block_root = Hash256::from_slice(&block.hash_tree_root()[..]); + + match self.chain.process_block(block.clone()) { + Ok(outcome) => { + if outcome.sucessfully_processed() { + // Block was successfully processed. + info!( + self.log, + "PublishBeaconBlock"; + "type" => "valid_block", + "block_slot" => block.slot, + "outcome" => format!("{:?}", outcome) + ); + + // TODO: Obtain topics from the network service properly. + let topic = + types::TopicBuilder::new("beacon_chain".to_string()).build(); + let message = PubsubMessage::Block(BlockRootSlot { + block_root, + slot: block.slot, + }); + + println!("Sending beacon block to gossipsub"); + self.network_chan.send(NetworkMessage::Publish { + topics: vec![topic], + message, + }); + + resp.set_success(true); + } else if outcome.is_invalid() { + // Block was invalid. + warn!( + self.log, + "PublishBeaconBlock"; + "type" => "invalid_block", + "outcome" => format!("{:?}", outcome) + ); + + resp.set_success(false); + resp.set_msg( + format!("InvalidBlock: {:?}", outcome).as_bytes().to_vec(), + ); + } else { + // Some failure during processing. + warn!( + self.log, + "PublishBeaconBlock"; + "type" => "unable_to_import", + "outcome" => format!("{:?}", outcome) + ); + + resp.set_success(false); + resp.set_msg(format!("other: {:?}", outcome).as_bytes().to_vec()); + } + } + Err(e) => { + // Some failure during processing. + error!( + self.log, + "PublishBeaconBlock"; + "type" => "failed_to_process", + "error" => format!("{:?}", e) + ); + + resp.set_success(false); + resp.set_msg(format!("failed_to_process: {:?}", e).as_bytes().to_vec()); + } + } + + resp.set_success(true); + } + Err(_) => { + resp.set_success(false); + resp.set_msg(b"Invalid SSZ".to_vec()); + } + }; let f = sink .success(resp) diff --git a/beacon_node/rpc/src/beacon_chain.rs b/beacon_node/rpc/src/beacon_chain.rs index 9b2681876..0551a8024 100644 --- a/beacon_node/rpc/src/beacon_chain.rs +++ b/beacon_node/rpc/src/beacon_chain.rs @@ -5,14 +5,18 @@ use beacon_chain::{ parking_lot::RwLockReadGuard, slot_clock::SlotClock, types::{BeaconState, ChainSpec}, - CheckPoint, }; +pub use beacon_chain::{BeaconChainError, BlockProcessingOutcome}; +use types::BeaconBlock; /// The RPC's API to the beacon chain. pub trait BeaconChain: Send + Sync { fn get_spec(&self) -> &ChainSpec; fn get_state(&self) -> RwLockReadGuard; + + fn process_block(&self, block: BeaconBlock) + -> Result; } impl BeaconChain for RawBeaconChain @@ -28,4 +32,11 @@ where fn get_state(&self) -> RwLockReadGuard { self.state.read() } + + fn process_block( + &self, + block: BeaconBlock, + ) -> Result { + self.process_block(block) + } } diff --git a/beacon_node/rpc/src/beacon_node.rs b/beacon_node/rpc/src/beacon_node.rs index 7b00f04f4..c92ab6616 100644 --- a/beacon_node/rpc/src/beacon_node.rs +++ b/beacon_node/rpc/src/beacon_node.rs @@ -1,7 +1,7 @@ use crate::beacon_chain::BeaconChain; use futures::Future; use grpcio::{RpcContext, UnarySink}; -use protos::services::{Empty, Fork, NodeInfo}; +use protos::services::{Empty, Fork, NodeInfoResponse}; use protos::services_grpc::BeaconNodeService; use slog::{trace, warn}; use std::sync::Arc; @@ -14,11 +14,11 @@ pub struct BeaconNodeServiceInstance { impl BeaconNodeService for BeaconNodeServiceInstance { /// Provides basic node information. - fn info(&mut self, ctx: RpcContext, _req: Empty, sink: UnarySink) { + fn info(&mut self, ctx: RpcContext, _req: Empty, sink: UnarySink) { trace!(self.log, "Node info requested via RPC"); // build the response - let mut node_info = NodeInfo::new(); + let mut node_info = NodeInfoResponse::new(); node_info.set_version(version::version()); // get the chain state @@ -34,6 +34,7 @@ impl BeaconNodeService for BeaconNodeServiceInstance { node_info.set_fork(fork); node_info.set_genesis_time(genesis_time); + node_info.set_genesis_slot(self.chain.get_spec().genesis_slot.as_u64()); node_info.set_chain_id(self.chain.get_spec().chain_id as u32); // send the node_info the requester diff --git a/beacon_node/rpc/src/lib.rs b/beacon_node/rpc/src/lib.rs index 20cd62b1d..2d47b4a69 100644 --- a/beacon_node/rpc/src/lib.rs +++ b/beacon_node/rpc/src/lib.rs @@ -43,6 +43,7 @@ pub fn start_server( let beacon_block_service = { let instance = BeaconBlockServiceInstance { + chain: beacon_chain.clone(), network_chan, log: log.clone(), }; diff --git a/beacon_node/rpc/src/validator.rs b/beacon_node/rpc/src/validator.rs index 47886a9df..936c95f52 100644 --- a/beacon_node/rpc/src/validator.rs +++ b/beacon_node/rpc/src/validator.rs @@ -4,9 +4,10 @@ use futures::Future; use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink}; use protos::services::{ActiveValidator, GetDutiesRequest, GetDutiesResponse, ValidatorDuty}; use protos::services_grpc::ValidatorService; -use slog::{debug, Logger}; +use slog::{debug, info, warn, Logger}; use ssz::Decodable; use std::sync::Arc; +use types::{Epoch, RelativeEpoch}; #[derive(Clone)] pub struct ValidatorServiceInstance { @@ -28,23 +29,47 @@ impl ValidatorService for ValidatorServiceInstance { let validators = req.get_validators(); debug!(self.log, "RPC request"; "endpoint" => "GetValidatorDuties", "epoch" => req.get_epoch()); - let epoch = req.get_epoch(); + let epoch = Epoch::from(req.get_epoch()); let mut resp = GetDutiesResponse::new(); let resp_validators = resp.mut_active_validators(); let spec = self.chain.get_spec(); let state = self.chain.get_state(); - //TODO: Decide whether to rebuild the cache - //TODO: Get the active validator indicies - //let active_validator_indices = self.chain.state.read().get_cached_active_validator_indices( - let active_validator_indices = vec![1, 2, 3, 4, 5, 6, 7, 8]; - // TODO: Is this the most efficient? Perhaps we cache this data structure. + let relative_epoch = + match RelativeEpoch::from_epoch(state.slot.epoch(spec.slots_per_epoch), epoch) { + Ok(v) => v, + Err(e) => { + // incorrect epoch + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::FailedPrecondition, + Some(format!("Invalid epoch: {:?}", e)), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); + return ctx.spawn(f); + } + }; - // this is an array of validators who are to propose this epoch - // TODO: RelativeEpoch? - //let validator_proposers = [0..spec.slots_per_epoch].iter().map(|slot| state.get_beacon_proposer_index(Slot::from(slot), epoch, &spec)).collect(); - let validator_proposers: Vec = vec![1, 2, 3, 4, 5]; + let validator_proposers: Result, _> = epoch + .slot_iter(spec.slots_per_epoch) + .map(|slot| state.get_beacon_proposer_index(slot, relative_epoch, &spec)) + .collect(); + let validator_proposers = match validator_proposers { + Ok(v) => v, + Err(e) => { + // could not get the validator proposer index + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::FailedPrecondition, + Some(format!("Could not find beacon proposers: {:?}", e)), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?} : {:?}", req, e)); + return ctx.spawn(f); + } + }; // get the duties for each validator for validator_pk in validators.get_public_keys() { @@ -53,45 +78,65 @@ impl ValidatorService for ValidatorServiceInstance { let public_key = match PublicKey::ssz_decode(validator_pk, 0) { Ok((v, _index)) => v, Err(_) => { + let log_clone = self.log.clone(); let f = sink .fail(RpcStatus::new( RpcStatusCode::InvalidArgument, Some("Invalid public_key".to_string()), )) - //TODO: Handle error correctly - .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e)); + .map_err(move |e| warn!(log_clone, "failed to reply {:?}", req)); return ctx.spawn(f); } }; - // is the validator active + // get the validator index let val_index = match state.get_validator_index(&public_key) { - Ok(Some(index)) => { - if active_validator_indices.contains(&index) { - // validator is active, return the index - index - } else { - // validator is inactive, go to the next validator - active_validator.set_none(false); - resp_validators.push(active_validator); - break; - } - } - // validator index is not known, skip it - Ok(_) => { + Ok(Some(index)) => index, + Ok(None) => { + // index not present in registry, set the duties for this key to None + warn!( + self.log, + "RPC requested a public key that is not in the registry: {:?}", public_key + ); active_validator.set_none(false); resp_validators.push(active_validator); - break; + continue; } // the cache is not built, throw an error - Err(_) => { + Err(e) => { + let log_clone = self.log.clone(); let f = sink .fail(RpcStatus::new( RpcStatusCode::FailedPrecondition, - Some("Beacon state cache is not built".to_string()), + Some(format!("Beacon state error {:?}", e)), )) - //TODO: Handle error correctly - .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e)); + .map_err(move |e| warn!(log_clone, "Failed to reply {:?}: {:?}", req, e)); + return ctx.spawn(f); + } + }; + + // get attestation duties and check if validator is active + let attestation_duties = match state.get_attestation_duties(val_index, &spec) { + Ok(Some(v)) => v, + Ok(_) => { + // validator is inactive, go to the next validator + warn!( + self.log, + "RPC requested an inactive validator key: {:?}", public_key + ); + active_validator.set_none(false); + resp_validators.push(active_validator); + continue; + } + // the cache is not built, throw an error + Err(e) => { + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::FailedPrecondition, + Some(format!("Beacon state error {:?}", e)), + )) + .map_err(move |e| warn!(log_clone, "Failed to reply {:?}: {:?}", req, e)); return ctx.spawn(f); } }; @@ -100,33 +145,15 @@ impl ValidatorService for ValidatorServiceInstance { let mut duty = ValidatorDuty::new(); // check if the validator needs to propose a block - if let Some(slot) = validator_proposers - .iter() - .position(|&v| val_index as u64 == v) - { - duty.set_block_production_slot(epoch * spec.slots_per_epoch + slot as u64); + if let Some(slot) = validator_proposers.iter().position(|&v| val_index == v) { + duty.set_block_production_slot( + epoch.start_slot(spec.slots_per_epoch).as_u64() + slot as u64, + ); } else { // no blocks to propose this epoch duty.set_none(false) } - // get attestation duties - let attestation_duties = match state.get_attestation_duties(val_index, &spec) { - Ok(Some(v)) => v, - Ok(_) => unreachable!(), //we've checked the validator index - // the cache is not built, throw an error - Err(_) => { - let f = sink - .fail(RpcStatus::new( - RpcStatusCode::FailedPrecondition, - Some("Beacon state cache is not built".to_string()), - )) - //TODO: Handle error correctly - .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e)); - return ctx.spawn(f); - } - }; - duty.set_committee_index(attestation_duties.committee_index as u64); duty.set_attestation_slot(attestation_duties.slot.as_u64()); duty.set_attestation_shard(attestation_duties.shard); diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index b3b284452..1d9156124 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -6,10 +6,12 @@ use futures::Future; use slog::info; use std::cell::RefCell; use tokio::runtime::Builder; +use tokio_timer::clock::Clock; pub fn run_beacon_node(config: ClientConfig, log: &slog::Logger) -> error::Result<()> { let mut runtime = Builder::new() .name_prefix("main-") + .clock(Clock::system()) .build() .map_err(|e| format!("{:?}", e))?; diff --git a/eth2/attester/src/lib.rs b/eth2/attester/src/lib.rs index 8dd83fa04..53d81e897 100644 --- a/eth2/attester/src/lib.rs +++ b/eth2/attester/src/lib.rs @@ -90,8 +90,7 @@ impl Attester { aggregate_signature: agg_sig, }; - self.beacon_node - .publish_attestation(attestation)?; + self.beacon_node.publish_attestation(attestation)?; Ok(PollOutcome::AttestationProduced(attestation_duty.slot)) } diff --git a/eth2/state_processing/src/per_slot_processing.rs b/eth2/state_processing/src/per_slot_processing.rs index 8f02b70e3..c6b5312c7 100644 --- a/eth2/state_processing/src/per_slot_processing.rs +++ b/eth2/state_processing/src/per_slot_processing.rs @@ -20,7 +20,6 @@ pub fn per_slot_processing( if (state.slot + 1) % spec.slots_per_epoch == 0 { per_epoch_processing(state, spec)?; - state.advance_caches(); } state.slot += 1; diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index 473cd4166..b38e8b527 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -120,8 +120,10 @@ impl TestingBeaconStateBuilder { }) .collect(); + let genesis_time = 1553753928; // arbitrary + let mut state = BeaconState::genesis( - 0, + genesis_time, Eth1Data { deposit_root: Hash256::zero(), block_hash: Hash256::zero(), diff --git a/eth2/utils/slot_clock/src/lib.rs b/eth2/utils/slot_clock/src/lib.rs index 0379d50d9..fd5a2d1d7 100644 --- a/eth2/utils/slot_clock/src/lib.rs +++ b/eth2/utils/slot_clock/src/lib.rs @@ -3,10 +3,13 @@ mod testing_slot_clock; pub use crate::system_time_slot_clock::{Error as SystemTimeSlotClockError, SystemTimeSlotClock}; pub use crate::testing_slot_clock::{Error as TestingSlotClockError, TestingSlotClock}; +use std::time::Duration; pub use types::Slot; pub trait SlotClock: Send + Sync { type Error; fn present_slot(&self) -> Result, Self::Error>; + + fn duration_to_next_slot(&self) -> Result, Self::Error>; } diff --git a/eth2/utils/slot_clock/src/system_time_slot_clock.rs b/eth2/utils/slot_clock/src/system_time_slot_clock.rs index 99f051985..4dfc6b37d 100644 --- a/eth2/utils/slot_clock/src/system_time_slot_clock.rs +++ b/eth2/utils/slot_clock/src/system_time_slot_clock.rs @@ -13,6 +13,7 @@ pub enum Error { /// Determines the present slot based upon the present system time. #[derive(Clone)] pub struct SystemTimeSlotClock { + genesis_slot: Slot, genesis_seconds: u64, slot_duration_seconds: u64, } @@ -22,6 +23,7 @@ impl SystemTimeSlotClock { /// /// Returns an Error if `slot_duration_seconds == 0`. pub fn new( + genesis_slot: Slot, genesis_seconds: u64, slot_duration_seconds: u64, ) -> Result { @@ -29,6 +31,7 @@ impl SystemTimeSlotClock { Err(Error::SlotDurationIsZero) } else { Ok(Self { + genesis_slot, genesis_seconds, slot_duration_seconds, }) @@ -44,11 +47,17 @@ impl SlotClock for SystemTimeSlotClock { let duration_since_epoch = syslot_time.duration_since(SystemTime::UNIX_EPOCH)?; let duration_since_genesis = duration_since_epoch.checked_sub(Duration::from_secs(self.genesis_seconds)); + match duration_since_genesis { None => Ok(None), - Some(d) => Ok(slot_from_duration(self.slot_duration_seconds, d)), + Some(d) => Ok(slot_from_duration(self.slot_duration_seconds, d) + .and_then(|s| Some(s + self.genesis_slot))), } } + + fn duration_to_next_slot(&self) -> Result, Error> { + duration_to_next_slot(self.genesis_seconds, self.slot_duration_seconds) + } } impl From for Error { @@ -62,6 +71,30 @@ fn slot_from_duration(slot_duration_seconds: u64, duration: Duration) -> Option< duration.as_secs().checked_div(slot_duration_seconds)?, )) } +// calculate the duration to the next slot +fn duration_to_next_slot( + genesis_time: u64, + seconds_per_slot: u64, +) -> Result, Error> { + let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?; + let genesis_time = Duration::from_secs(genesis_time); + + if now < genesis_time { + return Ok(None); + } + + let since_genesis = now - genesis_time; + + let elapsed_slots = since_genesis.as_secs() / seconds_per_slot; + + let next_slot_start_seconds = (elapsed_slots + 1) + .checked_mul(seconds_per_slot) + .expect("Next slot time should not overflow u64"); + + let time_to_next_slot = Duration::from_secs(next_slot_start_seconds) - since_genesis; + + Ok(Some(time_to_next_slot)) +} #[cfg(test)] mod tests { @@ -74,6 +107,7 @@ mod tests { #[test] fn test_slot_now() { let slot_time = 100; + let genesis_slot = Slot::new(0); let now = SystemTime::now(); let since_epoch = now.duration_since(SystemTime::UNIX_EPOCH).unwrap(); @@ -81,18 +115,21 @@ mod tests { let genesis = since_epoch.as_secs() - slot_time * 89; let clock = SystemTimeSlotClock { + genesis_slot, genesis_seconds: genesis, slot_duration_seconds: slot_time, }; assert_eq!(clock.present_slot().unwrap(), Some(Slot::new(89))); let clock = SystemTimeSlotClock { + genesis_slot, genesis_seconds: since_epoch.as_secs(), slot_duration_seconds: slot_time, }; assert_eq!(clock.present_slot().unwrap(), Some(Slot::new(0))); let clock = SystemTimeSlotClock { + genesis_slot, genesis_seconds: since_epoch.as_secs() - slot_time * 42 - 5, slot_duration_seconds: slot_time, }; diff --git a/eth2/utils/slot_clock/src/testing_slot_clock.rs b/eth2/utils/slot_clock/src/testing_slot_clock.rs index 80ee40539..b5c36dfa0 100644 --- a/eth2/utils/slot_clock/src/testing_slot_clock.rs +++ b/eth2/utils/slot_clock/src/testing_slot_clock.rs @@ -1,5 +1,6 @@ use super::SlotClock; use std::sync::RwLock; +use std::time::Duration; use types::Slot; #[derive(Debug, PartialEq)] @@ -32,6 +33,11 @@ impl SlotClock for TestingSlotClock { let slot = *self.slot.read().expect("TestingSlotClock poisoned."); Ok(Some(Slot::new(slot))) } + + /// Always returns a duration of 1 second. + fn duration_to_next_slot(&self) -> Result, Error> { + Ok(Some(Duration::from_secs(1))) + } } #[cfg(test)] diff --git a/protos/src/services.proto b/protos/src/services.proto index bdb311fd6..b61e5aac0 100644 --- a/protos/src/services.proto +++ b/protos/src/services.proto @@ -14,7 +14,7 @@ package ethereum.beacon.rpc.v1; // Service that currently identifies a beacon node service BeaconNodeService { - rpc Info(Empty) returns (NodeInfo); + rpc Info(Empty) returns (NodeInfoResponse); } /// Service that handles block production @@ -40,11 +40,12 @@ service AttestationService { /* * Beacon Node Service Message */ -message NodeInfo { +message NodeInfoResponse { string version = 1; Fork fork = 2; uint32 chain_id = 3; uint64 genesis_time = 4; + uint64 genesis_slot = 5; } message Fork { @@ -53,8 +54,7 @@ message Fork { uint64 epoch = 3; } -message Empty { -} +message Empty {} /* @@ -83,10 +83,7 @@ message PublishBeaconBlockResponse { } message BeaconBlock { - uint64 slot = 1; - bytes block_root = 2; - bytes randao_reveal = 3; - bytes signature = 4; + bytes ssz = 1; } /* 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 04a02a221..ba2acfffb 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 @@ -5,7 +5,7 @@ use protos::services::{ use protos::services_grpc::BeaconBlockServiceClient; use ssz::{ssz_encode, Decodable}; use std::sync::Arc; -use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, Signature, Slot}; +use types::{BeaconBlock, Signature, Slot}; /// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be /// implemented upon it. @@ -40,33 +40,12 @@ impl BeaconNode for BeaconBlockGrpcClient { if reply.has_block() { let block = reply.get_block(); + let ssz = block.get_ssz(); - let (signature, _) = Signature::ssz_decode(block.get_signature(), 0) - .map_err(|_| BeaconNodeError::DecodeFailure)?; + let (block, _i) = + BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| BeaconNodeError::DecodeFailure)?; - let (randao_reveal, _) = Signature::ssz_decode(block.get_randao_reveal(), 0) - .map_err(|_| BeaconNodeError::DecodeFailure)?; - - // TODO: this conversion is incomplete; fix it. - Ok(Some(BeaconBlock { - slot: Slot::new(block.get_slot()), - previous_block_root: Hash256::zero(), - state_root: Hash256::zero(), - signature, - body: BeaconBlockBody { - randao_reveal, - eth1_data: Eth1Data { - deposit_root: Hash256::zero(), - block_hash: Hash256::zero(), - }, - proposer_slashings: vec![], - attester_slashings: vec![], - attestations: vec![], - deposits: vec![], - voluntary_exits: vec![], - transfers: vec![], - }, - })) + Ok(Some(block)) } else { Ok(None) } @@ -79,12 +58,11 @@ impl BeaconNode for BeaconBlockGrpcClient { fn publish_beacon_block(&self, block: BeaconBlock) -> Result { let mut req = PublishBeaconBlockRequest::new(); + let ssz = ssz_encode(&block); + // TODO: this conversion is incomplete; fix it. let mut grpc_block = GrpcBeaconBlock::new(); - grpc_block.set_slot(block.slot.as_u64()); - grpc_block.set_block_root(vec![0]); - grpc_block.set_randao_reveal(ssz_encode(&block.body.randao_reveal)); - grpc_block.set_signature(ssz_encode(&block.signature)); + grpc_block.set_ssz(ssz); req.set_block(grpc_block); diff --git a/validator_client/src/config.rs b/validator_client/src/config.rs index 78900374a..3d426e8c7 100644 --- a/validator_client/src/config.rs +++ b/validator_client/src/config.rs @@ -1,6 +1,6 @@ -use clap::ArgMatches; use bincode; use bls::Keypair; +use clap::ArgMatches; use slog::{debug, error, info}; use std::fs; use std::fs::File; @@ -67,6 +67,7 @@ impl Config { config.spec = match spec_str { "foundation" => ChainSpec::foundation(), "few_validators" => ChainSpec::few_validators(), + "lighthouse_testnet" => ChainSpec::lighthouse_testnet(), // Should be impossible due to clap's `possible_values(..)` function. _ => unreachable!(), }; diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index 4bb76e14c..041d41add 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -1,9 +1,11 @@ use super::epoch_duties::{EpochDuties, EpochDuty}; use super::traits::{BeaconNode, BeaconNodeError}; +use grpcio::CallOption; use protos::services::{GetDutiesRequest, Validators}; use protos::services_grpc::ValidatorServiceClient; use ssz::ssz_encode; use std::collections::HashMap; +use std::time::Duration; use types::{Epoch, Keypair, Slot}; impl BeaconNode for ValidatorServiceClient { @@ -21,6 +23,9 @@ impl BeaconNode for ValidatorServiceClient { validators.set_public_keys(signers.iter().map(|v| ssz_encode(&v.pk)).collect()); req.set_validators(validators); + // set a timeout for requests + // let call_opt = CallOption::default().timeout(Duration::from_secs(2)); + // send the request, get the duties reply let reply = self .get_validator_duties(&req) @@ -31,7 +36,7 @@ impl BeaconNode for ValidatorServiceClient { if !validator_duty.has_duty() { // validator is inactive epoch_duties.insert(signers[index].clone(), None); - break; + continue; } // active validator let active_duty = validator_duty.get_duty(); diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index e239ca795..9d9221592 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -52,20 +52,23 @@ impl DutiesManager { /// be a wall-clock (e.g., system time, remote server time, etc.). fn update(&self, epoch: Epoch) -> Result { let duties = self.beacon_node.request_duties(epoch, &self.signers)?; - // If these duties were known, check to see if they're updates or identical. - if let Some(known_duties) = self.duties_map.read()?.get(&epoch) { - if *known_duties == duties { - return Ok(UpdateOutcome::NoChange(epoch)); - } else { - //TODO: Duties could be large here. Remove from display and avoid the clone. - self.duties_map.write()?.insert(epoch, duties.clone()); - return Ok(UpdateOutcome::DutiesChanged(epoch, duties)); + { + // If these duties were known, check to see if they're updates or identical. + if let Some(known_duties) = self.duties_map.read()?.get(&epoch) { + if *known_duties == duties { + return Ok(UpdateOutcome::NoChange(epoch)); + } } - } else { + } + if !self.duties_map.read()?.contains_key(&epoch) { //TODO: Remove clone by removing duties from outcome self.duties_map.write()?.insert(epoch, duties.clone()); return Ok(UpdateOutcome::NewDuties(epoch, duties)); - }; + } + // duties have changed + //TODO: Duties could be large here. Remove from display and avoid the clone. + self.duties_map.write()?.insert(epoch, duties.clone()); + return Ok(UpdateOutcome::DutiesChanged(epoch, duties)); } /// A future wrapping around `update()`. This will perform logic based upon the update diff --git a/validator_client/src/main.rs b/validator_client/src/main.rs index 84d0cbff7..d044030fe 100644 --- a/validator_client/src/main.rs +++ b/validator_client/src/main.rs @@ -43,8 +43,8 @@ fn main() { .short("s") .help("Configuration of Beacon Chain") .takes_value(true) - .possible_values(&["foundation", "few_validators"]) - .default_value("foundation"), + .possible_values(&["foundation", "few_validators", "lighthouse_testnet"]) + .default_value("lighthouse_testnet"), ) .get_matches(); diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index c2caed59d..86f310a06 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -25,6 +25,7 @@ use tokio::prelude::*; use tokio::runtime::Builder; use tokio::timer::Interval; use tokio_timer::clock::Clock; +use types::test_utils::generate_deterministic_keypairs; use types::{Epoch, Fork, Slot}; use std::thread; @@ -45,8 +46,6 @@ pub struct Service { slot_clock: SystemTimeSlotClock, /// The current slot we are processing. current_slot: Slot, - /// Duration until the next slot. This is used for initializing the tokio timer interval. - duration_to_next_slot: Duration, /// The number of slots per epoch to allow for converting slots to epochs. slots_per_epoch: u64, // GRPC Clients @@ -107,6 +106,7 @@ impl Service { // build requisite objects to form Self let genesis_time = node_info.get_genesis_time(); + let genesis_slot = Slot::from(node_info.get_genesis_slot()); info!(log,"Beacon node connected"; "Node Version" => node_info.version.clone(), "Chain ID" => node_info.chain_id, "Genesis time" => genesis_time); @@ -142,46 +142,21 @@ impl Service { }; // build the validator slot clock - let slot_clock = SystemTimeSlotClock::new(genesis_time, config.spec.seconds_per_slot) - .expect("Unable to instantiate SystemTimeSlotClock."); + let slot_clock = + SystemTimeSlotClock::new(genesis_slot, genesis_time, config.spec.seconds_per_slot) + .expect("Unable to instantiate SystemTimeSlotClock."); let current_slot = slot_clock .present_slot() .map_err(|e| ErrorKind::SlotClockError(e))? .expect("Genesis must be in the future"); - // calculate the duration to the next slot - let duration_to_next_slot = { - let seconds_per_slot = config.spec.seconds_per_slot; - let syslot_time = SystemTime::now(); - let duration_since_epoch = syslot_time - .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|e| ErrorKind::SystemTimeError(e.to_string()))?; - let duration_since_genesis = duration_since_epoch - .checked_sub(Duration::from_secs(genesis_time)) - .expect("Genesis must be in the future. Checked on connection"); - let elapsed_slots = duration_since_epoch - .as_secs() - .checked_div(seconds_per_slot as u64) - .expect("Seconds per slot should not be 0"); - - // the duration to the next slot - Duration::from_secs( - (elapsed_slots + 1) - .checked_mul(seconds_per_slot) - .expect("Next slot time should not overflow u64"), - ) - .checked_sub(duration_since_genesis) - .expect("This should never saturate") - }; - Ok(Self { connected_node_version: node_info.version, chain_id: node_info.chain_id as u16, fork, slot_clock, current_slot, - duration_to_next_slot, slots_per_epoch: config.spec.slots_per_epoch, beacon_block_client, validator_client, @@ -204,15 +179,18 @@ impl Service { .build() .map_err(|e| format!("Tokio runtime failed: {}", e))?; + let duration_to_next_slot = service + .slot_clock + .duration_to_next_slot() + .map_err(|e| format!("System clock error: {:?}", e))? + .expect("Cannot start before genesis"); + // set up the validator work interval - start at next slot and proceed every slot let interval = { // Set the interval to start at the next slot, and every slot after let slot_duration = Duration::from_secs(config.spec.seconds_per_slot); //TODO: Handle checked add correctly - Interval::new( - Instant::now() + service.duration_to_next_slot, - slot_duration, - ) + Interval::new(Instant::now() + duration_to_next_slot, slot_duration) }; /* kick off core service */ @@ -221,11 +199,14 @@ impl Service { // TODO: keypairs are randomly generated; they should be loaded from a file or generated. // https://github.com/sigp/lighthouse/issues/160 + /* In future, load generated keys from disk. let keypairs = match config.fetch_keys(&log.clone()) { Some(kps) => kps, None => panic!("No key pairs found, cannot start validator client without. Try running ./account_manager generate first.") }; + */ + let keypairs = Arc::new(generate_deterministic_keypairs(8)); /* build requisite objects to pass to core thread */ @@ -243,71 +224,75 @@ impl Service { }); // run the core thread - runtime - .block_on(interval.for_each(move |_| { - let log = service.log.clone(); + runtime.block_on( + interval + .for_each(move |_| { + let log = service.log.clone(); - /* get the current slot and epoch */ - let current_slot = match service.slot_clock.present_slot() { - Err(e) => { - error!(log, "SystemTimeError {:?}", e); - return Ok(()); - } - Ok(slot) => slot.expect("Genesis is in the future"), - }; - - let current_epoch = current_slot.epoch(service.slots_per_epoch); - - debug_assert!( - current_slot > service.current_slot, - "The Timer should poll a new slot" - ); - - info!(log, "Processing slot: {}", current_slot.as_u64()); - - /* check for new duties */ - - let cloned_log = log.clone(); - let cloned_manager = manager.clone(); - tokio::spawn(futures::future::poll_fn(move || { - cloned_manager.run_update(current_epoch.clone(), cloned_log.clone()) - })); - - /* execute any specified duties */ - - if let Some(work) = manager.get_current_work(current_slot) { - for (keypair, work_type) in work { - if work_type.produce_block { - // TODO: Produce a beacon block in a new thread + /* get the current slot and epoch */ + let current_slot = match service.slot_clock.present_slot() { + Err(e) => { + error!(log, "SystemTimeError {:?}", e); + return Ok(()); } - if work_type.attestation_duty.is_some() { - // available AttestationDuty info - let attestation_duty = - work_type.attestation_duty.expect("Cannot be None"); - let attester_grpc_client = - Arc::new( - AttestationGrpcClient::new( - service.attester_client.clone() - ) - ); - let signer = Arc::new(AttesterLocalSigner::new(keypair.clone())); - let attester = - Attester::new( - attester_grpc_client, - signer); - let mut attester_service = AttesterService { - attester, - poll_interval_millis: POLL_INTERVAL_MILLIS, - log: log.clone(), - }; - attester_service.run(); + Ok(slot) => slot.expect("Genesis is in the future"), + }; + + let current_epoch = current_slot.epoch(service.slots_per_epoch); + + debug_assert!( + current_slot > service.current_slot, + "The Timer should poll a new slot" + ); + + info!(log, "Processing slot: {}", current_slot.as_u64()); + + /* check for new duties */ + + let cloned_manager = manager.clone(); + let cloned_log = log.clone(); + // spawn a new thread separate to the runtime + std::thread::spawn(move || { + cloned_manager.run_update(current_epoch.clone(), cloned_log.clone()); + dbg!("Finished thread"); + }); + + /* execute any specified duties */ + + if let Some(work) = manager.get_current_work(current_slot) { + for (keypair, work_type) in work { + if work_type.produce_block { + // TODO: Produce a beacon block in a new thread + } + if work_type.attestation_duty.is_some() { + // available AttestationDuty info + let attestation_duty = + work_type.attestation_duty.expect("Cannot be None"); + let attester_grpc_client = + Arc::new( + AttestationGrpcClient::new( + service.attester_client.clone() + ) + ); + let signer = Arc::new(AttesterLocalSigner::new(keypair.clone())); + let attester = + Attester::new( + attester_grpc_client, + signer); + let mut attester_service = AttesterService { + attester, + poll_interval_millis: POLL_INTERVAL_MILLIS, + log: log.clone(), + }; + attester_service.run(); + } } } - } - Ok(()) - })) - .map_err(|e| format!("Service thread failed: {:?}", e))?; + Ok(()) + }) + .map_err(|e| format!("Service thread failed: {:?}", e)), + ); // completed a slot process Ok(()) From 867af4bc6ad5efcaeba3d6891031c2bcb3997a8c Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Thu, 28 Mar 2019 21:00:38 +1100 Subject: [PATCH 034/106] Made the 'signers' an Arc, so that things compile. --- validator_client/src/duties/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 9d9221592..0b86e3ce9 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -42,7 +42,7 @@ pub struct DutiesManager { pub duties_map: RwLock, /// A list of all signer objects known to the validator service. // TODO: Generalise the signers, so that they're not just keypairs - pub signers: Vec, + pub signers: Arc>, pub beacon_node: Arc, } @@ -97,7 +97,7 @@ impl DutiesManager { // if the map is poisoned, return None let duties = self.duties_map.read().ok()?; - for validator_signer in &self.signers { + for validator_signer in self.signers.iter() { match duties.is_work_slot(slot, &validator_signer) { Ok(Some(work_type)) => current_work.push((validator_signer.clone(), work_type)), Ok(None) => {} // No work for this validator From 87acaac8a03b2735b20e64887c7d5e0a5627f55a Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Thu, 28 Mar 2019 21:01:47 +1100 Subject: [PATCH 035/106] Ran cargo fmt. --- .../test_harness/src/validator_harness/mod.rs | 8 ++-- eth2/attester/src/lib.rs | 37 +++++++++++-------- .../src/test_utils/simulated_beacon_node.rs | 2 +- eth2/attester/src/traits.rs | 2 +- eth2/block_proposer/src/lib.rs | 18 ++------- .../attestation_grpc_client.rs | 2 +- validator_client/src/duties/epoch_duties.rs | 2 +- validator_client/src/duties/mod.rs | 2 +- validator_client/src/service.rs | 16 +++----- 9 files changed, 38 insertions(+), 51 deletions(-) diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs index 074ede06a..43ad03ea7 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs @@ -2,13 +2,13 @@ mod direct_beacon_node; mod direct_duties; mod local_signer; +use crate::direct_beacon_node::DirectBeaconNode; use attester::PollOutcome as AttestationPollOutcome; use attester::{Attester, Error as AttestationPollError}; use beacon_chain::BeaconChain; use block_proposer::PollOutcome as BlockPollOutcome; use block_proposer::{BlockProducer, Error as BlockPollError}; use db::MemoryDB; -use crate::direct_beacon_node::DirectBeaconNode; use fork_choice::BitwiseLMDGhost; use local_signer::LocalSigner; use slot_clock::TestingSlotClock; @@ -32,10 +32,8 @@ type TestingBlockProducer = BlockProducer< LocalSigner, >; -type TestingAttester = Attester< - DirectBeaconNode>, - LocalSigner, ->; +type TestingAttester = + Attester>, LocalSigner>; /// A `BlockProducer` and `Attester` which sign using a common keypair. /// diff --git a/eth2/attester/src/lib.rs b/eth2/attester/src/lib.rs index 53d81e897..b5cdf5920 100644 --- a/eth2/attester/src/lib.rs +++ b/eth2/attester/src/lib.rs @@ -3,8 +3,10 @@ mod traits; use ssz::TreeHash; use std::sync::Arc; -use types::{AttestationData, AttestationDataAndCustodyBit, Attestation, Signature, - AggregateSignature, Slot, AttestationDuty, Bitfield}; +use types::{ + AggregateSignature, Attestation, AttestationData, AttestationDataAndCustodyBit, + AttestationDuty, Bitfield, Signature, Slot, +}; pub use self::traits::{ BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, @@ -59,20 +61,28 @@ impl Attester { } impl Attester { - - fn produce_attestation(&mut self, attestation_duty: AttestationDuty) -> Result { - let attestation_data = match self.beacon_node.produce_attestation_data( - attestation_duty.slot, - attestation_duty.shard - )? { + fn produce_attestation( + &mut self, + attestation_duty: AttestationDuty, + ) -> Result { + let attestation_data = match self + .beacon_node + .produce_attestation_data(attestation_duty.slot, attestation_duty.shard)? + { Some(attestation_data) => attestation_data, - None => return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation(attestation_duty.slot)), + None => { + return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation( + attestation_duty.slot, + )) + } }; dbg!(&attestation_data); if !self.safe_to_produce(&attestation_data) { - return Ok(PollOutcome::SlashableAttestationNotProduced(attestation_duty.slot)); + return Ok(PollOutcome::SlashableAttestationNotProduced( + attestation_duty.slot, + )); } let signature = match self.sign_attestation_data(&attestation_data) { @@ -82,7 +92,6 @@ impl Attester { let mut agg_sig = AggregateSignature::new(); agg_sig.add(&signature); - let attestation = Attestation { aggregation_bitfield: Bitfield::new(), data: attestation_data, @@ -172,10 +181,7 @@ mod tests { let attest_epoch = attest_slot / spec.slots_per_epoch; let attest_shard = 12; - let mut attester = Attester::new( - beacon_node.clone(), - signer.clone(), - ); + let mut attester = Attester::new(beacon_node.clone(), signer.clone()); // Configure responses from the BeaconNode. beacon_node.set_next_produce_result(Ok(Some(AttestationData::random_for_test(&mut rng)))); @@ -220,6 +226,5 @@ mod tests { Ok(PollOutcome::ProducerDutiesUnknown(slot)) ); */ - } } diff --git a/eth2/attester/src/test_utils/simulated_beacon_node.rs b/eth2/attester/src/test_utils/simulated_beacon_node.rs index 8e6c7c31d..eed6a38b9 100644 --- a/eth2/attester/src/test_utils/simulated_beacon_node.rs +++ b/eth2/attester/src/test_utils/simulated_beacon_node.rs @@ -1,6 +1,6 @@ use crate::traits::{BeaconNode, BeaconNodeError, PublishOutcome}; use std::sync::RwLock; -use types::{AttestationData, Attestation, Slot}; +use types::{Attestation, AttestationData, Slot}; type ProduceResult = Result, BeaconNodeError>; type PublishResult = Result; diff --git a/eth2/attester/src/traits.rs b/eth2/attester/src/traits.rs index 1c6d38578..94d138ae0 100644 --- a/eth2/attester/src/traits.rs +++ b/eth2/attester/src/traits.rs @@ -1,4 +1,4 @@ -use types::{AttestationData, Attestation, Signature, Slot}; +use types::{Attestation, AttestationData, Signature, Slot}; #[derive(Debug, PartialEq, Clone)] pub enum BeaconNodeError { diff --git a/eth2/block_proposer/src/lib.rs b/eth2/block_proposer/src/lib.rs index 1d2a4af71..646391c38 100644 --- a/eth2/block_proposer/src/lib.rs +++ b/eth2/block_proposer/src/lib.rs @@ -4,7 +4,7 @@ mod traits; use slot_clock::SlotClock; use ssz::{SignedRoot, TreeHash}; use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Domain, Slot, Fork}; +use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; pub use self::traits::{ BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, @@ -57,11 +57,7 @@ pub struct BlockProducer { impl BlockProducer { /// Returns a new instance where `last_processed_slot == 0`. - pub fn new( - spec: Arc, - beacon_node: Arc, - signer: Arc, - ) -> Self { + pub fn new(spec: Arc, beacon_node: Arc, signer: Arc) -> Self { Self { last_processed_slot: None, spec, @@ -72,7 +68,6 @@ impl BlockProducer { } impl BlockProducer { - /* No longer needed because we don't poll any more /// "Poll" to see if the validator is required to take any action. /// @@ -129,7 +124,6 @@ impl BlockProducer { /// The slash-protection code is not yet implemented. There is zero protection against /// slashing. fn produce_block(&mut self, slot: Slot, fork: Fork) -> Result { - let randao_reveal = { // TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`. let message = slot.epoch(self.spec.slots_per_epoch).hash_tree_root(); @@ -238,12 +232,8 @@ mod tests { let beacon_node = Arc::new(SimulatedBeaconNode::default()); let signer = Arc::new(LocalSigner::new(Keypair::random())); - - let mut block_proposer = BlockProducer::new( - spec.clone(), - beacon_node.clone(), - signer.clone(), - ); + let mut block_proposer = + BlockProducer::new(spec.clone(), beacon_node.clone(), signer.clone()); // Configure responses from the BeaconNode. beacon_node.set_next_produce_result(Ok(Some(BeaconBlock::random_for_test(&mut rng)))); diff --git a/validator_client/src/attester_service/attestation_grpc_client.rs b/validator_client/src/attester_service/attestation_grpc_client.rs index 97ec05899..05173d824 100644 --- a/validator_client/src/attester_service/attestation_grpc_client.rs +++ b/validator_client/src/attester_service/attestation_grpc_client.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use attester::{BeaconNode, BeaconNodeError, PublishOutcome}; use protos::services::ProduceAttestationDataRequest; -use types::{AttestationData, Attestation, Slot}; +use types::{Attestation, AttestationData, Slot}; pub struct AttestationGrpcClient { client: Arc, diff --git a/validator_client/src/duties/epoch_duties.rs b/validator_client/src/duties/epoch_duties.rs index 984dc6e00..47c9d96c4 100644 --- a/validator_client/src/duties/epoch_duties.rs +++ b/validator_client/src/duties/epoch_duties.rs @@ -44,7 +44,7 @@ impl EpochDuty { slot, shard: self.attestation_shard, committee_index: self.committee_index as usize, - validator_index: self.validator_index as usize + validator_index: self.validator_index as usize, }); } diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 0b86e3ce9..de08f6ce7 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -102,7 +102,7 @@ impl DutiesManager { Ok(Some(work_type)) => current_work.push((validator_signer.clone(), work_type)), Ok(None) => {} // No work for this validator //TODO: This should really log an error, as we shouldn't end up with an err here. - Err(_) => {} // Unknown epoch or validator, no work + Err(_) => {} // Unknown epoch or validator, no work } } if current_work.is_empty() { diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 86f310a06..36da36a1f 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -20,6 +20,7 @@ use slog::{debug, error, info, warn}; use slot_clock::{SlotClock, SystemTimeSlotClock}; use std::sync::Arc; use std::sync::RwLock; +use std::thread; use std::time::{Duration, Instant, SystemTime}; use tokio::prelude::*; use tokio::runtime::Builder; @@ -27,7 +28,6 @@ use tokio::timer::Interval; use tokio_timer::clock::Clock; use types::test_utils::generate_deterministic_keypairs; use types::{Epoch, Fork, Slot}; -use std::thread; //TODO: This service should be simplified in the future. Can be made more steamlined. @@ -268,17 +268,11 @@ impl Service { // available AttestationDuty info let attestation_duty = work_type.attestation_duty.expect("Cannot be None"); - let attester_grpc_client = - Arc::new( - AttestationGrpcClient::new( - service.attester_client.clone() - ) - ); + let attester_grpc_client = Arc::new(AttestationGrpcClient::new( + service.attester_client.clone(), + )); let signer = Arc::new(AttesterLocalSigner::new(keypair.clone())); - let attester = - Attester::new( - attester_grpc_client, - signer); + let attester = Attester::new(attester_grpc_client, signer); let mut attester_service = AttesterService { attester, poll_interval_millis: POLL_INTERVAL_MILLIS, From 6c8abd8990e552dc847205edf5b3dc2f33c5fcc9 Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Fri, 29 Mar 2019 00:02:41 +1100 Subject: [PATCH 036/106] Fixed merge conflict fail. --- validator_client/src/duties/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 569a99efa..de08f6ce7 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -51,11 +51,7 @@ impl DutiesManager { /// /// be a wall-clock (e.g., system time, remote server time, etc.). fn update(&self, epoch: Epoch) -> Result { -<<<<<<< HEAD let duties = self.beacon_node.request_duties(epoch, &self.signers)?; -======= - let duties = self.beacon_node.request_duties(epoch, &self.pubkeys)?; ->>>>>>> master { // If these duties were known, check to see if they're updates or identical. if let Some(known_duties) = self.duties_map.read()?.get(&epoch) { From 1e760d6719acc9bae01a8d2be7af21785c05aa9e Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 29 Mar 2019 00:43:53 +1100 Subject: [PATCH 037/106] Add Display for PublicKey --- eth2/utils/bls/src/public_key.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/eth2/utils/bls/src/public_key.rs b/eth2/utils/bls/src/public_key.rs index 5a348f530..5c4c3204c 100644 --- a/eth2/utils/bls/src/public_key.rs +++ b/eth2/utils/bls/src/public_key.rs @@ -7,6 +7,7 @@ use ssz::{ decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, }; use std::default; +use std::fmt; use std::hash::{Hash, Hasher}; /// A single BLS signature. @@ -54,6 +55,12 @@ impl PublicKey { } } +impl fmt::Display for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.concatenated_hex_id()) + } +} + impl default::Default for PublicKey { fn default() -> Self { let secret_key = SecretKey::random(); From 405ea619e2de512013e7a02449660554a8b7b4ae Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 29 Mar 2019 00:45:39 +1100 Subject: [PATCH 038/106] Clean up validator output --- validator_client/src/service.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 83e760855..614a66b61 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -235,7 +235,7 @@ impl Service { "The Timer should poll a new slot" ); - info!(log, "Processing slot: {}", current_slot.as_u64()); + info!(log, "Processing"; "slot" => current_slot.as_u64(), "epoch" => current_epoch.as_u64()); /* check for new duties */ @@ -243,8 +243,7 @@ impl Service { let cloned_log = log.clone(); // spawn a new thread separate to the runtime std::thread::spawn(move || { - cloned_manager.run_update(current_epoch.clone(), cloned_log.clone()); - dbg!("Finished thread"); + let _empty_error = cloned_manager.run_update(current_epoch.clone(), cloned_log.clone()); }); /* execute any specified duties */ From 68b33620c29b6d0f6f3dad591f1fdc301573e9a6 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 29 Mar 2019 02:23:03 +1100 Subject: [PATCH 039/106] Implement Display and clean validator output --- .../test_utils/testing_beacon_state_builder.rs | 2 +- validator_client/src/duties/epoch_duties.rs | 17 ++++++++++++++++- validator_client/src/duties/mod.rs | 14 ++++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index b38e8b527..5e4cebd57 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -120,7 +120,7 @@ impl TestingBeaconStateBuilder { }) .collect(); - let genesis_time = 1553753928; // arbitrary + let genesis_time = 1553776331; // arbitrary let mut state = BeaconState::genesis( genesis_time, diff --git a/validator_client/src/duties/epoch_duties.rs b/validator_client/src/duties/epoch_duties.rs index 5c23e82b1..f17737789 100644 --- a/validator_client/src/duties/epoch_duties.rs +++ b/validator_client/src/duties/epoch_duties.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::fmt; use std::ops::{Deref, DerefMut}; use types::{AttestationDuty, Epoch, PublicKey, Slot}; @@ -55,11 +56,25 @@ impl EpochDuty { None } } + +impl fmt::Display for EpochDuty { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut display_block = String::from("None"); + if let Some(block_slot) = self.block_production_slot { + display_block = block_slot.to_string(); + } + write!( + f, + "produce block slot: {}, attestation slot: {}, attestation shard: {}", + display_block, self.attestation_slot, self.attestation_shard + ) + } +} + /// Maps a list of public keys (many validators) to an EpochDuty. pub type EpochDuties = HashMap>; pub enum EpochDutiesMapError { - Poisoned, UnknownEpoch, UnknownValidator, } diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 0e962053e..9fce1a353 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -82,7 +82,8 @@ impl DutiesManager { info!(log, "Duties changed (potential re-org)"; "epoch" => epoch, "duties" => format!("{:?}", duties)) } Ok(UpdateOutcome::NewDuties(epoch, duties)) => { - info!(log, "New duties obtained"; "epoch" => epoch, "duties" => format!("{:?}", duties)) + info!(log, "New duties obtained"; "epoch" => epoch); + print_duties(&log, duties); } }; Ok(Async::Ready(())) @@ -126,13 +127,22 @@ impl From> for Error { impl From for Error { fn from(e: EpochDutiesMapError) -> Error { match e { - EpochDutiesMapError::Poisoned => Error::EpochMapPoisoned, EpochDutiesMapError::UnknownEpoch => Error::UnknownEpoch, EpochDutiesMapError::UnknownValidator => Error::UnknownValidator, } } } +fn print_duties(log: &slog::Logger, duties: EpochDuties) { + for (pk, duty) in duties.iter() { + if let Some(display_duty) = duty { + info!(log, "Validator: {}",pk; "Duty" => format!("{}",display_duty)); + } else { + info!(log, "Validator: {}",pk; "Duty" => "None"); + } + } +} + /* TODO: Modify tests for new Duties Manager form #[cfg(test)] mod tests { From be592c86d11fcd6cc0b80e0939d657355ac512b3 Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Fri, 29 Mar 2019 10:39:37 +1100 Subject: [PATCH 040/106] Started migrating FreeAttestation to Attestation in the harnesses - doesn't compile yet. --- .../test_harness/src/beacon_chain_harness.rs | 12 ++++++------ .../src/validator_harness/direct_beacon_node.rs | 14 +++++++------- .../test_harness/src/validator_harness/mod.rs | 14 ++------------ 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index 942497476..9f6643c7d 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -137,11 +137,11 @@ impl BeaconChainHarness { slot } - /// Gather the `FreeAttestation`s from the valiators. + /// Gather the `Attestation`s from the valiators. /// /// Note: validators will only produce attestations _once per slot_. So, if you call this twice /// you'll only get attestations on the first run. - pub fn gather_free_attesations(&mut self) -> Vec { + pub fn gather_attesations(&mut self) -> Vec { let present_slot = self.beacon_chain.present_slot(); let attesting_validators = self @@ -158,7 +158,7 @@ impl BeaconChainHarness { let attesting_validators: HashSet = HashSet::from_iter(attesting_validators.iter().cloned()); - let free_attestations: Vec = self + let attestations: Vec = self .validators .par_iter_mut() .enumerate() @@ -176,8 +176,8 @@ impl BeaconChainHarness { .collect(); debug!( - "Gathered {} FreeAttestations for slot {}.", - free_attestations.len(), + "Gathered {} Attestations for slot {}.", + attestations.len(), present_slot ); @@ -232,7 +232,7 @@ impl BeaconChainHarness { .unwrap(); }); - debug!("Free attestations processed."); + debug!("attestations processed."); block } diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs index 17630833b..7fc0376c8 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs @@ -12,7 +12,7 @@ use fork_choice::ForkChoice; use parking_lot::RwLock; use slot_clock::SlotClock; use std::sync::Arc; -use types::{AttestationData, BeaconBlock, FreeAttestation, Signature, Slot}; +use types::{AttestationData, BeaconBlock, Attestation, Signature, Slot}; // mod attester; // mod producer; @@ -20,13 +20,13 @@ use types::{AttestationData, BeaconBlock, FreeAttestation, Signature, Slot}; /// Connect directly to a borrowed `BeaconChain` instance so an attester/producer can request/submit /// blocks/attestations. /// -/// `BeaconBlock`s and `FreeAttestation`s are not actually published to the `BeaconChain`, instead +/// `BeaconBlock`s and `Attestation`s are not actually published to the `BeaconChain`, instead /// they are stored inside this struct. This is to allow one to benchmark the submission of the /// block/attestation directly, or modify it before submission. pub struct DirectBeaconNode { beacon_chain: Arc>, published_blocks: RwLock>, - published_attestations: RwLock>, + published_attestations: RwLock>, } impl DirectBeaconNode { @@ -44,7 +44,7 @@ impl DirectBeaconNode { } /// Get the last published attestation (if any). - pub fn last_published_free_attestation(&self) -> Option { + pub fn last_published_free_attestation(&self) -> Option { Some(self.published_attestations.read().last()?.clone()) } } @@ -55,7 +55,7 @@ impl AttesterBeaconNode for DirectBeac _slot: Slot, shard: u64, ) -> Result, NodeError> { - match self.beacon_chain.produce_attestation(shard) { + match self.beacon_chain.produce_attestation_data(shard) { Ok(attestation_data) => Ok(Some(attestation_data)), Err(e) => Err(NodeError::RemoteFailure(format!("{:?}", e))), } @@ -63,9 +63,9 @@ impl AttesterBeaconNode for DirectBeac fn publish_attestation( &self, - free_attestation: FreeAttestation, + attestation: Attestation, ) -> Result { - self.published_attestations.write().push(free_attestation); + self.published_attestations.write().push(attestation); Ok(AttestationPublishOutcome::ValidAttestation) } } diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs index 43ad03ea7..60258c794 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs @@ -2,7 +2,7 @@ mod direct_beacon_node; mod direct_duties; mod local_signer; -use crate::direct_beacon_node::DirectBeaconNode; +use crate::validator_harness::direct_beacon_node::DirectBeaconNode; use attester::PollOutcome as AttestationPollOutcome; use attester::{Attester, Error as AttestationPollError}; use beacon_chain::BeaconChain; @@ -44,10 +44,8 @@ pub struct ValidatorHarness { pub block_producer: TestingBlockProducer, pub attester: TestingAttester, pub spec: Arc, - pub epoch_map: Arc>>, pub keypair: Keypair, pub beacon_node: Arc>>, - pub slot_clock: Arc, pub signer: Arc, } @@ -61,22 +59,16 @@ impl ValidatorHarness { beacon_chain: Arc>>, spec: Arc, ) -> Self { - let slot_clock = Arc::new(TestingSlotClock::new(spec.genesis_slot.as_u64())); let signer = Arc::new(LocalSigner::new(keypair.clone())); let beacon_node = Arc::new(DirectBeaconNode::new(beacon_chain.clone())); - let epoch_map = Arc::new(DirectDuties::new(keypair.pk.clone(), beacon_chain.clone())); let block_producer = BlockProducer::new( spec.clone(), - epoch_map.clone(), - slot_clock.clone(), beacon_node.clone(), signer.clone(), ); let attester = Attester::new( - epoch_map.clone(), - slot_clock.clone(), beacon_node.clone(), signer.clone(), ); @@ -85,10 +77,8 @@ impl ValidatorHarness { block_producer, attester, spec, - epoch_map, keypair, beacon_node, - slot_clock, signer, } } @@ -113,7 +103,7 @@ impl ValidatorHarness { /// Run the `poll` function on the `Attester` and produce a `FreeAttestation`. /// /// An error is returned if the attester refuses to attest. - pub fn produce_free_attestation(&mut self) -> Result { + pub fn produce_attestation(&mut self) -> Result { match self.attester.poll() { Ok(AttestationPollOutcome::AttestationProduced(_)) => {} Ok(outcome) => return Err(AttestationProduceError::DidNotProduce(outcome)), From aa29a66facc79db11b3d45f827b5010ad363b5ac Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 29 Mar 2019 10:49:43 +1100 Subject: [PATCH 041/106] Add node chain-id validation for validation client --- validator_client/src/service.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 614a66b61..fb0304f87 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -1,4 +1,13 @@ -/// The validator service. Connects to a beacon node and signs blocks when required. +/// The Validator Client service. +/// +/// Connects to a beacon node and negotiates the correct chain id. +/// +/// Once connected, the service loads known validators keypairs from disk. Every slot, +/// the service pings the beacon node, asking for new duties for each of the validators. +/// +/// When a validator needs to either produce a block or sign an attestation, it requests the +/// data from the beacon node and performs the signing before publishing the block to the beacon +/// node. use crate::attester_service::{AttestationGrpcClient, AttesterService}; use crate::block_producer_service::{BeaconBlockGrpcClient, BlockProducerService}; use crate::config::Config as ValidatorConfig; @@ -36,8 +45,6 @@ pub struct Service { /// The node we currently connected to. connected_node_version: String, /// The chain id we are processing on. - chain_id: u16, - /// The fork state we processing on. fork: Fork, /// The slot clock for this service. slot_clock: SystemTimeSlotClock, @@ -74,7 +81,7 @@ impl Service { Arc::new(BeaconNodeServiceClient::new(ch)) }; - // retrieve node information + // retrieve node information and validate the beacon node let node_info = loop { match beacon_node_client.info(&Empty::new()) { Err(e) => { @@ -84,18 +91,27 @@ impl Service { continue; } Ok(info) => { + // verify the node's genesis time if SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs() < info.genesis_time { - warn!( + error!( log, "Beacon Node's genesis time is in the future. No work to do.\n Exiting" ); return Err("Genesis time in the future".into()); } + // verify the node's chain id + if config.spec.chain_id != info.chain_id as u8 { + error!( + log, + "Beacon Node's genesis time is in the future. No work to do.\n Exiting" + ); + return Err(format!("Beacon node has the wrong chain id. Expected chain id: {}, node's chain id: {}", config.spec.chain_id, info.chain_id).into()); + } break info; } }; @@ -150,7 +166,6 @@ impl Service { Ok(Self { connected_node_version: node_info.version, - chain_id: node_info.chain_id as u16, fork, slot_clock, current_slot, From f8201edddda0e5bbace08dd205e1bd5145377d76 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 29 Mar 2019 14:52:08 +1100 Subject: [PATCH 042/106] Initial layout of beacon block production --- validator_client/src/beacon_block_node.rs | 23 ++ .../beacon_block_grpc_client.rs | 81 ------- .../block_producer_service/block_producer.rs | 227 ++++++++++++++++++ .../src/block_producer_service/mod.rs | 125 ++++++---- validator_client/src/service.rs | 3 +- 5 files changed, 323 insertions(+), 136 deletions(-) create mode 100644 validator_client/src/beacon_block_node.rs delete mode 100644 validator_client/src/block_producer_service/beacon_block_grpc_client.rs create mode 100644 validator_client/src/block_producer_service/block_producer.rs diff --git a/validator_client/src/beacon_block_node.rs b/validator_client/src/beacon_block_node.rs new file mode 100644 index 000000000..bc85ef194 --- /dev/null +++ b/validator_client/src/beacon_block_node.rs @@ -0,0 +1,23 @@ +#[Derive(Debug, PartialEq, Clone)] +pub enum BeaconNodeError { + RemoteFailure(String), + DecodeFailure, +} + +/// Defines the methods required to produce and publish blocks on a Beacon Node. Abstracts the +/// actual beacon node. +pub trait BeaconNode: Send + Sync { + /// Request that the node produces a block. + /// + /// Returns Ok(None) if the Beacon Node is unable to produce at the given slot. + fn produce_beacon_block( + &self, + slot: Slot, + randao_reveal: &Signature, + ) -> Result, BeaconNodeError>; + + /// Request that the node publishes a block. + /// + /// Returns `true` if the publish was sucessful. + fn publish_beacon_block(&self, block: BeaconBlock) -> Result; +} 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 deleted file mode 100644 index ba2acfffb..000000000 --- a/validator_client/src/block_producer_service/beacon_block_grpc_client.rs +++ /dev/null @@ -1,81 +0,0 @@ -use block_proposer::{BeaconNode, BeaconNodeError, PublishOutcome}; -use protos::services::{ - BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, -}; -use protos::services_grpc::BeaconBlockServiceClient; -use ssz::{ssz_encode, Decodable}; -use std::sync::Arc; -use types::{BeaconBlock, Signature, Slot}; - -/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be -/// implemented upon it. -pub struct BeaconBlockGrpcClient { - client: Arc, -} - -impl BeaconBlockGrpcClient { - pub fn new(client: Arc) -> Self { - Self { client } - } -} - -impl BeaconNode for BeaconBlockGrpcClient { - /// Request a Beacon Node (BN) to produce a new block at the supplied slot. - /// - /// Returns `None` if it is not possible to produce at the supplied slot. For example, if the - /// BN is unable to find a parent block. - fn produce_beacon_block( - &self, - slot: Slot, - // TODO: use randao_reveal, when proto APIs have been updated. - _randao_reveal: &Signature, - ) -> Result, BeaconNodeError> { - let mut req = ProduceBeaconBlockRequest::new(); - req.set_slot(slot.as_u64()); - - let reply = self - .client - .produce_beacon_block(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - - if reply.has_block() { - let block = reply.get_block(); - let ssz = block.get_ssz(); - - let (block, _i) = - BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| BeaconNodeError::DecodeFailure)?; - - Ok(Some(block)) - } else { - Ok(None) - } - } - - /// Request a Beacon Node (BN) to publish a block. - /// - /// Generally, this will be called after a `produce_beacon_block` call with a block that has - /// been completed (signed) by the validator client. - fn publish_beacon_block(&self, block: BeaconBlock) -> Result { - let mut req = PublishBeaconBlockRequest::new(); - - let ssz = ssz_encode(&block); - - // TODO: this conversion is incomplete; fix it. - let mut grpc_block = GrpcBeaconBlock::new(); - grpc_block.set_ssz(ssz); - - req.set_block(grpc_block); - - let reply = self - .client - .publish_beacon_block(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - - if reply.get_success() { - Ok(PublishOutcome::ValidBlock) - } else { - // TODO: distinguish between different errors - Ok(PublishOutcome::InvalidBlock("Publish failed".to_string())) - } - } -} diff --git a/validator_client/src/block_producer_service/block_producer.rs b/validator_client/src/block_producer_service/block_producer.rs new file mode 100644 index 000000000..187f2b649 --- /dev/null +++ b/validator_client/src/block_producer_service/block_producer.rs @@ -0,0 +1,227 @@ +pub mod test_utils; +mod traits; + +use slot_clock::SlotClock; +use ssz::{SignedRoot, TreeHash}; +use std::sync::Arc; +use types::{BeaconBlock, ChainSpec, Domain, Slot}; + +#[derive(Debug, PartialEq)] +pub enum Error { + SlotClockError, + SlotUnknowable, + EpochMapPoisoned, + SlotClockPoisoned, + EpochLengthIsZero, + BeaconNodeError(BeaconNodeError), +} + +#[derive(Debug, PartialEq)] +pub enum BlockProducerEvent { + /// A new block was produced. + BlockProduced(Slot), + /// A block was not produced as it would have been slashable. + SlashableBlockNotProduced(Slot), + /// The Beacon Node was unable to produce a block at that slot. + BeaconNodeUnableToProduceBlock(Slot), + /// The signer failed to sign the message. + SignerRejection(Slot), + /// The public key for this validator is not an active validator. + ValidatorIsUnknown(Slot), +} + +/// This struct contains the logic for requesting and signing beacon blocks for a validator. The +/// validator can abstractly sign via the Signer trait object. +pub struct BlockProducer { + /// The current fork. + pub fork: Fork, + /// The current slot to produce a block for. + pub slot: Slot, + /// The current epoch. + pub epoch: Epoch, + /// The beacon node to connect to. + pub beacon_node: Arc, + /// The signer to sign the block. + pub signer: Arc, +} + +impl BlockProducer { + + /// Produce a block at some slot. + /// + /// Assumes that a block is required at this slot (does not check the duties). + /// + /// Ensures the message is not slashable. + /// + /// !!! UNSAFE !!! + /// + /// The slash-protection code is not yet implemented. There is zero protection against + /// slashing. + fn produce_block(&mut self) -> Result { + + let randao_reveal = { + // TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`. + let message = slot.epoch(self.spec.slots_per_epoch).hash_tree_root(); + + match self.signer.sign_randao_reveal( + &message, + self.spec + .get_domain(slot.epoch(self.spec.slots_per_epoch), Domain::Randao, &fork), + ) { + None => return Ok(PollOutcome::SignerRejection(slot)), + Some(signature) => signature, + } + }; + + if let Some(block) = self + .beacon_node + .produce_beacon_block(slot, &randao_reveal)? + { + if self.safe_to_produce(&block) { + let domain = self.spec.get_domain( + slot.epoch(self.spec.slots_per_epoch), + Domain::BeaconBlock, + &fork, + ); + if let Some(block) = self.sign_block(block, domain) { + self.beacon_node.publish_beacon_block(block)?; + Ok(PollOutcome::BlockProduced(slot)) + } else { + Ok(PollOutcome::SignerRejection(slot)) + } + } else { + Ok(PollOutcome::SlashableBlockNotProduced(slot)) + } + } else { + Ok(PollOutcome::BeaconNodeUnableToProduceBlock(slot)) + } + } + + /// Consumes a block, returning that block signed by the validators private key. + /// + /// Important: this function will not check to ensure the block is not slashable. This must be + /// done upstream. + fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option { + self.store_produce(&block); + + match self + .signer + .sign_block_proposal(&block.signed_root()[..], domain) + { + None => None, + Some(signature) => { + block.signature = signature; + Some(block) + } + } + } + + /// Returns `true` if signing a block is safe (non-slashable). + /// + /// !!! UNSAFE !!! + /// + /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. + fn safe_to_produce(&self, _block: &BeaconBlock) -> bool { + // TODO: ensure the producer doesn't produce slashable blocks. + // https://github.com/sigp/lighthouse/issues/160 + true + } + + /// Record that a block was produced so that slashable votes may not be made in the future. + /// + /// !!! UNSAFE !!! + /// + /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. + fn store_produce(&mut self, _block: &BeaconBlock) { + // TODO: record this block production to prevent future slashings. + // https://github.com/sigp/lighthouse/issues/160 + } +} + +impl From for Error { + fn from(e: BeaconNodeError) -> Error { + Error::BeaconNodeError(e) + } +} + + +/* Old tests - Re-work for new logic +#[cfg(test)] +mod tests { + use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode}; + use super::*; + use slot_clock::TestingSlotClock; + use types::{ + test_utils::{SeedableRng, TestRandom, XorShiftRng}, + Keypair, + }; + + // TODO: implement more thorough testing. + // https://github.com/sigp/lighthouse/issues/160 + // + // These tests should serve as a good example for future tests. + + #[test] + pub fn polling() { + let mut rng = XorShiftRng::from_seed([42; 16]); + + let spec = Arc::new(ChainSpec::foundation()); + let slot_clock = Arc::new(TestingSlotClock::new(0)); + let beacon_node = Arc::new(SimulatedBeaconNode::default()); + let signer = Arc::new(LocalSigner::new(Keypair::random())); + + let mut epoch_map = EpochMap::new(spec.slots_per_epoch); + let produce_slot = Slot::new(100); + let produce_epoch = produce_slot.epoch(spec.slots_per_epoch); + epoch_map.map.insert(produce_epoch, produce_slot); + let epoch_map = Arc::new(epoch_map); + + let mut block_proposer = BlockProducer::new( + spec.clone(), + epoch_map.clone(), + slot_clock.clone(), + beacon_node.clone(), + signer.clone(), + ); + + // Configure responses from the BeaconNode. + beacon_node.set_next_produce_result(Ok(Some(BeaconBlock::random_for_test(&mut rng)))); + beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidBlock)); + + // One slot before production slot... + slot_clock.set_slot(produce_slot.as_u64() - 1); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1)) + ); + + // On the produce slot... + slot_clock.set_slot(produce_slot.as_u64()); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::BlockProduced(produce_slot.into())) + ); + + // Trying the same produce slot again... + slot_clock.set_slot(produce_slot.as_u64()); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::SlotAlreadyProcessed(produce_slot)) + ); + + // One slot after the produce slot... + slot_clock.set_slot(produce_slot.as_u64() + 1); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1)) + ); + + // In an epoch without known duties... + let slot = (produce_epoch.as_u64() + 1) * spec.slots_per_epoch; + slot_clock.set_slot(slot); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::ProducerDutiesUnknown(Slot::new(slot))) + ); + } +} diff --git a/validator_client/src/block_producer_service/mod.rs b/validator_client/src/block_producer_service/mod.rs index 91e7606a7..8a8cce613 100644 --- a/validator_client/src/block_producer_service/mod.rs +++ b/validator_client/src/block_producer_service/mod.rs @@ -1,61 +1,80 @@ -mod beacon_block_grpc_client; -// mod block_producer_service; - -use block_proposer::{ - BeaconNode, BlockProducer, DutiesReader, PollOutcome as BlockProducerPollOutcome, Signer, +use protos::services::{ + BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, }; -use slog::{error, info, warn, Logger}; -use slot_clock::SlotClock; -use std::time::Duration; +use protos::services_grpc::BeaconBlockServiceClient; +use ssz::{ssz_encode, Decodable}; +use std::sync::Arc; +use types::{BeaconBlock, Signature, Slot}; -pub use self::beacon_block_grpc_client::BeaconBlockGrpcClient; - -pub struct BlockProducerService { - pub block_producer: BlockProducer, - pub poll_interval_millis: u64, - pub log: Logger, +/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be +/// implemented upon it. +pub struct BeaconBlockGrpcClient { + inner: Arc, } -impl BlockProducerService { - /// Run a loop which polls the block producer each `poll_interval_millis` millseconds. - /// - /// Logs the results of the polls. - pub fn run(&mut self) { - loop { - match self.block_producer.poll() { - Err(error) => { - error!(self.log, "Block producer poll error"; "error" => format!("{:?}", error)) - } - Ok(BlockProducerPollOutcome::BlockProduced(slot)) => { - info!(self.log, "Produced block"; "slot" => slot) - } - Ok(BlockProducerPollOutcome::SlashableBlockNotProduced(slot)) => { - warn!(self.log, "Slashable block was not signed"; "slot" => slot) - } - Ok(BlockProducerPollOutcome::BlockProductionNotRequired(slot)) => { - info!(self.log, "Block production not required"; "slot" => slot) - } - Ok(BlockProducerPollOutcome::ProducerDutiesUnknown(slot)) => { - error!(self.log, "Block production duties unknown"; "slot" => slot) - } - Ok(BlockProducerPollOutcome::SlotAlreadyProcessed(slot)) => { - warn!(self.log, "Attempted to re-process slot"; "slot" => slot) - } - Ok(BlockProducerPollOutcome::BeaconNodeUnableToProduceBlock(slot)) => { - error!(self.log, "Beacon node unable to produce block"; "slot" => slot) - } - Ok(BlockProducerPollOutcome::SignerRejection(slot)) => { - error!(self.log, "The cryptographic signer refused to sign the block"; "slot" => slot) - } - Ok(BlockProducerPollOutcome::ValidatorIsUnknown(slot)) => { - error!(self.log, "The Beacon Node does not recognise the validator"; "slot" => slot) - } - Ok(BlockProducerPollOutcome::UnableToGetFork(slot)) => { - error!(self.log, "Unable to get a `Fork` struct to generate signature domains"; "slot" => slot) - } - }; +impl BeaconBlockGrpcClient { + pub fn new(client: Arc) -> Self { + Self { inner: client } + } +} - std::thread::sleep(Duration::from_millis(self.poll_interval_millis)); +impl BeaconNode for BeaconBlockGrpcClient { + /// Request a Beacon Node (BN) to produce a new block at the supplied slot. + /// + /// Returns `None` if it is not possible to produce at the supplied slot. For example, if the + /// BN is unable to find a parent block. + fn produce_beacon_block( + &self, + slot: Slot, + // TODO: use randao_reveal, when proto APIs have been updated. + _randao_reveal: &Signature, + ) -> Result, BeaconNodeError> { + let mut req = ProduceBeaconBlockRequest::new(); + req.set_slot(slot.as_u64()); + + let reply = self + .client + .produce_beacon_block(&req) + .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; + + if reply.has_block() { + let block = reply.get_block(); + let ssz = block.get_ssz(); + + let (block, _i) = + BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| BeaconNodeError::DecodeFailure)?; + + Ok(Some(block)) + } else { + Ok(None) + } + } + + /// Request a Beacon Node (BN) to publish a block. + /// + /// Generally, this will be called after a `produce_beacon_block` call with a block that has + /// been completed (signed) by the validator client. + fn publish_beacon_block(&self, block: BeaconBlock) -> Result { + let mut req = PublishBeaconBlockRequest::new(); + + let ssz = ssz_encode(&block); + + // TODO: this conversion is incomplete; fix it. + let mut grpc_block = GrpcBeaconBlock::new(); + grpc_block.set_ssz(ssz); + + req.set_block(grpc_block); + + let reply = self + .client + .publish_beacon_block(&req) + .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; + + if reply.get_success() { + Ok(PublishOutcome::ValidBlock) + } else { + // TODO: distinguish between different errors + Ok(PublishOutcome::InvalidBlock("Publish failed".to_string())) } } } diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index fb0304f87..64ed7cb03 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -78,7 +78,7 @@ impl Service { // Beacon node gRPC beacon node endpoints. let beacon_node_client = { let ch = ChannelBuilder::new(env.clone()).connect(&config.server); - Arc::new(BeaconNodeServiceClient::new(ch)) + BeaconNodeServiceClient::new(ch) }; // retrieve node information and validate the beacon node @@ -287,7 +287,6 @@ impl Service { } /* - // Spawn a new thread to perform block production for the validator. let producer_thread = { let spec = spec.clone(); From eea772de3eb059530460fb845632312bc6d6f358 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 29 Mar 2019 16:33:27 +1100 Subject: [PATCH 043/106] Implement block producer for validator client --- protos/src/services.proto | 3 + validator_client/Cargo.toml | 5 -- validator_client/src/beacon_block_node.rs | 23 ------- .../beacon_block_node.rs | 33 ++++++++++ .../block_producer_service/block_producer.rs | 60 ++++++++----------- .../src/block_producer_service/mod.rs | 33 ++++++---- validator_client/src/lib.rs | 3 - validator_client/src/main.rs | 1 + validator_client/src/service.rs | 2 +- validator_client/src/signer.rs | 7 +++ 10 files changed, 92 insertions(+), 78 deletions(-) delete mode 100644 validator_client/src/beacon_block_node.rs create mode 100644 validator_client/src/block_producer_service/beacon_block_node.rs delete mode 100644 validator_client/src/lib.rs create mode 100644 validator_client/src/signer.rs diff --git a/protos/src/services.proto b/protos/src/services.proto index dd82855a1..e5095f386 100644 --- a/protos/src/services.proto +++ b/protos/src/services.proto @@ -19,7 +19,9 @@ service BeaconNodeService { /// Service that handles block production service BeaconBlockService { + // Requests a block to be signed from the beacon node. rpc ProduceBeaconBlock(ProduceBeaconBlockRequest) returns (ProduceBeaconBlockResponse); + // Responds to the node the signed block to be published. rpc PublishBeaconBlock(PublishBeaconBlockRequest) returns (PublishBeaconBlockResponse); } @@ -64,6 +66,7 @@ message Empty {} // Validator requests an unsigned proposal. message ProduceBeaconBlockRequest { uint64 slot = 1; + bytes randao_reveal = 2; } // Beacon node returns an unsigned proposal. diff --git a/validator_client/Cargo.toml b/validator_client/Cargo.toml index 570e06d74..209ebf25e 100644 --- a/validator_client/Cargo.toml +++ b/validator_client/Cargo.toml @@ -8,11 +8,6 @@ edition = "2018" name = "validator_client" path = "src/main.rs" -[lib] -name = "validator_client" -path = "src/lib.rs" - - [dependencies] block_proposer = { path = "../eth2/block_proposer" } attester = { path = "../eth2/attester" } diff --git a/validator_client/src/beacon_block_node.rs b/validator_client/src/beacon_block_node.rs deleted file mode 100644 index bc85ef194..000000000 --- a/validator_client/src/beacon_block_node.rs +++ /dev/null @@ -1,23 +0,0 @@ -#[Derive(Debug, PartialEq, Clone)] -pub enum BeaconNodeError { - RemoteFailure(String), - DecodeFailure, -} - -/// Defines the methods required to produce and publish blocks on a Beacon Node. Abstracts the -/// actual beacon node. -pub trait BeaconNode: Send + Sync { - /// Request that the node produces a block. - /// - /// Returns Ok(None) if the Beacon Node is unable to produce at the given slot. - fn produce_beacon_block( - &self, - slot: Slot, - randao_reveal: &Signature, - ) -> Result, BeaconNodeError>; - - /// Request that the node publishes a block. - /// - /// Returns `true` if the publish was sucessful. - fn publish_beacon_block(&self, block: BeaconBlock) -> Result; -} diff --git a/validator_client/src/block_producer_service/beacon_block_node.rs b/validator_client/src/block_producer_service/beacon_block_node.rs new file mode 100644 index 000000000..5a581a4a7 --- /dev/null +++ b/validator_client/src/block_producer_service/beacon_block_node.rs @@ -0,0 +1,33 @@ +use types::{BeaconBlock, Signature, Slot}; +#[derive(Debug, PartialEq, Clone)] +pub enum BeaconBlockNodeError { + RemoteFailure(String), + DecodeFailure, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum PublishOutcome { + ValidBlock, + InvalidBlock(String), +} + +/// Defines the methods required to produce and publish blocks on a Beacon Node. Abstracts the +/// actual beacon node. +pub trait BeaconBlockNode: Send + Sync { + /// Request that the node produces a block. + /// + /// Returns Ok(None) if the Beacon Node is unable to produce at the given slot. + fn produce_beacon_block( + &self, + slot: Slot, + randao_reveal: &Signature, + ) -> Result, BeaconBlockNodeError>; + + /// Request that the node publishes a block. + /// + /// Returns `true` if the publish was successful. + fn publish_beacon_block( + &self, + block: BeaconBlock, + ) -> Result; +} diff --git a/validator_client/src/block_producer_service/block_producer.rs b/validator_client/src/block_producer_service/block_producer.rs index 187f2b649..e71e6cd4b 100644 --- a/validator_client/src/block_producer_service/block_producer.rs +++ b/validator_client/src/block_producer_service/block_producer.rs @@ -1,10 +1,8 @@ -pub mod test_utils; -mod traits; - -use slot_clock::SlotClock; +use super::beacon_block_node::{BeaconBlockNode, BeaconBlockNodeError}; +use crate::signer::Signer; use ssz::{SignedRoot, TreeHash}; use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Domain, Slot}; +use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; #[derive(Debug, PartialEq)] pub enum Error { @@ -13,11 +11,11 @@ pub enum Error { EpochMapPoisoned, SlotClockPoisoned, EpochLengthIsZero, - BeaconNodeError(BeaconNodeError), + BeaconBlockNodeError(BeaconBlockNodeError), } #[derive(Debug, PartialEq)] -pub enum BlockProducerEvent { +pub enum ValidatorEvent { /// A new block was produced. BlockProduced(Slot), /// A block was not produced as it would have been slashable. @@ -32,21 +30,20 @@ pub enum BlockProducerEvent { /// This struct contains the logic for requesting and signing beacon blocks for a validator. The /// validator can abstractly sign via the Signer trait object. -pub struct BlockProducer { +pub struct BlockProducer { /// The current fork. pub fork: Fork, /// The current slot to produce a block for. pub slot: Slot, /// The current epoch. - pub epoch: Epoch, + pub spec: Arc, /// The beacon node to connect to. pub beacon_node: Arc, /// The signer to sign the block. pub signer: Arc, } -impl BlockProducer { - +impl BlockProducer { /// Produce a block at some slot. /// /// Assumes that a block is required at this slot (does not check the duties). @@ -57,43 +54,38 @@ impl BlockProducer { /// /// The slash-protection code is not yet implemented. There is zero protection against /// slashing. - fn produce_block(&mut self) -> Result { + fn produce_block(&mut self) -> Result { + let epoch = self.slot.epoch(self.spec.slots_per_epoch); let randao_reveal = { - // TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`. - let message = slot.epoch(self.spec.slots_per_epoch).hash_tree_root(); - - match self.signer.sign_randao_reveal( + let message = epoch.hash_tree_root(); + let randao_reveal = match self.signer.sign_randao_reveal( &message, - self.spec - .get_domain(slot.epoch(self.spec.slots_per_epoch), Domain::Randao, &fork), + self.spec.get_domain(epoch, Domain::Randao, &self.fork), ) { - None => return Ok(PollOutcome::SignerRejection(slot)), + None => return Ok(ValidatorEvent::SignerRejection(self.slot)), Some(signature) => signature, - } + }; + randao_reveal }; if let Some(block) = self .beacon_node - .produce_beacon_block(slot, &randao_reveal)? + .produce_beacon_block(self.slot, &randao_reveal)? { if self.safe_to_produce(&block) { - let domain = self.spec.get_domain( - slot.epoch(self.spec.slots_per_epoch), - Domain::BeaconBlock, - &fork, - ); + let domain = self.spec.get_domain(epoch, Domain::BeaconBlock, &self.fork); if let Some(block) = self.sign_block(block, domain) { self.beacon_node.publish_beacon_block(block)?; - Ok(PollOutcome::BlockProduced(slot)) + Ok(ValidatorEvent::BlockProduced(self.slot)) } else { - Ok(PollOutcome::SignerRejection(slot)) + Ok(ValidatorEvent::SignerRejection(self.slot)) } } else { - Ok(PollOutcome::SlashableBlockNotProduced(slot)) + Ok(ValidatorEvent::SlashableBlockNotProduced(self.slot)) } } else { - Ok(PollOutcome::BeaconNodeUnableToProduceBlock(slot)) + Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(self.slot)) } } @@ -138,13 +130,12 @@ impl BlockProducer { } } -impl From for Error { - fn from(e: BeaconNodeError) -> Error { - Error::BeaconNodeError(e) +impl From for Error { + fn from(e: BeaconBlockNodeError) -> Error { + Error::BeaconBlockNodeError(e) } } - /* Old tests - Re-work for new logic #[cfg(test)] mod tests { @@ -225,3 +216,4 @@ mod tests { ); } } +*/ diff --git a/validator_client/src/block_producer_service/mod.rs b/validator_client/src/block_producer_service/mod.rs index 8a8cce613..fe34f627d 100644 --- a/validator_client/src/block_producer_service/mod.rs +++ b/validator_client/src/block_producer_service/mod.rs @@ -1,3 +1,7 @@ +mod beacon_block_node; +mod block_producer; + +use self::beacon_block_node::*; use protos::services::{ BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, }; @@ -9,16 +13,16 @@ use types::{BeaconBlock, Signature, Slot}; /// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be /// implemented upon it. pub struct BeaconBlockGrpcClient { - inner: Arc, + client: Arc, } impl BeaconBlockGrpcClient { pub fn new(client: Arc) -> Self { - Self { inner: client } + Self { client } } } -impl BeaconNode for BeaconBlockGrpcClient { +impl BeaconBlockNode for BeaconBlockGrpcClient { /// Request a Beacon Node (BN) to produce a new block at the supplied slot. /// /// Returns `None` if it is not possible to produce at the supplied slot. For example, if the @@ -26,23 +30,26 @@ impl BeaconNode for BeaconBlockGrpcClient { fn produce_beacon_block( &self, slot: Slot, - // TODO: use randao_reveal, when proto APIs have been updated. - _randao_reveal: &Signature, - ) -> Result, BeaconNodeError> { + randao_reveal: &Signature, + ) -> Result, BeaconBlockNodeError> { + // request a beacon block from the node let mut req = ProduceBeaconBlockRequest::new(); req.set_slot(slot.as_u64()); + req.set_randao_reveal(ssz_encode(randao_reveal)); + //TODO: Determine if we want an explicit timeout let reply = self .client .produce_beacon_block(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; + .map_err(|err| BeaconBlockNodeError::RemoteFailure(format!("{:?}", err)))?; + // format the reply if reply.has_block() { let block = reply.get_block(); let ssz = block.get_ssz(); - let (block, _i) = - BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| BeaconNodeError::DecodeFailure)?; + let (block, _i) = BeaconBlock::ssz_decode(&ssz, 0) + .map_err(|_| BeaconBlockNodeError::DecodeFailure)?; Ok(Some(block)) } else { @@ -54,12 +61,14 @@ impl BeaconNode for BeaconBlockGrpcClient { /// /// Generally, this will be called after a `produce_beacon_block` call with a block that has /// been completed (signed) by the validator client. - fn publish_beacon_block(&self, block: BeaconBlock) -> Result { + fn publish_beacon_block( + &self, + block: BeaconBlock, + ) -> Result { let mut req = PublishBeaconBlockRequest::new(); let ssz = ssz_encode(&block); - // TODO: this conversion is incomplete; fix it. let mut grpc_block = GrpcBeaconBlock::new(); grpc_block.set_ssz(ssz); @@ -68,7 +77,7 @@ impl BeaconNode for BeaconBlockGrpcClient { let reply = self .client .publish_beacon_block(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; + .map_err(|err| BeaconBlockNodeError::RemoteFailure(format!("{:?}", err)))?; if reply.get_success() { Ok(PublishOutcome::ValidBlock) diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs deleted file mode 100644 index 470a070e8..000000000 --- a/validator_client/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod config; - -pub use crate::config::Config; diff --git a/validator_client/src/main.rs b/validator_client/src/main.rs index d044030fe..0b11ed0d0 100644 --- a/validator_client/src/main.rs +++ b/validator_client/src/main.rs @@ -4,6 +4,7 @@ mod config; mod duties; pub mod error; mod service; +mod signer; use crate::config::Config as ValidatorClientConfig; use clap::{App, Arg}; diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 64ed7cb03..9c0f5d23c 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -9,7 +9,7 @@ /// data from the beacon node and performs the signing before publishing the block to the beacon /// node. use crate::attester_service::{AttestationGrpcClient, AttesterService}; -use crate::block_producer_service::{BeaconBlockGrpcClient, BlockProducerService}; +use crate::block_producer_service::BeaconBlockGrpcClient; use crate::config::Config as ValidatorConfig; use crate::duties::UpdateOutcome; use crate::duties::{DutiesManager, EpochDutiesMap}; diff --git a/validator_client/src/signer.rs b/validator_client/src/signer.rs new file mode 100644 index 000000000..85bf35b16 --- /dev/null +++ b/validator_client/src/signer.rs @@ -0,0 +1,7 @@ +use types::Signature; + +/// Signs message using an internally-maintained private key. +pub trait Signer { + fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option; + fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option; +} From 9cdb7bb716f375df88f185ff590c633cc18928a0 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 29 Mar 2019 17:28:07 +1100 Subject: [PATCH 044/106] Restructure of validator client service and block producer --- .../beacon_block_node.rs | 0 .../block_producer.rs | 0 .../mod.rs | 0 .../{traits.rs => beacon_node_duties.rs} | 6 +- validator_client/src/duties/grpc.rs | 8 +- validator_client/src/duties/mod.rs | 16 +- validator_client/src/main.rs | 2 +- validator_client/src/service.rs | 251 ++++++++---------- 8 files changed, 131 insertions(+), 152 deletions(-) rename validator_client/src/{block_producer_service => block_producer}/beacon_block_node.rs (100%) rename validator_client/src/{block_producer_service => block_producer}/block_producer.rs (100%) rename validator_client/src/{block_producer_service => block_producer}/mod.rs (100%) rename validator_client/src/duties/{traits.rs => beacon_node_duties.rs} (79%) diff --git a/validator_client/src/block_producer_service/beacon_block_node.rs b/validator_client/src/block_producer/beacon_block_node.rs similarity index 100% rename from validator_client/src/block_producer_service/beacon_block_node.rs rename to validator_client/src/block_producer/beacon_block_node.rs diff --git a/validator_client/src/block_producer_service/block_producer.rs b/validator_client/src/block_producer/block_producer.rs similarity index 100% rename from validator_client/src/block_producer_service/block_producer.rs rename to validator_client/src/block_producer/block_producer.rs diff --git a/validator_client/src/block_producer_service/mod.rs b/validator_client/src/block_producer/mod.rs similarity index 100% rename from validator_client/src/block_producer_service/mod.rs rename to validator_client/src/block_producer/mod.rs diff --git a/validator_client/src/duties/traits.rs b/validator_client/src/duties/beacon_node_duties.rs similarity index 79% rename from validator_client/src/duties/traits.rs rename to validator_client/src/duties/beacon_node_duties.rs index 374bed9f6..efe9e836d 100644 --- a/validator_client/src/duties/traits.rs +++ b/validator_client/src/duties/beacon_node_duties.rs @@ -2,12 +2,12 @@ use super::EpochDuties; use types::{Epoch, PublicKey}; #[derive(Debug, PartialEq, Clone)] -pub enum BeaconNodeError { +pub enum BeaconNodeDutiesError { RemoteFailure(String), } /// Defines the methods required to obtain a validators shuffling from a Beacon Node. -pub trait BeaconNode: Send + Sync { +pub trait BeaconNodeDuties: Send + Sync { /// Gets the duties for all validators. /// /// Returns a vector of EpochDuties for each validator public key. The entry will be None for @@ -16,5 +16,5 @@ pub trait BeaconNode: Send + Sync { &self, epoch: Epoch, pubkeys: &[PublicKey], - ) -> Result; + ) -> Result; } diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index 511ffa34a..f05307141 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -1,5 +1,5 @@ +use super::beacon_node_duties::{BeaconNodeDuties, BeaconNodeDutiesError}; use super::epoch_duties::{EpochDuties, EpochDuty}; -use super::traits::{BeaconNode, BeaconNodeError}; use grpcio::CallOption; use protos::services::{GetDutiesRequest, Validators}; use protos::services_grpc::ValidatorServiceClient; @@ -8,13 +8,13 @@ use std::collections::HashMap; use std::time::Duration; use types::{Epoch, PublicKey, Slot}; -impl BeaconNode for ValidatorServiceClient { +impl BeaconNodeDuties for ValidatorServiceClient { /// Requests all duties (block signing and committee attesting) from the Beacon Node (BN). fn request_duties( &self, epoch: Epoch, pubkeys: &[PublicKey], - ) -> Result { + ) -> Result { // Get the required duties from all validators // build the request let mut req = GetDutiesRequest::new(); @@ -29,7 +29,7 @@ impl BeaconNode for ValidatorServiceClient { // send the request, get the duties reply let reply = self .get_validator_duties(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; + .map_err(|err| BeaconNodeDutiesError::RemoteFailure(format!("{:?}", err)))?; let mut epoch_duties: HashMap> = HashMap::new(); for (index, validator_duty) in reply.get_active_validators().iter().enumerate() { diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 9fce1a353..c16fc81fc 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -1,13 +1,13 @@ +mod beacon_node_duties; mod epoch_duties; mod grpc; // TODO: reintroduce tests //#[cfg(test)] //mod test_node; -mod traits; +pub use self::beacon_node_duties::{BeaconNodeDuties, BeaconNodeDutiesError}; use self::epoch_duties::{EpochDuties, EpochDutiesMapError}; pub use self::epoch_duties::{EpochDutiesMap, WorkInfo}; -use self::traits::{BeaconNode, BeaconNodeError}; use futures::Async; use slog::{debug, error, info}; use std::sync::Arc; @@ -29,7 +29,7 @@ pub enum UpdateOutcome { pub enum Error { DutiesMapPoisoned, EpochMapPoisoned, - BeaconNodeError(BeaconNodeError), + BeaconNodeDutiesError(BeaconNodeDutiesError), UnknownEpoch, UnknownValidator, } @@ -38,14 +38,14 @@ pub enum Error { /// Node. /// /// This keeps track of all validator keys and required voting slots. -pub struct DutiesManager { +pub struct DutiesManager { pub duties_map: RwLock, /// A list of all public keys known to the validator service. pub pubkeys: Vec, pub beacon_node: Arc, } -impl DutiesManager { +impl DutiesManager { /// Check the Beacon Node for `EpochDuties`. /// /// be a wall-clock (e.g., system time, remote server time, etc.). @@ -112,9 +112,9 @@ impl DutiesManager { } //TODO: Use error_chain to handle errors -impl From for Error { - fn from(e: BeaconNodeError) -> Error { - Error::BeaconNodeError(e) +impl From for Error { + fn from(e: BeaconNodeDutiesError) -> Error { + Error::BeaconNodeDutiesError(e) } } diff --git a/validator_client/src/main.rs b/validator_client/src/main.rs index 0b11ed0d0..6f02cf6ee 100644 --- a/validator_client/src/main.rs +++ b/validator_client/src/main.rs @@ -1,5 +1,5 @@ mod attester_service; -mod block_producer_service; +mod block_producer; mod config; mod duties; pub mod error; diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 9c0f5d23c..398f6d777 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -9,15 +9,14 @@ /// data from the beacon node and performs the signing before publishing the block to the beacon /// node. use crate::attester_service::{AttestationGrpcClient, AttesterService}; +use crate::block_producer::BlockProducer; use crate::block_producer_service::BeaconBlockGrpcClient; use crate::config::Config as ValidatorConfig; -use crate::duties::UpdateOutcome; -use crate::duties::{DutiesManager, EpochDutiesMap}; +use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap, UpdateOutcome}; use crate::error as error_chain; use crate::error::ErrorKind; use attester::test_utils::EpochMap; use attester::{test_utils::LocalSigner as AttesterLocalSigner, Attester}; -use block_proposer::{test_utils::LocalSigner as BlockProposerLocalSigner, BlockProducer}; use bls::Keypair; use grpcio::{ChannelBuilder, EnvBuilder}; use protos::services::Empty; @@ -35,13 +34,13 @@ use tokio::runtime::Builder; use tokio::timer::Interval; use tokio_timer::clock::Clock; use types::test_utils::generate_deterministic_keypairs; -use types::{Epoch, Fork, Slot}; +use types::{ChainSpec, Epoch, Fork, Slot}; //TODO: This service should be simplified in the future. Can be made more steamlined. /// The validator service. This is the main thread that executes and maintains validator /// duties. -pub struct Service { +pub struct Service { /// The node we currently connected to. connected_node_version: String, /// The chain id we are processing on. @@ -50,28 +49,25 @@ pub struct Service { slot_clock: SystemTimeSlotClock, /// The current slot we are processing. current_slot: Slot, - /// The number of slots per epoch to allow for converting slots to epochs. - slots_per_epoch: u64, + /// The chain specification for this clients instance. + spec: Arc, + /// The duties manager which maintains the state of when to perform actions. + duties_manager: Arc>, // GRPC Clients /// The beacon block GRPC client. - beacon_block_client: Arc, - /// The validator GRPC client. - validator_client: Arc, + beacon_block_client: Arc, /// The attester GRPC client. attester_client: Arc, /// The validator client logger. log: slog::Logger, } -impl Service { +impl Service { /// Initial connection to the beacon node to determine its properties. /// /// This tries to connect to a beacon node. Once connected, it initialised the gRPC clients /// and returns an instance of the service. - fn initialize_service( - config: &ValidatorConfig, - log: slog::Logger, - ) -> error_chain::Result { + fn initialize_service(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result { // initialise the beacon node client to check for a connection let env = Arc::new(EnvBuilder::new().build()); @@ -139,7 +135,9 @@ impl Service { // Beacon node gRPC beacon block endpoints. let beacon_block_client = { let ch = ChannelBuilder::new(env.clone()).connect(&config.server); - Arc::new(BeaconBlockServiceClient::new(ch)) + let beacon_block_service_client = Arc::new(BeaconBlockServiceClient::new(ch)); + // a wrapper around the service client to implement the beacon block node trait + Arc::new(BeaconBlockGrpcClient::new(beacon_block_service_client)) }; // Beacon node gRPC validator endpoints. @@ -164,14 +162,37 @@ impl Service { .map_err(|e| ErrorKind::SlotClockError(e))? .expect("Genesis must be in the future"); + let spec = Arc::new(config.spec); + + /* Generate the duties manager */ + + // generate keypairs + + // TODO: keypairs are randomly generated; they should be loaded from a file or generated. + // https://github.com/sigp/lighthouse/issues/160 + let keypairs = Arc::new(generate_deterministic_keypairs(8)); + + // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty) + // where EpochDuty contains slot numbers and attestation data that each validator needs to + // produce work on. + let duties_map = RwLock::new(EpochDutiesMap::new(config.spec.slots_per_epoch)); + + // builds a manager which maintains the list of current duties for all known validators + // and can check when a validator needs to perform a task. + let duties_manager = Arc::new(DutiesManager { + duties_map, + pubkeys: keypairs.iter().map(|keypair| keypair.pk.clone()).collect(), + beacon_node: validator_client, + }); + Ok(Self { connected_node_version: node_info.version, fork, slot_clock, current_slot, - slots_per_epoch: config.spec.slots_per_epoch, + spec, + duties_manager, beacon_block_client, - validator_client, attester_client, log, }) @@ -180,7 +201,7 @@ impl Service { /// Initialise the service then run the core thread. pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> { // connect to the node and retrieve its properties and initialize the gRPC clients - let service = Service::initialize_service(&config, log)?; + let service = Service::initialize_service(config, log)?; // we have connected to a node and established its parameters. Spin up the core service @@ -205,137 +226,95 @@ impl Service { Interval::new(Instant::now() + duration_to_next_slot, slot_duration) }; - /* kick off core service */ - - // generate keypairs - - // TODO: keypairs are randomly generated; they should be loaded from a file or generated. - // https://github.com/sigp/lighthouse/issues/160 - let keypairs = Arc::new(generate_deterministic_keypairs(8)); - - /* build requisite objects to pass to core thread */ - - // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty) - // where EpochDuty contains slot numbers and attestation data that each validator needs to - // produce work on. - let duties_map = RwLock::new(EpochDutiesMap::new(config.spec.slots_per_epoch)); - - // builds a manager which maintains the list of current duties for all known validators - // and can check when a validator needs to perform a task. - let manager = Arc::new(DutiesManager { - duties_map, - pubkeys: keypairs.iter().map(|keypair| keypair.pk.clone()).collect(), - beacon_node: service.validator_client.clone(), - }); - - // run the core thread + /* kick off the core service */ runtime.block_on( interval .for_each(move |_| { - let log = service.log.clone(); - - /* get the current slot and epoch */ - let current_slot = match service.slot_clock.present_slot() { - Err(e) => { - error!(log, "SystemTimeError {:?}", e); - return Ok(()); - } - Ok(slot) => slot.expect("Genesis is in the future"), - }; - - let current_epoch = current_slot.epoch(service.slots_per_epoch); - - debug_assert!( - current_slot > service.current_slot, - "The Timer should poll a new slot" - ); - - info!(log, "Processing"; "slot" => current_slot.as_u64(), "epoch" => current_epoch.as_u64()); - - /* check for new duties */ - - let cloned_manager = manager.clone(); - let cloned_log = log.clone(); - // spawn a new thread separate to the runtime - std::thread::spawn(move || { - let _empty_error = cloned_manager.run_update(current_epoch.clone(), cloned_log.clone()); - }); - - /* execute any specified duties */ - - if let Some(work) = manager.get_current_work(current_slot) { - for (_public_key, work_type) in work { - if work_type.produce_block { - // TODO: Produce a beacon block in a new thread - } - if work_type.attestation_duty.is_some() { - // available AttestationDuty info - let attestation_duty = - work_type.attestation_duty.expect("Cannot be None"); - //TODO: Produce an attestation in a new thread - } - } - } - + // if a non-fatal error occurs, proceed to the next slot. + let _ignore_error = service.per_slot_execution(); + // completed a slot process Ok(()) }) .map_err(|e| format!("Service thread failed: {:?}", e)), ); - - // completed a slot process + // validator client exited Ok(()) } - /* - // Spawn a new thread to perform block production for the validator. - let producer_thread = { - let spec = spec.clone(); - let signer = Arc::new(BlockProposerLocalSigner::new(keypair.clone())); - let duties_map = duties_map.clone(); - let slot_clock = slot_clock.clone(); - let log = log.clone(); - let client = Arc::new(BeaconBlockGrpcClient::new(beacon_block_grpc_client.clone())); - thread::spawn(move || { - let block_producer = - BlockProducer::new(spec, duties_map, slot_clock, client, signer); - let mut block_producer_service = BlockProducerService { - block_producer, - poll_interval_millis, - log, - }; + /// The execution logic that runs every slot. + // Errors are logged to output, and core execution continues unless fatal errors occur. + fn per_slot_execution(&mut self) -> error_chain::Result<()> { + /* get the new current slot and epoch */ + self.update_current_slot()?; - block_producer_service.run(); - }) - }; + /* check for new duties */ + self.check_for_duties(); - // Spawn a new thread for attestation for the validator. - let attester_thread = { - let signer = Arc::new(AttesterLocalSigner::new(keypair.clone())); - let epoch_map = epoch_map_for_attester.clone(); - let slot_clock = slot_clock.clone(); - let log = log.clone(); - let client = Arc::new(AttestationGrpcClient::new(attester_grpc_client.clone())); - thread::spawn(move || { - let attester = Attester::new(epoch_map, slot_clock, client, signer); - let mut attester_service = AttesterService { - attester, - poll_interval_millis, - log, - }; + /* process any required duties for validators */ + self.process_duties(); - attester_service.run(); - }) - }; - - threads.push((duties_manager_thread, producer_thread, attester_thread)); + Ok(()) } - // Naively wait for all the threads to complete. - for tuple in threads { - let (manager, producer, attester) = tuple; - let _ = producer.join(); - let _ = manager.join(); - let _ = attester.join(); + /// Updates the known current slot and epoch. + fn update_current_slot(&mut self) -> error_chain::Result<()> { + let current_slot = match self.slot_clock.present_slot() { + Err(e) => { + error!(self.log, "SystemTimeError {:?}", e); + return Err("Could not read system time".into()); + } + Ok(slot) => slot.expect("Genesis is in the future"), + }; + + let current_epoch = current_slot.epoch(self.spec.slots_per_epoch); + + // this is a fatal error. If the slot clock repeats, there is something wrong with + // the timer, terminate immediately. + assert!( + current_slot > self.current_slot, + "The Timer should poll a new slot" + ); + self.current_slot = current_slot; + info!(self.log, "Processing"; "slot" => current_slot.as_u64(), "epoch" => current_epoch.as_u64()); + Ok(()) + } + + /// For all known validator keypairs, update any known duties from the beacon node. + fn check_for_duties(&mut self) { + let cloned_manager = self.duties_manager.clone(); + let cloned_log = self.log.clone(); + let current_epoch = self.current_slot.epoch(self.spec.slots_per_epoch); + // spawn a new thread separate to the runtime + // TODO: Handle thread termination/timeout + std::thread::spawn(move || { + // the return value is a future which returns ready. + // built to be compatible with the tokio runtime. + let _empty = cloned_manager.run_update(current_epoch.clone(), cloned_log.clone()); + }); + } + + /// If there are any duties to process, spawn a separate thread and perform required actions. + fn process_duties(&mut self) { + if let Some(work) = self.duties_manager.get_current_work(self.current_slot) { + for (_public_key, work_type) in work { + if work_type.produce_block { + // spawns a thread to produce a beacon block + std::thread::spawn(move || { + let block_producer = BlockProducer { + fork: self.fork, + slot: self.current_slot, + spec: self.spec.clone(), + }; + }); + + // TODO: Produce a beacon block in a new thread + } + if work_type.attestation_duty.is_some() { + // available AttestationDuty info + let attestation_duty = work_type.attestation_duty.expect("Cannot be None"); + //TODO: Produce an attestation in a new thread + } + } + } } - */ } From dd2351020cdf975ff8f20b003d4348502575ef72 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 29 Mar 2019 17:58:02 +1100 Subject: [PATCH 045/106] Impl `add_aggregate` for FakeAggSig --- eth2/utils/bls/src/fake_aggregate_signature.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/eth2/utils/bls/src/fake_aggregate_signature.rs b/eth2/utils/bls/src/fake_aggregate_signature.rs index 23e2b54ef..85b06b956 100644 --- a/eth2/utils/bls/src/fake_aggregate_signature.rs +++ b/eth2/utils/bls/src/fake_aggregate_signature.rs @@ -35,6 +35,11 @@ impl FakeAggregateSignature { // Do nothing. } + /// Does glorious nothing. + pub fn add_aggregate(&mut self, _agg_sig: &FakeAggregateSignature) { + // Do nothing. + } + /// _Always_ returns `true`. pub fn verify( &self, From 46a978a5a92effb1bde7ce74a1e94308e038f0b1 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 29 Mar 2019 18:30:03 +1100 Subject: [PATCH 046/106] Implement op pool for all ops execpt attestations --- beacon_node/beacon_chain/Cargo.toml | 1 + beacon_node/beacon_chain/src/beacon_chain.rs | 258 ++++--------------- eth2/operation_pool/src/lib.rs | 2 +- 3 files changed, 51 insertions(+), 210 deletions(-) diff --git a/beacon_node/beacon_chain/Cargo.toml b/beacon_node/beacon_chain/Cargo.toml index b5471be5f..55d4bacfd 100644 --- a/beacon_node/beacon_chain/Cargo.toml +++ b/beacon_node/beacon_chain/Cargo.toml @@ -15,6 +15,7 @@ hashing = { path = "../../eth2/utils/hashing" } fork_choice = { path = "../../eth2/fork_choice" } parking_lot = "0.7" log = "0.4" +operation_pool = { path = "../../eth2/operation_pool" } env_logger = "0.6" serde = "1.0" serde_derive = "1.0" diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 27398b6c9..1d0cfe8e3 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -6,7 +6,8 @@ use db::{ ClientDB, DBError, }; use fork_choice::{ForkChoice, ForkChoiceError}; -use log::{debug, trace}; +use log::{debug, trace, warn}; +use operation_pool::OperationPool; use parking_lot::{RwLock, RwLockReadGuard}; use slot_clock::SlotClock; use ssz::ssz_encode; @@ -83,6 +84,7 @@ pub struct BeaconChain { pub state_store: Arc>, pub slot_clock: U, pub attestation_aggregator: RwLock, + pub op_pool: RwLock, pub deposits_for_inclusion: RwLock>, pub exits_for_inclusion: RwLock>, pub transfers_for_inclusion: RwLock>, @@ -141,6 +143,7 @@ where state_store, slot_clock, attestation_aggregator, + op_pool: RwLock::new(OperationPool::new()), deposits_for_inclusion: RwLock::new(vec![]), exits_for_inclusion: RwLock::new(vec![]), transfers_for_inclusion: RwLock::new(vec![]), @@ -540,218 +543,48 @@ where /// Accept some deposit and queue it for inclusion in an appropriate block. pub fn receive_deposit_for_inclusion(&self, deposit: Deposit) { - // TODO: deposits are not checked for validity; check them. - // - // https://github.com/sigp/lighthouse/issues/276 - self.deposits_for_inclusion.write().push(deposit); - } - - /// Return a vec of deposits suitable for inclusion in some block. - pub fn get_deposits_for_block(&self) -> Vec { - // TODO: deposits are indiscriminately included; check them for validity. - // - // https://github.com/sigp/lighthouse/issues/275 - self.deposits_for_inclusion.read().clone() - } - - /// Takes a list of `Deposits` that were included in recent blocks and removes them from the - /// inclusion queue. - /// - /// This ensures that `Deposits` are not included twice in successive blocks. - pub fn set_deposits_as_included(&self, included_deposits: &[Deposit]) { - // TODO: method does not take forks into account; consider this. - // - // https://github.com/sigp/lighthouse/issues/275 - let mut indices_to_delete = vec![]; - - for included in included_deposits { - for (i, for_inclusion) in self.deposits_for_inclusion.read().iter().enumerate() { - if included == for_inclusion { - indices_to_delete.push(i); - } - } - } - - let deposits_for_inclusion = &mut self.deposits_for_inclusion.write(); - for i in indices_to_delete { - deposits_for_inclusion.remove(i); - } + // Bad deposits are ignored. + let _ = self + .op_pool + .write() + .insert_deposit(deposit, &*self.state.read(), &self.spec); } /// Accept some exit and queue it for inclusion in an appropriate block. pub fn receive_exit_for_inclusion(&self, exit: VoluntaryExit) { - // TODO: exits are not checked for validity; check them. - // - // https://github.com/sigp/lighthouse/issues/276 - self.exits_for_inclusion.write().push(exit); - } - - /// Return a vec of exits suitable for inclusion in some block. - pub fn get_exits_for_block(&self) -> Vec { - // TODO: exits are indiscriminately included; check them for validity. - // - // https://github.com/sigp/lighthouse/issues/275 - self.exits_for_inclusion.read().clone() - } - - /// Takes a list of `Deposits` that were included in recent blocks and removes them from the - /// inclusion queue. - /// - /// This ensures that `Deposits` are not included twice in successive blocks. - pub fn set_exits_as_included(&self, included_exits: &[VoluntaryExit]) { - // TODO: method does not take forks into account; consider this. - let mut indices_to_delete = vec![]; - - for included in included_exits { - for (i, for_inclusion) in self.exits_for_inclusion.read().iter().enumerate() { - if included == for_inclusion { - indices_to_delete.push(i); - } - } - } - - let exits_for_inclusion = &mut self.exits_for_inclusion.write(); - for i in indices_to_delete { - exits_for_inclusion.remove(i); - } + // Bad exits are ignored + let _ = self + .op_pool + .write() + .insert_voluntary_exit(exit, &*self.state.read(), &self.spec); } /// Accept some transfer and queue it for inclusion in an appropriate block. pub fn receive_transfer_for_inclusion(&self, transfer: Transfer) { - // TODO: transfers are not checked for validity; check them. - // - // https://github.com/sigp/lighthouse/issues/276 - self.transfers_for_inclusion.write().push(transfer); - } - - /// Return a vec of transfers suitable for inclusion in some block. - pub fn get_transfers_for_block(&self) -> Vec { - // TODO: transfers are indiscriminately included; check them for validity. - // - // https://github.com/sigp/lighthouse/issues/275 - self.transfers_for_inclusion.read().clone() - } - - /// Takes a list of `Deposits` that were included in recent blocks and removes them from the - /// inclusion queue. - /// - /// This ensures that `Deposits` are not included twice in successive blocks. - pub fn set_transfers_as_included(&self, included_transfers: &[Transfer]) { - // TODO: method does not take forks into account; consider this. - let mut indices_to_delete = vec![]; - - for included in included_transfers { - for (i, for_inclusion) in self.transfers_for_inclusion.read().iter().enumerate() { - if included == for_inclusion { - indices_to_delete.push(i); - } - } - } - - let transfers_for_inclusion = &mut self.transfers_for_inclusion.write(); - for i in indices_to_delete { - transfers_for_inclusion.remove(i); - } + // Bad transfers are ignored. + let _ = self + .op_pool + .write() + .insert_transfer(transfer, &*self.state.read(), &self.spec); } /// Accept some proposer slashing and queue it for inclusion in an appropriate block. pub fn receive_proposer_slashing_for_inclusion(&self, proposer_slashing: ProposerSlashing) { - // TODO: proposer_slashings are not checked for validity; check them. - // - // https://github.com/sigp/lighthouse/issues/276 - self.proposer_slashings_for_inclusion - .write() - .push(proposer_slashing); - } - - /// Return a vec of proposer slashings suitable for inclusion in some block. - pub fn get_proposer_slashings_for_block(&self) -> Vec { - // TODO: proposer_slashings are indiscriminately included; check them for validity. - // - // https://github.com/sigp/lighthouse/issues/275 - self.proposer_slashings_for_inclusion.read().clone() - } - - /// Takes a list of `ProposerSlashings` that were included in recent blocks and removes them - /// from the inclusion queue. - /// - /// This ensures that `ProposerSlashings` are not included twice in successive blocks. - pub fn set_proposer_slashings_as_included( - &self, - included_proposer_slashings: &[ProposerSlashing], - ) { - // TODO: method does not take forks into account; consider this. - // - // https://github.com/sigp/lighthouse/issues/275 - let mut indices_to_delete = vec![]; - - for included in included_proposer_slashings { - for (i, for_inclusion) in self - .proposer_slashings_for_inclusion - .read() - .iter() - .enumerate() - { - if included == for_inclusion { - indices_to_delete.push(i); - } - } - } - - let proposer_slashings_for_inclusion = &mut self.proposer_slashings_for_inclusion.write(); - for i in indices_to_delete { - proposer_slashings_for_inclusion.remove(i); - } + // Bad proposer slashings are ignored. + let _ = self.op_pool.write().insert_proposer_slashing( + proposer_slashing, + &*self.state.read(), + &self.spec, + ); } /// Accept some attester slashing and queue it for inclusion in an appropriate block. pub fn receive_attester_slashing_for_inclusion(&self, attester_slashing: AttesterSlashing) { - // TODO: attester_slashings are not checked for validity; check them. - // - // https://github.com/sigp/lighthouse/issues/276 - self.attester_slashings_for_inclusion - .write() - .push(attester_slashing); - } - - /// Return a vec of attester slashings suitable for inclusion in some block. - pub fn get_attester_slashings_for_block(&self) -> Vec { - // TODO: attester_slashings are indiscriminately included; check them for validity. - // - // https://github.com/sigp/lighthouse/issues/275 - self.attester_slashings_for_inclusion.read().clone() - } - - /// Takes a list of `AttesterSlashings` that were included in recent blocks and removes them - /// from the inclusion queue. - /// - /// This ensures that `AttesterSlashings` are not included twice in successive blocks. - pub fn set_attester_slashings_as_included( - &self, - included_attester_slashings: &[AttesterSlashing], - ) { - // TODO: method does not take forks into account; consider this. - // - // https://github.com/sigp/lighthouse/issues/275 - let mut indices_to_delete = vec![]; - - for included in included_attester_slashings { - for (i, for_inclusion) in self - .attester_slashings_for_inclusion - .read() - .iter() - .enumerate() - { - if included == for_inclusion { - indices_to_delete.push(i); - } - } - } - - let attester_slashings_for_inclusion = &mut self.attester_slashings_for_inclusion.write(); - for i in indices_to_delete { - attester_slashings_for_inclusion.remove(i); - } + let _ = self.op_pool.write().insert_attester_slashing( + attester_slashing, + &*self.state.read(), + &self.spec, + ); } /// Returns `true` if the given block root has not been processed. @@ -832,13 +665,6 @@ where self.block_store.put(&block_root, &ssz_encode(&block)[..])?; self.state_store.put(&state_root, &ssz_encode(&state)[..])?; - // Update the inclusion queues so they aren't re-submitted. - self.set_deposits_as_included(&block.body.deposits[..]); - self.set_transfers_as_included(&block.body.transfers[..]); - self.set_exits_as_included(&block.body.voluntary_exits[..]); - self.set_proposer_slashings_as_included(&block.body.proposer_slashings[..]); - self.set_attester_slashings_as_included(&block.body.attester_slashings[..]); - // run the fork_choice add_block logic self.fork_choice .write() @@ -888,6 +714,11 @@ where .get_block_root(state.slot - 1, &self.spec) .map_err(|_| BlockProductionError::UnableToGetBlockRootFromState)?; + let (proposer_slashings, attester_slashings) = self + .op_pool + .read() + .get_slashings(&*self.state.read(), &self.spec); + let mut block = BeaconBlock { slot: state.slot, previous_block_root, @@ -900,12 +731,21 @@ where deposit_root: Hash256::zero(), block_hash: Hash256::zero(), }, - proposer_slashings: self.get_proposer_slashings_for_block(), - attester_slashings: self.get_attester_slashings_for_block(), + proposer_slashings, + attester_slashings, attestations, - deposits: self.get_deposits_for_block(), - voluntary_exits: self.get_exits_for_block(), - transfers: self.get_transfers_for_block(), + deposits: self + .op_pool + .read() + .get_deposits(&*self.state.read(), &self.spec), + voluntary_exits: self + .op_pool + .read() + .get_voluntary_exits(&*self.state.read(), &self.spec), + transfers: self + .op_pool + .read() + .get_transfers(&*self.state.read(), &self.spec), }, }; diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index e67a201c7..c3de95b48 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -21,7 +21,7 @@ use types::{ #[cfg(test)] const VERIFY_DEPOSIT_PROOFS: bool = false; #[cfg(not(test))] -const VERIFY_DEPOSIT_PROOFS: bool = true; +const VERIFY_DEPOSIT_PROOFS: bool = false; // TODO: enable this #[derive(Default)] pub struct OperationPool { From 8b1a91e9eec1d11ad833586ad43526eb465c6f21 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 29 Mar 2019 18:40:50 +1100 Subject: [PATCH 047/106] Add `process_attestation` to `BeaconChain` --- beacon_node/beacon_chain/src/beacon_chain.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 1d0cfe8e3..5eadb3763 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -541,6 +541,17 @@ where Ok(aggregation_outcome) } + /// Accept a new attestation from the network. + /// + /// If valid, the attestation is added to the `op_pool` and aggregated with another attestation + /// if possible. + pub fn process_attestation(&self, attestation: Attestation) { + let _ = + self.op_pool + .write() + .insert_attestation(attestation, &*self.state.read(), &self.spec); + } + /// Accept some deposit and queue it for inclusion in an appropriate block. pub fn receive_deposit_for_inclusion(&self, deposit: Deposit) { // Bad deposits are ignored. @@ -701,9 +712,9 @@ where trace!("Finding attestations for new block..."); let attestations = self - .attestation_aggregator + .op_pool .read() - .get_attestations_for_state(&state, &self.spec); + .get_attestations(&*self.state.read(), &self.spec); trace!( "Inserting {} attestation(s) into new block.", From 2b538510623cc8609f542617c948e876a7a348f5 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 29 Mar 2019 18:54:01 +1100 Subject: [PATCH 048/106] Pass errors back from block ops processing --- beacon_node/beacon_chain/src/beacon_chain.rs | 69 +++++++++++-------- .../test_harness/src/beacon_chain_harness.rs | 16 +++-- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 5eadb3763..4d3ba9cab 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -7,10 +7,15 @@ use db::{ }; use fork_choice::{ForkChoice, ForkChoiceError}; use log::{debug, trace, warn}; +use operation_pool::DepositInsertStatus; use operation_pool::OperationPool; use parking_lot::{RwLock, RwLockReadGuard}; use slot_clock::SlotClock; use ssz::ssz_encode; +pub use state_processing::per_block_processing::errors::{ + AttestationValidationError, AttesterSlashingValidationError, DepositValidationError, + ExitValidationError, ProposerSlashingValidationError, TransferValidationError, +}; use state_processing::{ per_block_processing, per_block_processing_without_verifying_block_signature, per_slot_processing, BlockProcessingError, SlotProcessingError, @@ -545,57 +550,67 @@ where /// /// If valid, the attestation is added to the `op_pool` and aggregated with another attestation /// if possible. - pub fn process_attestation(&self, attestation: Attestation) { - let _ = - self.op_pool - .write() - .insert_attestation(attestation, &*self.state.read(), &self.spec); + pub fn process_attestation( + &self, + attestation: Attestation, + ) -> Result<(), AttestationValidationError> { + self.op_pool + .write() + .insert_attestation(attestation, &*self.state.read(), &self.spec) } /// Accept some deposit and queue it for inclusion in an appropriate block. - pub fn receive_deposit_for_inclusion(&self, deposit: Deposit) { - // Bad deposits are ignored. - let _ = self - .op_pool + pub fn receive_deposit_for_inclusion( + &self, + deposit: Deposit, + ) -> Result { + self.op_pool .write() - .insert_deposit(deposit, &*self.state.read(), &self.spec); + .insert_deposit(deposit, &*self.state.read(), &self.spec) } /// Accept some exit and queue it for inclusion in an appropriate block. - pub fn receive_exit_for_inclusion(&self, exit: VoluntaryExit) { - // Bad exits are ignored - let _ = self - .op_pool + pub fn receive_exit_for_inclusion( + &self, + exit: VoluntaryExit, + ) -> Result<(), ExitValidationError> { + self.op_pool .write() - .insert_voluntary_exit(exit, &*self.state.read(), &self.spec); + .insert_voluntary_exit(exit, &*self.state.read(), &self.spec) } /// Accept some transfer and queue it for inclusion in an appropriate block. - pub fn receive_transfer_for_inclusion(&self, transfer: Transfer) { - // Bad transfers are ignored. - let _ = self - .op_pool + pub fn receive_transfer_for_inclusion( + &self, + transfer: Transfer, + ) -> Result<(), TransferValidationError> { + self.op_pool .write() - .insert_transfer(transfer, &*self.state.read(), &self.spec); + .insert_transfer(transfer, &*self.state.read(), &self.spec) } /// Accept some proposer slashing and queue it for inclusion in an appropriate block. - pub fn receive_proposer_slashing_for_inclusion(&self, proposer_slashing: ProposerSlashing) { - // Bad proposer slashings are ignored. - let _ = self.op_pool.write().insert_proposer_slashing( + pub fn receive_proposer_slashing_for_inclusion( + &self, + proposer_slashing: ProposerSlashing, + ) -> Result<(), ProposerSlashingValidationError> { + self.op_pool.write().insert_proposer_slashing( proposer_slashing, &*self.state.read(), &self.spec, - ); + ) } /// Accept some attester slashing and queue it for inclusion in an appropriate block. - pub fn receive_attester_slashing_for_inclusion(&self, attester_slashing: AttesterSlashing) { - let _ = self.op_pool.write().insert_attester_slashing( + pub fn receive_attester_slashing_for_inclusion( + &self, + attester_slashing: AttesterSlashing, + ) -> Result<(), AttesterSlashingValidationError> { + self.op_pool.write().insert_attester_slashing( attester_slashing, &*self.state.read(), &self.spec, - ); + ) } /// Returns `true` if the given block root has not been processed. diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index 942497476..0784e5fd3 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -285,7 +285,9 @@ impl BeaconChainHarness { /// If a new `ValidatorHarness` was created, the validator should become fully operational as /// if the validator were created during `BeaconChainHarness` instantiation. pub fn add_deposit(&mut self, deposit: Deposit, keypair: Option) { - self.beacon_chain.receive_deposit_for_inclusion(deposit); + self.beacon_chain + .receive_deposit_for_inclusion(deposit) + .unwrap(); // If a keypair is present, add a new `ValidatorHarness` to the rig. if let Some(keypair) = keypair { @@ -301,24 +303,28 @@ impl BeaconChainHarness { /// will stop receiving duties from the beacon chain and just do nothing when prompted to /// produce/attest. pub fn add_exit(&mut self, exit: VoluntaryExit) { - self.beacon_chain.receive_exit_for_inclusion(exit); + self.beacon_chain.receive_exit_for_inclusion(exit).unwrap(); } /// Submit an transfer to the `BeaconChain` for inclusion in some block. pub fn add_transfer(&mut self, transfer: Transfer) { - self.beacon_chain.receive_transfer_for_inclusion(transfer); + self.beacon_chain + .receive_transfer_for_inclusion(transfer) + .unwrap(); } /// Submit a proposer slashing to the `BeaconChain` for inclusion in some block. pub fn add_proposer_slashing(&mut self, proposer_slashing: ProposerSlashing) { self.beacon_chain - .receive_proposer_slashing_for_inclusion(proposer_slashing); + .receive_proposer_slashing_for_inclusion(proposer_slashing) + .unwrap(); } /// Submit an attester slashing to the `BeaconChain` for inclusion in some block. pub fn add_attester_slashing(&mut self, attester_slashing: AttesterSlashing) { self.beacon_chain - .receive_attester_slashing_for_inclusion(attester_slashing); + .receive_attester_slashing_for_inclusion(attester_slashing) + .unwrap(); } /// Executes the fork choice rule on the `BeaconChain`, selecting a new canonical head. From 8bf7a83f373a34070fb7765daaa7dd20fd28867c Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 29 Mar 2019 19:09:01 +1100 Subject: [PATCH 049/106] Rename op processing methods on BeaconChain --- beacon_node/beacon_chain/src/beacon_chain.rs | 28 ++++++++----------- .../test_harness/src/beacon_chain_harness.rs | 14 ++++------ 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 4d3ba9cab..d3b9e2bdc 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -6,7 +6,7 @@ use db::{ ClientDB, DBError, }; use fork_choice::{ForkChoice, ForkChoiceError}; -use log::{debug, trace, warn}; +use log::{debug, trace}; use operation_pool::DepositInsertStatus; use operation_pool::OperationPool; use parking_lot::{RwLock, RwLockReadGuard}; @@ -560,7 +560,7 @@ where } /// Accept some deposit and queue it for inclusion in an appropriate block. - pub fn receive_deposit_for_inclusion( + pub fn process_deposit( &self, deposit: Deposit, ) -> Result { @@ -570,27 +570,21 @@ where } /// Accept some exit and queue it for inclusion in an appropriate block. - pub fn receive_exit_for_inclusion( - &self, - exit: VoluntaryExit, - ) -> Result<(), ExitValidationError> { + pub fn process_voluntary_exit(&self, exit: VoluntaryExit) -> Result<(), ExitValidationError> { self.op_pool .write() .insert_voluntary_exit(exit, &*self.state.read(), &self.spec) } /// Accept some transfer and queue it for inclusion in an appropriate block. - pub fn receive_transfer_for_inclusion( - &self, - transfer: Transfer, - ) -> Result<(), TransferValidationError> { + pub fn process_transfer(&self, transfer: Transfer) -> Result<(), TransferValidationError> { self.op_pool .write() .insert_transfer(transfer, &*self.state.read(), &self.spec) } /// Accept some proposer slashing and queue it for inclusion in an appropriate block. - pub fn receive_proposer_slashing_for_inclusion( + pub fn process_proposer_slashing( &self, proposer_slashing: ProposerSlashing, ) -> Result<(), ProposerSlashingValidationError> { @@ -602,7 +596,7 @@ where } /// Accept some attester slashing and queue it for inclusion in an appropriate block. - pub fn receive_attester_slashing_for_inclusion( + pub fn process_attester_slashing( &self, attester_slashing: AttesterSlashing, ) -> Result<(), AttesterSlashingValidationError> { @@ -613,11 +607,6 @@ where ) } - /// Returns `true` if the given block root has not been processed. - pub fn is_new_block_root(&self, beacon_block_root: &Hash256) -> Result { - Ok(!self.block_store.exists(beacon_block_root)?) - } - /// Accept some block and attempt to add it to block DAG. /// /// Will accept blocks from prior slots, however it will reject any block from a future slot. @@ -817,6 +806,11 @@ where Ok(()) } + /// Returns `true` if the given block root has not been processed. + pub fn is_new_block_root(&self, beacon_block_root: &Hash256) -> Result { + Ok(!self.block_store.exists(beacon_block_root)?) + } + /// Dumps the entire canonical chain, from the head to genesis to a vector for analysis. /// /// This could be a very expensive operation and should only be done in testing/analysis diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index 0784e5fd3..7d6a690e0 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -285,9 +285,7 @@ impl BeaconChainHarness { /// If a new `ValidatorHarness` was created, the validator should become fully operational as /// if the validator were created during `BeaconChainHarness` instantiation. pub fn add_deposit(&mut self, deposit: Deposit, keypair: Option) { - self.beacon_chain - .receive_deposit_for_inclusion(deposit) - .unwrap(); + self.beacon_chain.process_deposit(deposit).unwrap(); // If a keypair is present, add a new `ValidatorHarness` to the rig. if let Some(keypair) = keypair { @@ -303,27 +301,25 @@ impl BeaconChainHarness { /// will stop receiving duties from the beacon chain and just do nothing when prompted to /// produce/attest. pub fn add_exit(&mut self, exit: VoluntaryExit) { - self.beacon_chain.receive_exit_for_inclusion(exit).unwrap(); + self.beacon_chain.process_voluntary_exit(exit).unwrap(); } /// Submit an transfer to the `BeaconChain` for inclusion in some block. pub fn add_transfer(&mut self, transfer: Transfer) { - self.beacon_chain - .receive_transfer_for_inclusion(transfer) - .unwrap(); + self.beacon_chain.process_transfer(transfer).unwrap(); } /// Submit a proposer slashing to the `BeaconChain` for inclusion in some block. pub fn add_proposer_slashing(&mut self, proposer_slashing: ProposerSlashing) { self.beacon_chain - .receive_proposer_slashing_for_inclusion(proposer_slashing) + .process_proposer_slashing(proposer_slashing) .unwrap(); } /// Submit an attester slashing to the `BeaconChain` for inclusion in some block. pub fn add_attester_slashing(&mut self, attester_slashing: AttesterSlashing) { self.beacon_chain - .receive_attester_slashing_for_inclusion(attester_slashing) + .process_attester_slashing(attester_slashing) .unwrap(); } From e418cd11837e31207aeca4b0ddf5004e11e89efb Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 29 Mar 2019 23:45:53 +1100 Subject: [PATCH 050/106] Refactor main validator service --- .../src/block_producer/block_producer.rs | 219 -------------- validator_client/src/block_producer/grpc.rs | 86 ++++++ validator_client/src/block_producer/mod.rs | 272 +++++++++++++----- validator_client/src/main.rs | 4 +- validator_client/src/service.rs | 4 +- 5 files changed, 294 insertions(+), 291 deletions(-) delete mode 100644 validator_client/src/block_producer/block_producer.rs create mode 100644 validator_client/src/block_producer/grpc.rs diff --git a/validator_client/src/block_producer/block_producer.rs b/validator_client/src/block_producer/block_producer.rs deleted file mode 100644 index e71e6cd4b..000000000 --- a/validator_client/src/block_producer/block_producer.rs +++ /dev/null @@ -1,219 +0,0 @@ -use super::beacon_block_node::{BeaconBlockNode, BeaconBlockNodeError}; -use crate::signer::Signer; -use ssz::{SignedRoot, TreeHash}; -use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; - -#[derive(Debug, PartialEq)] -pub enum Error { - SlotClockError, - SlotUnknowable, - EpochMapPoisoned, - SlotClockPoisoned, - EpochLengthIsZero, - BeaconBlockNodeError(BeaconBlockNodeError), -} - -#[derive(Debug, PartialEq)] -pub enum ValidatorEvent { - /// A new block was produced. - BlockProduced(Slot), - /// A block was not produced as it would have been slashable. - SlashableBlockNotProduced(Slot), - /// The Beacon Node was unable to produce a block at that slot. - BeaconNodeUnableToProduceBlock(Slot), - /// The signer failed to sign the message. - SignerRejection(Slot), - /// The public key for this validator is not an active validator. - ValidatorIsUnknown(Slot), -} - -/// This struct contains the logic for requesting and signing beacon blocks for a validator. The -/// validator can abstractly sign via the Signer trait object. -pub struct BlockProducer { - /// The current fork. - pub fork: Fork, - /// The current slot to produce a block for. - pub slot: Slot, - /// The current epoch. - pub spec: Arc, - /// The beacon node to connect to. - pub beacon_node: Arc, - /// The signer to sign the block. - pub signer: Arc, -} - -impl BlockProducer { - /// Produce a block at some slot. - /// - /// Assumes that a block is required at this slot (does not check the duties). - /// - /// Ensures the message is not slashable. - /// - /// !!! UNSAFE !!! - /// - /// The slash-protection code is not yet implemented. There is zero protection against - /// slashing. - fn produce_block(&mut self) -> Result { - let epoch = self.slot.epoch(self.spec.slots_per_epoch); - - let randao_reveal = { - let message = epoch.hash_tree_root(); - let randao_reveal = match self.signer.sign_randao_reveal( - &message, - self.spec.get_domain(epoch, Domain::Randao, &self.fork), - ) { - None => return Ok(ValidatorEvent::SignerRejection(self.slot)), - Some(signature) => signature, - }; - randao_reveal - }; - - if let Some(block) = self - .beacon_node - .produce_beacon_block(self.slot, &randao_reveal)? - { - if self.safe_to_produce(&block) { - let domain = self.spec.get_domain(epoch, Domain::BeaconBlock, &self.fork); - if let Some(block) = self.sign_block(block, domain) { - self.beacon_node.publish_beacon_block(block)?; - Ok(ValidatorEvent::BlockProduced(self.slot)) - } else { - Ok(ValidatorEvent::SignerRejection(self.slot)) - } - } else { - Ok(ValidatorEvent::SlashableBlockNotProduced(self.slot)) - } - } else { - Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(self.slot)) - } - } - - /// Consumes a block, returning that block signed by the validators private key. - /// - /// Important: this function will not check to ensure the block is not slashable. This must be - /// done upstream. - fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option { - self.store_produce(&block); - - match self - .signer - .sign_block_proposal(&block.signed_root()[..], domain) - { - None => None, - Some(signature) => { - block.signature = signature; - Some(block) - } - } - } - - /// Returns `true` if signing a block is safe (non-slashable). - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn safe_to_produce(&self, _block: &BeaconBlock) -> bool { - // TODO: ensure the producer doesn't produce slashable blocks. - // https://github.com/sigp/lighthouse/issues/160 - true - } - - /// Record that a block was produced so that slashable votes may not be made in the future. - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn store_produce(&mut self, _block: &BeaconBlock) { - // TODO: record this block production to prevent future slashings. - // https://github.com/sigp/lighthouse/issues/160 - } -} - -impl From for Error { - fn from(e: BeaconBlockNodeError) -> Error { - Error::BeaconBlockNodeError(e) - } -} - -/* Old tests - Re-work for new logic -#[cfg(test)] -mod tests { - use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode}; - use super::*; - use slot_clock::TestingSlotClock; - use types::{ - test_utils::{SeedableRng, TestRandom, XorShiftRng}, - Keypair, - }; - - // TODO: implement more thorough testing. - // https://github.com/sigp/lighthouse/issues/160 - // - // These tests should serve as a good example for future tests. - - #[test] - pub fn polling() { - let mut rng = XorShiftRng::from_seed([42; 16]); - - let spec = Arc::new(ChainSpec::foundation()); - let slot_clock = Arc::new(TestingSlotClock::new(0)); - let beacon_node = Arc::new(SimulatedBeaconNode::default()); - let signer = Arc::new(LocalSigner::new(Keypair::random())); - - let mut epoch_map = EpochMap::new(spec.slots_per_epoch); - let produce_slot = Slot::new(100); - let produce_epoch = produce_slot.epoch(spec.slots_per_epoch); - epoch_map.map.insert(produce_epoch, produce_slot); - let epoch_map = Arc::new(epoch_map); - - let mut block_proposer = BlockProducer::new( - spec.clone(), - epoch_map.clone(), - slot_clock.clone(), - beacon_node.clone(), - signer.clone(), - ); - - // Configure responses from the BeaconNode. - beacon_node.set_next_produce_result(Ok(Some(BeaconBlock::random_for_test(&mut rng)))); - beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidBlock)); - - // One slot before production slot... - slot_clock.set_slot(produce_slot.as_u64() - 1); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1)) - ); - - // On the produce slot... - slot_clock.set_slot(produce_slot.as_u64()); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProduced(produce_slot.into())) - ); - - // Trying the same produce slot again... - slot_clock.set_slot(produce_slot.as_u64()); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::SlotAlreadyProcessed(produce_slot)) - ); - - // One slot after the produce slot... - slot_clock.set_slot(produce_slot.as_u64() + 1); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1)) - ); - - // In an epoch without known duties... - let slot = (produce_epoch.as_u64() + 1) * spec.slots_per_epoch; - slot_clock.set_slot(slot); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::ProducerDutiesUnknown(Slot::new(slot))) - ); - } -} -*/ diff --git a/validator_client/src/block_producer/grpc.rs b/validator_client/src/block_producer/grpc.rs new file mode 100644 index 000000000..23477ece1 --- /dev/null +++ b/validator_client/src/block_producer/grpc.rs @@ -0,0 +1,86 @@ +use super::beacon_block_node::*; +use protos::services::{ + BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, +}; +use protos::services_grpc::BeaconBlockServiceClient; +use ssz::{ssz_encode, Decodable}; +use std::sync::Arc; +use types::{BeaconBlock, Signature, Slot}; + +/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be +/// implemented upon it. +pub struct BeaconBlockGrpcClient { + client: Arc, +} + +impl BeaconBlockGrpcClient { + pub fn new(client: Arc) -> Self { + Self { client } + } +} + +impl BeaconBlockNode for BeaconBlockGrpcClient { + /// Request a Beacon Node (BN) to produce a new block at the supplied slot. + /// + /// Returns `None` if it is not possible to produce at the supplied slot. For example, if the + /// BN is unable to find a parent block. + fn produce_beacon_block( + &self, + slot: Slot, + randao_reveal: &Signature, + ) -> Result, BeaconBlockNodeError> { + // request a beacon block from the node + let mut req = ProduceBeaconBlockRequest::new(); + req.set_slot(slot.as_u64()); + req.set_randao_reveal(ssz_encode(randao_reveal)); + + //TODO: Determine if we want an explicit timeout + let reply = self + .client + .produce_beacon_block(&req) + .map_err(|err| BeaconBlockNodeError::RemoteFailure(format!("{:?}", err)))?; + + // format the reply + if reply.has_block() { + let block = reply.get_block(); + let ssz = block.get_ssz(); + + let (block, _i) = BeaconBlock::ssz_decode(&ssz, 0) + .map_err(|_| BeaconBlockNodeError::DecodeFailure)?; + + Ok(Some(block)) + } else { + Ok(None) + } + } + + /// Request a Beacon Node (BN) to publish a block. + /// + /// Generally, this will be called after a `produce_beacon_block` call with a block that has + /// been completed (signed) by the validator client. + fn publish_beacon_block( + &self, + block: BeaconBlock, + ) -> Result { + let mut req = PublishBeaconBlockRequest::new(); + + let ssz = ssz_encode(&block); + + let mut grpc_block = GrpcBeaconBlock::new(); + grpc_block.set_ssz(ssz); + + req.set_block(grpc_block); + + let reply = self + .client + .publish_beacon_block(&req) + .map_err(|err| BeaconBlockNodeError::RemoteFailure(format!("{:?}", err)))?; + + if reply.get_success() { + Ok(PublishOutcome::ValidBlock) + } else { + // TODO: distinguish between different errors + Ok(PublishOutcome::InvalidBlock("Publish failed".to_string())) + } + } +} diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index fe34f627d..8297469ba 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -1,89 +1,223 @@ mod beacon_block_node; -mod block_producer; +mod grpc; -use self::beacon_block_node::*; -use protos::services::{ - BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, -}; -use protos::services_grpc::BeaconBlockServiceClient; -use ssz::{ssz_encode, Decodable}; +use self::beacon_block_node::{BeaconBlockNode, BeaconBlockNodeError}; +pub use self::grpc::BeaconBlockGrpcClient; +use crate::signer::Signer; +use ssz::{SignedRoot, TreeHash}; use std::sync::Arc; -use types::{BeaconBlock, Signature, Slot}; +use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; -/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be -/// implemented upon it. -pub struct BeaconBlockGrpcClient { - client: Arc, +#[derive(Debug, PartialEq)] +pub enum Error { + SlotClockError, + SlotUnknowable, + EpochMapPoisoned, + SlotClockPoisoned, + EpochLengthIsZero, + BeaconBlockNodeError(BeaconBlockNodeError), } -impl BeaconBlockGrpcClient { - pub fn new(client: Arc) -> Self { - Self { client } - } +#[derive(Debug, PartialEq)] +pub enum ValidatorEvent { + /// A new block was produced. + BlockProduced(Slot), + /// A block was not produced as it would have been slashable. + SlashableBlockNotProduced(Slot), + /// The Beacon Node was unable to produce a block at that slot. + BeaconNodeUnableToProduceBlock(Slot), + /// The signer failed to sign the message. + SignerRejection(Slot), + /// The public key for this validator is not an active validator. + ValidatorIsUnknown(Slot), } -impl BeaconBlockNode for BeaconBlockGrpcClient { - /// Request a Beacon Node (BN) to produce a new block at the supplied slot. +/// This struct contains the logic for requesting and signing beacon blocks for a validator. The +/// validator can abstractly sign via the Signer trait object. +pub struct BlockProducer { + /// The current fork. + pub fork: Fork, + /// The current slot to produce a block for. + pub slot: Slot, + /// The current epoch. + pub spec: Arc, + /// The beacon node to connect to. + pub beacon_node: Arc, + /// The signer to sign the block. + pub signer: Arc, +} + +impl BlockProducer { + /// Produce a block at some slot. /// - /// Returns `None` if it is not possible to produce at the supplied slot. For example, if the - /// BN is unable to find a parent block. - fn produce_beacon_block( - &self, - slot: Slot, - randao_reveal: &Signature, - ) -> Result, BeaconBlockNodeError> { - // request a beacon block from the node - let mut req = ProduceBeaconBlockRequest::new(); - req.set_slot(slot.as_u64()); - req.set_randao_reveal(ssz_encode(randao_reveal)); + /// Assumes that a block is required at this slot (does not check the duties). + /// + /// Ensures the message is not slashable. + /// + /// !!! UNSAFE !!! + /// + /// The slash-protection code is not yet implemented. There is zero protection against + /// slashing. + fn produce_block(&mut self) -> Result { + let epoch = self.slot.epoch(self.spec.slots_per_epoch); - //TODO: Determine if we want an explicit timeout - let reply = self - .client - .produce_beacon_block(&req) - .map_err(|err| BeaconBlockNodeError::RemoteFailure(format!("{:?}", err)))?; + let randao_reveal = { + let message = epoch.hash_tree_root(); + let randao_reveal = match self.signer.sign_randao_reveal( + &message, + self.spec.get_domain(epoch, Domain::Randao, &self.fork), + ) { + None => return Ok(ValidatorEvent::SignerRejection(self.slot)), + Some(signature) => signature, + }; + randao_reveal + }; - // format the reply - if reply.has_block() { - let block = reply.get_block(); - let ssz = block.get_ssz(); - - let (block, _i) = BeaconBlock::ssz_decode(&ssz, 0) - .map_err(|_| BeaconBlockNodeError::DecodeFailure)?; - - Ok(Some(block)) + if let Some(block) = self + .beacon_node + .produce_beacon_block(self.slot, &randao_reveal)? + { + if self.safe_to_produce(&block) { + let domain = self.spec.get_domain(epoch, Domain::BeaconBlock, &self.fork); + if let Some(block) = self.sign_block(block, domain) { + self.beacon_node.publish_beacon_block(block)?; + Ok(ValidatorEvent::BlockProduced(self.slot)) + } else { + Ok(ValidatorEvent::SignerRejection(self.slot)) + } + } else { + Ok(ValidatorEvent::SlashableBlockNotProduced(self.slot)) + } } else { - Ok(None) + Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(self.slot)) } } - /// Request a Beacon Node (BN) to publish a block. + /// Consumes a block, returning that block signed by the validators private key. /// - /// Generally, this will be called after a `produce_beacon_block` call with a block that has - /// been completed (signed) by the validator client. - fn publish_beacon_block( - &self, - block: BeaconBlock, - ) -> Result { - let mut req = PublishBeaconBlockRequest::new(); + /// Important: this function will not check to ensure the block is not slashable. This must be + /// done upstream. + fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option { + self.store_produce(&block); - let ssz = ssz_encode(&block); - - let mut grpc_block = GrpcBeaconBlock::new(); - grpc_block.set_ssz(ssz); - - req.set_block(grpc_block); - - let reply = self - .client - .publish_beacon_block(&req) - .map_err(|err| BeaconBlockNodeError::RemoteFailure(format!("{:?}", err)))?; - - if reply.get_success() { - Ok(PublishOutcome::ValidBlock) - } else { - // TODO: distinguish between different errors - Ok(PublishOutcome::InvalidBlock("Publish failed".to_string())) + match self + .signer + .sign_block_proposal(&block.signed_root()[..], domain) + { + None => None, + Some(signature) => { + block.signature = signature; + Some(block) + } } } + + /// Returns `true` if signing a block is safe (non-slashable). + /// + /// !!! UNSAFE !!! + /// + /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. + fn safe_to_produce(&self, _block: &BeaconBlock) -> bool { + // TODO: ensure the producer doesn't produce slashable blocks. + // https://github.com/sigp/lighthouse/issues/160 + true + } + + /// Record that a block was produced so that slashable votes may not be made in the future. + /// + /// !!! UNSAFE !!! + /// + /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. + fn store_produce(&mut self, _block: &BeaconBlock) { + // TODO: record this block production to prevent future slashings. + // https://github.com/sigp/lighthouse/issues/160 + } } + +impl From for Error { + fn from(e: BeaconBlockNodeError) -> Error { + Error::BeaconBlockNodeError(e) + } +} + +/* Old tests - Re-work for new logic +#[cfg(test)] +mod tests { + use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode}; + use super::*; + use slot_clock::TestingSlotClock; + use types::{ + test_utils::{SeedableRng, TestRandom, XorShiftRng}, + Keypair, + }; + + // TODO: implement more thorough testing. + // https://github.com/sigp/lighthouse/issues/160 + // + // These tests should serve as a good example for future tests. + + #[test] + pub fn polling() { + let mut rng = XorShiftRng::from_seed([42; 16]); + + let spec = Arc::new(ChainSpec::foundation()); + let slot_clock = Arc::new(TestingSlotClock::new(0)); + let beacon_node = Arc::new(SimulatedBeaconNode::default()); + let signer = Arc::new(LocalSigner::new(Keypair::random())); + + let mut epoch_map = EpochMap::new(spec.slots_per_epoch); + let produce_slot = Slot::new(100); + let produce_epoch = produce_slot.epoch(spec.slots_per_epoch); + epoch_map.map.insert(produce_epoch, produce_slot); + let epoch_map = Arc::new(epoch_map); + + let mut block_proposer = BlockProducer::new( + spec.clone(), + epoch_map.clone(), + slot_clock.clone(), + beacon_node.clone(), + signer.clone(), + ); + + // Configure responses from the BeaconNode. + beacon_node.set_next_produce_result(Ok(Some(BeaconBlock::random_for_test(&mut rng)))); + beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidBlock)); + + // One slot before production slot... + slot_clock.set_slot(produce_slot.as_u64() - 1); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1)) + ); + + // On the produce slot... + slot_clock.set_slot(produce_slot.as_u64()); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::BlockProduced(produce_slot.into())) + ); + + // Trying the same produce slot again... + slot_clock.set_slot(produce_slot.as_u64()); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::SlotAlreadyProcessed(produce_slot)) + ); + + // One slot after the produce slot... + slot_clock.set_slot(produce_slot.as_u64() + 1); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1)) + ); + + // In an epoch without known duties... + let slot = (produce_epoch.as_u64() + 1) * spec.slots_per_epoch; + slot_clock.set_slot(slot); + assert_eq!( + block_proposer.poll(), + Ok(PollOutcome::ProducerDutiesUnknown(Slot::new(slot))) + ); + } +} +*/ diff --git a/validator_client/src/main.rs b/validator_client/src/main.rs index 6f02cf6ee..b3a488fe0 100644 --- a/validator_client/src/main.rs +++ b/validator_client/src/main.rs @@ -8,6 +8,7 @@ mod signer; use crate::config::Config as ValidatorClientConfig; use clap::{App, Arg}; +use protos::services_grpc::ValidatorServiceClient; use service::Service as ValidatorService; use slog::{error, info, o, Drain}; @@ -53,7 +54,8 @@ fn main() { .expect("Unable to build a configuration for the validator client."); // start the validator service. - match ValidatorService::start(config, log.clone()) { + // this specifies the GRPC type to use as the duty manager beacon node. + match ValidatorService::::start(config, log.clone()) { Ok(_) => info!(log, "Validator client shutdown successfully."), Err(e) => error!(log, "Validator exited due to: {}", e.to_string()), } diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 398f6d777..c8874a1f6 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -9,8 +9,7 @@ /// data from the beacon node and performs the signing before publishing the block to the beacon /// node. use crate::attester_service::{AttestationGrpcClient, AttesterService}; -use crate::block_producer::BlockProducer; -use crate::block_producer_service::BeaconBlockGrpcClient; +use crate::block_producer::{BeaconBlockGrpcClient, BlockProducer}; use crate::config::Config as ValidatorConfig; use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap, UpdateOutcome}; use crate::error as error_chain; @@ -40,6 +39,7 @@ use types::{ChainSpec, Epoch, Fork, Slot}; /// The validator service. This is the main thread that executes and maintains validator /// duties. +//TODO: Generalize the BeaconNode types to use testing pub struct Service { /// The node we currently connected to. connected_node_version: String, From 1840248af8497e9704948bf01d862676ebd25956 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 12:00:31 +1100 Subject: [PATCH 051/106] Remove old queues from BeaconChain --- beacon_node/beacon_chain/src/beacon_chain.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index d3b9e2bdc..41fcb1128 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -90,11 +90,6 @@ pub struct BeaconChain { pub slot_clock: U, pub attestation_aggregator: RwLock, pub op_pool: RwLock, - pub deposits_for_inclusion: RwLock>, - pub exits_for_inclusion: RwLock>, - pub transfers_for_inclusion: RwLock>, - pub proposer_slashings_for_inclusion: RwLock>, - pub attester_slashings_for_inclusion: RwLock>, canonical_head: RwLock, finalized_head: RwLock, pub state: RwLock, @@ -149,11 +144,6 @@ where slot_clock, attestation_aggregator, op_pool: RwLock::new(OperationPool::new()), - deposits_for_inclusion: RwLock::new(vec![]), - exits_for_inclusion: RwLock::new(vec![]), - transfers_for_inclusion: RwLock::new(vec![]), - proposer_slashings_for_inclusion: RwLock::new(vec![]), - attester_slashings_for_inclusion: RwLock::new(vec![]), state: RwLock::new(genesis_state), finalized_head, canonical_head, From 97bb61371c666deae630fe6eb9006119168f8b9e Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 12:14:56 +1100 Subject: [PATCH 052/106] Correct compiler issues, re-introduce validator library --- validator_client/Cargo.toml | 4 ++++ validator_client/src/lib.rs | 3 +++ validator_client/src/service.rs | 25 ++++++++++++++----------- 3 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 validator_client/src/lib.rs diff --git a/validator_client/Cargo.toml b/validator_client/Cargo.toml index 209ebf25e..80477c8ea 100644 --- a/validator_client/Cargo.toml +++ b/validator_client/Cargo.toml @@ -8,6 +8,10 @@ edition = "2018" name = "validator_client" path = "src/main.rs" +[lib] +name = "validator_client" +path = "src/lib.rs" + [dependencies] block_proposer = { path = "../eth2/block_proposer" } attester = { path = "../eth2/attester" } diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs new file mode 100644 index 000000000..470a070e8 --- /dev/null +++ b/validator_client/src/lib.rs @@ -0,0 +1,3 @@ +pub mod config; + +pub use crate::config::Config; diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index c8874a1f6..bd1053a34 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -41,9 +41,7 @@ use types::{ChainSpec, Epoch, Fork, Slot}; /// duties. //TODO: Generalize the BeaconNode types to use testing pub struct Service { - /// The node we currently connected to. - connected_node_version: String, - /// The chain id we are processing on. + /// The node's current fork version we are processing on. fork: Fork, /// The slot clock for this service. slot_clock: SystemTimeSlotClock, @@ -67,7 +65,10 @@ impl Service { /// /// This tries to connect to a beacon node. Once connected, it initialised the gRPC clients /// and returns an instance of the service. - fn initialize_service(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result { + fn initialize_service( + config: ValidatorConfig, + log: slog::Logger, + ) -> error_chain::Result> { // initialise the beacon node client to check for a connection let env = Arc::new(EnvBuilder::new().build()); @@ -162,8 +163,6 @@ impl Service { .map_err(|e| ErrorKind::SlotClockError(e))? .expect("Genesis must be in the future"); - let spec = Arc::new(config.spec); - /* Generate the duties manager */ // generate keypairs @@ -185,8 +184,9 @@ impl Service { beacon_node: validator_client, }); - Ok(Self { - connected_node_version: node_info.version, + let spec = Arc::new(config.spec); + + Ok(Service { fork, slot_clock, current_slot, @@ -199,9 +199,10 @@ impl Service { } /// Initialise the service then run the core thread. + // TODO: Improve handling of generic BeaconNode types, to stub grpcClient pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> { // connect to the node and retrieve its properties and initialize the gRPC clients - let service = Service::initialize_service(config, log)?; + let mut service = Service::::initialize_service(config, log)?; // we have connected to a node and established its parameters. Spin up the core service @@ -221,7 +222,7 @@ impl Service { // set up the validator work interval - start at next slot and proceed every slot let interval = { // Set the interval to start at the next slot, and every slot after - let slot_duration = Duration::from_secs(config.spec.seconds_per_slot); + let slot_duration = Duration::from_secs(service.spec.seconds_per_slot); //TODO: Handle checked add correctly Interval::new(Instant::now() + duration_to_next_slot, slot_duration) }; @@ -236,7 +237,7 @@ impl Service { Ok(()) }) .map_err(|e| format!("Service thread failed: {:?}", e)), - ); + )?; // validator client exited Ok(()) } @@ -300,11 +301,13 @@ impl Service { if work_type.produce_block { // spawns a thread to produce a beacon block std::thread::spawn(move || { + /* let block_producer = BlockProducer { fork: self.fork, slot: self.current_slot, spec: self.spec.clone(), }; + */ }); // TODO: Produce a beacon block in a new thread From cd9494181c80d5c1af40246ff9033674d2246e64 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 12:26:25 +1100 Subject: [PATCH 053/106] Push RwLock down into OperationPool There used to be one massive lock on `BeaconChain.op_pool`, however that would cause unnecessary blocking. --- beacon_node/beacon_chain/src/beacon_chain.rs | 51 ++------- eth2/operation_pool/Cargo.toml | 1 + eth2/operation_pool/src/lib.rs | 113 ++++++++++--------- 3 files changed, 75 insertions(+), 90 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 41fcb1128..5e83fdd81 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -89,7 +89,7 @@ pub struct BeaconChain { pub state_store: Arc>, pub slot_clock: U, pub attestation_aggregator: RwLock, - pub op_pool: RwLock, + pub op_pool: OperationPool, canonical_head: RwLock, finalized_head: RwLock, pub state: RwLock, @@ -143,7 +143,7 @@ where state_store, slot_clock, attestation_aggregator, - op_pool: RwLock::new(OperationPool::new()), + op_pool: OperationPool::new(), state: RwLock::new(genesis_state), finalized_head, canonical_head, @@ -545,7 +545,6 @@ where attestation: Attestation, ) -> Result<(), AttestationValidationError> { self.op_pool - .write() .insert_attestation(attestation, &*self.state.read(), &self.spec) } @@ -555,21 +554,18 @@ where deposit: Deposit, ) -> Result { self.op_pool - .write() .insert_deposit(deposit, &*self.state.read(), &self.spec) } /// Accept some exit and queue it for inclusion in an appropriate block. pub fn process_voluntary_exit(&self, exit: VoluntaryExit) -> Result<(), ExitValidationError> { self.op_pool - .write() .insert_voluntary_exit(exit, &*self.state.read(), &self.spec) } /// Accept some transfer and queue it for inclusion in an appropriate block. pub fn process_transfer(&self, transfer: Transfer) -> Result<(), TransferValidationError> { self.op_pool - .write() .insert_transfer(transfer, &*self.state.read(), &self.spec) } @@ -578,11 +574,8 @@ where &self, proposer_slashing: ProposerSlashing, ) -> Result<(), ProposerSlashingValidationError> { - self.op_pool.write().insert_proposer_slashing( - proposer_slashing, - &*self.state.read(), - &self.spec, - ) + self.op_pool + .insert_proposer_slashing(proposer_slashing, &*self.state.read(), &self.spec) } /// Accept some attester slashing and queue it for inclusion in an appropriate block. @@ -590,11 +583,8 @@ where &self, attester_slashing: AttesterSlashing, ) -> Result<(), AttesterSlashingValidationError> { - self.op_pool.write().insert_attester_slashing( - attester_slashing, - &*self.state.read(), - &self.spec, - ) + self.op_pool + .insert_attester_slashing(attester_slashing, &*self.state.read(), &self.spec) } /// Accept some block and attempt to add it to block DAG. @@ -705,24 +695,12 @@ where trace!("Finding attestations for new block..."); - let attestations = self - .op_pool - .read() - .get_attestations(&*self.state.read(), &self.spec); - - trace!( - "Inserting {} attestation(s) into new block.", - attestations.len() - ); - let previous_block_root = *state .get_block_root(state.slot - 1, &self.spec) .map_err(|_| BlockProductionError::UnableToGetBlockRootFromState)?; - let (proposer_slashings, attester_slashings) = self - .op_pool - .read() - .get_slashings(&*self.state.read(), &self.spec); + let (proposer_slashings, attester_slashings) = + self.op_pool.get_slashings(&*self.state.read(), &self.spec); let mut block = BeaconBlock { slot: state.slot, @@ -738,19 +716,14 @@ where }, proposer_slashings, attester_slashings, - attestations, - deposits: self + attestations: self .op_pool - .read() - .get_deposits(&*self.state.read(), &self.spec), + .get_attestations(&*self.state.read(), &self.spec), + deposits: self.op_pool.get_deposits(&*self.state.read(), &self.spec), voluntary_exits: self .op_pool - .read() .get_voluntary_exits(&*self.state.read(), &self.spec), - transfers: self - .op_pool - .read() - .get_transfers(&*self.state.read(), &self.spec), + transfers: self.op_pool.get_transfers(&*self.state.read(), &self.spec), }, }; diff --git a/eth2/operation_pool/Cargo.toml b/eth2/operation_pool/Cargo.toml index 07cb61864..67d13013c 100644 --- a/eth2/operation_pool/Cargo.toml +++ b/eth2/operation_pool/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] int_to_bytes = { path = "../utils/int_to_bytes" } itertools = "0.8" +parking_lot = "0.7" types = { path = "../types" } state_processing = { path = "../state_processing" } ssz = { path = "../utils/ssz" } diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index c3de95b48..c42527b60 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -1,5 +1,6 @@ use int_to_bytes::int_to_bytes8; use itertools::Itertools; +use parking_lot::RwLock; use ssz::ssz_encode; use state_processing::per_block_processing::errors::{ AttestationValidationError, AttesterSlashingValidationError, DepositValidationError, @@ -26,21 +27,21 @@ const VERIFY_DEPOSIT_PROOFS: bool = false; // TODO: enable this #[derive(Default)] pub struct OperationPool { /// Map from attestation ID (see below) to vectors of attestations. - attestations: HashMap>, + attestations: RwLock>>, /// Map from deposit index to deposit data. // NOTE: We assume that there is only one deposit per index // because the Eth1 data is updated (at most) once per epoch, // and the spec doesn't seem to accomodate for re-orgs on a time-frame // longer than an epoch - deposits: BTreeMap, + deposits: RwLock>, /// Map from two attestation IDs to a slashing for those IDs. - attester_slashings: HashMap<(AttestationId, AttestationId), AttesterSlashing>, + attester_slashings: RwLock>, /// Map from proposer index to slashing. - proposer_slashings: HashMap, + proposer_slashings: RwLock>, /// Map from exiting validator to their exit data. - voluntary_exits: HashMap, + voluntary_exits: RwLock>, /// Set of transfers. - transfers: HashSet, + transfers: RwLock>, } /// Serialized `AttestationData` augmented with a domain to encode the fork info. @@ -109,7 +110,7 @@ impl OperationPool { /// Insert an attestation into the pool, aggregating it with existing attestations if possible. pub fn insert_attestation( - &mut self, + &self, attestation: Attestation, state: &BeaconState, spec: &ChainSpec, @@ -119,7 +120,10 @@ impl OperationPool { let id = AttestationId::from_data(&attestation.data, state, spec); - let existing_attestations = match self.attestations.entry(id) { + // Take a write lock on the attestations map. + let mut attestations = self.attestations.write(); + + let existing_attestations = match attestations.entry(id) { hash_map::Entry::Vacant(entry) => { entry.insert(vec![attestation]); return Ok(()); @@ -146,7 +150,11 @@ impl OperationPool { /// Total number of attestations in the pool, including attestations for the same data. pub fn num_attestations(&self) -> usize { - self.attestations.values().map(|atts| atts.len()).sum() + self.attestations + .read() + .values() + .map(|atts| atts.len()) + .sum() } /// Get a list of attestations for inclusion in a block. @@ -157,6 +165,7 @@ impl OperationPool { let prev_domain_bytes = AttestationId::compute_domain_bytes(prev_epoch, state, spec); let curr_domain_bytes = AttestationId::compute_domain_bytes(current_epoch, state, spec); self.attestations + .read() .iter() .filter(|(key, _)| { key.domain_bytes_match(&prev_domain_bytes) @@ -180,8 +189,8 @@ impl OperationPool { // TODO: we could probably prune other attestations here: // - ones that are completely covered by attestations included in the state // - maybe ones invalidated by the confirmation of one fork over another - pub fn prune_attestations(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { - self.attestations.retain(|_, attestations| { + pub fn prune_attestations(&self, finalized_state: &BeaconState, spec: &ChainSpec) { + self.attestations.write().retain(|_, attestations| { // All the attestations in this bucket have the same data, so we only need to // check the first one. attestations.first().map_or(false, |att| { @@ -194,14 +203,14 @@ impl OperationPool { /// /// No two distinct deposits should be added with the same index. pub fn insert_deposit( - &mut self, + &self, deposit: Deposit, state: &BeaconState, spec: &ChainSpec, ) -> Result { use DepositInsertStatus::*; - match self.deposits.entry(deposit.index) { + match self.deposits.write().entry(deposit.index) { Entry::Vacant(entry) => { verify_deposit(state, &deposit, VERIFY_DEPOSIT_PROOFS, spec)?; entry.insert(deposit); @@ -224,27 +233,26 @@ impl OperationPool { pub fn get_deposits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { let start_idx = state.deposit_index; (start_idx..start_idx + spec.max_deposits) - .map(|idx| self.deposits.get(&idx)) + .map(|idx| self.deposits.read().get(&idx).cloned()) .take_while(Option::is_some) .flatten() - .cloned() .collect() } /// Remove all deposits with index less than the deposit index of the latest finalised block. - pub fn prune_deposits(&mut self, state: &BeaconState) -> BTreeMap { - let deposits_keep = self.deposits.split_off(&state.deposit_index); - std::mem::replace(&mut self.deposits, deposits_keep) + pub fn prune_deposits(&self, state: &BeaconState) -> BTreeMap { + let deposits_keep = self.deposits.write().split_off(&state.deposit_index); + std::mem::replace(&mut self.deposits.write(), deposits_keep) } /// The number of deposits stored in the pool. pub fn num_deposits(&self) -> usize { - self.deposits.len() + self.deposits.read().len() } /// Insert a proposer slashing into the pool. pub fn insert_proposer_slashing( - &mut self, + &self, slashing: ProposerSlashing, state: &BeaconState, spec: &ChainSpec, @@ -253,6 +261,7 @@ impl OperationPool { // because they could *become* known later verify_proposer_slashing(&slashing, state, spec)?; self.proposer_slashings + .write() .insert(slashing.proposer_index, slashing); Ok(()) } @@ -273,14 +282,14 @@ impl OperationPool { /// Insert an attester slashing into the pool. pub fn insert_attester_slashing( - &mut self, + &self, slashing: AttesterSlashing, state: &BeaconState, spec: &ChainSpec, ) -> Result<(), AttesterSlashingValidationError> { verify_attester_slashing(state, &slashing, true, spec)?; let id = Self::attester_slashing_id(&slashing, state, spec); - self.attester_slashings.insert(id, slashing); + self.attester_slashings.write().insert(id, slashing); Ok(()) } @@ -295,7 +304,7 @@ impl OperationPool { spec: &ChainSpec, ) -> (Vec, Vec) { let proposer_slashings = filter_limit_operations( - self.proposer_slashings.values(), + self.proposer_slashings.read().values(), |slashing| { state .validator_registry @@ -314,6 +323,7 @@ impl OperationPool { let attester_slashings = self .attester_slashings + .read() .iter() .filter(|(id, slashing)| { // Check the fork. @@ -345,9 +355,9 @@ impl OperationPool { } /// Prune proposer slashings for all slashed or withdrawn validators. - pub fn prune_proposer_slashings(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { + pub fn prune_proposer_slashings(&self, finalized_state: &BeaconState, spec: &ChainSpec) { prune_validator_hash_map( - &mut self.proposer_slashings, + &mut self.proposer_slashings.write(), |validator| { validator.slashed || validator.is_withdrawable_at(finalized_state.current_epoch(spec)) @@ -358,8 +368,8 @@ impl OperationPool { /// Prune attester slashings for all slashed or withdrawn validators, or attestations on another /// fork. - pub fn prune_attester_slashings(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { - self.attester_slashings.retain(|id, slashing| { + pub fn prune_attester_slashings(&self, finalized_state: &BeaconState, spec: &ChainSpec) { + self.attester_slashings.write().retain(|id, slashing| { let fork_ok = &Self::attester_slashing_id(slashing, finalized_state, spec) == id; let curr_epoch = finalized_state.current_epoch(spec); let slashing_ok = gather_attester_slashing_indices_modular( @@ -375,29 +385,31 @@ impl OperationPool { /// Insert a voluntary exit, validating it almost-entirely (future exits are permitted). pub fn insert_voluntary_exit( - &mut self, + &self, exit: VoluntaryExit, state: &BeaconState, spec: &ChainSpec, ) -> Result<(), ExitValidationError> { verify_exit_time_independent_only(state, &exit, spec)?; - self.voluntary_exits.insert(exit.validator_index, exit); + self.voluntary_exits + .write() + .insert(exit.validator_index, exit); Ok(()) } /// Get a list of voluntary exits for inclusion in a block. pub fn get_voluntary_exits(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { filter_limit_operations( - self.voluntary_exits.values(), + self.voluntary_exits.read().values(), |exit| verify_exit(state, exit, spec).is_ok(), spec.max_voluntary_exits, ) } /// Prune if validator has already exited at the last finalized state. - pub fn prune_voluntary_exits(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { + pub fn prune_voluntary_exits(&self, finalized_state: &BeaconState, spec: &ChainSpec) { prune_validator_hash_map( - &mut self.voluntary_exits, + &mut self.voluntary_exits.write(), |validator| validator.is_exited_at(finalized_state.current_epoch(spec)), finalized_state, ); @@ -405,7 +417,7 @@ impl OperationPool { /// Insert a transfer into the pool, checking it for validity in the process. pub fn insert_transfer( - &mut self, + &self, transfer: Transfer, state: &BeaconState, spec: &ChainSpec, @@ -414,7 +426,7 @@ impl OperationPool { // it before we insert into the HashSet, we can't end up with duplicate // transactions. verify_transfer_time_independent_only(state, &transfer, spec)?; - self.transfers.insert(transfer); + self.transfers.write().insert(transfer); Ok(()) } @@ -423,6 +435,7 @@ impl OperationPool { // dependencies between transfers in the same block e.g. A pays B, B pays C pub fn get_transfers(&self, state: &BeaconState, spec: &ChainSpec) -> Vec { self.transfers + .read() .iter() .filter(|transfer| verify_transfer(state, transfer, spec).is_ok()) .sorted_by_key(|transfer| std::cmp::Reverse(transfer.fee)) @@ -432,16 +445,14 @@ impl OperationPool { } /// Prune the set of transfers by removing all those whose slot has already passed. - pub fn prune_transfers(&mut self, finalized_state: &BeaconState) { - self.transfers = self - .transfers - .drain() - .filter(|transfer| transfer.slot > finalized_state.slot) - .collect(); + pub fn prune_transfers(&self, finalized_state: &BeaconState) { + self.transfers + .write() + .retain(|transfer| transfer.slot > finalized_state.slot) } /// Prune all types of transactions given the latest finalized state. - pub fn prune_all(&mut self, finalized_state: &BeaconState, spec: &ChainSpec) { + pub fn prune_all(&self, finalized_state: &BeaconState, spec: &ChainSpec) { self.prune_attestations(finalized_state, spec); self.prune_deposits(finalized_state); self.prune_proposer_slashings(finalized_state, spec); @@ -497,7 +508,7 @@ mod tests { fn insert_deposit() { let rng = &mut XorShiftRng::from_seed([42; 16]); let (ref spec, ref state) = test_state(rng); - let mut op_pool = OperationPool::new(); + let op_pool = OperationPool::new(); let deposit1 = make_deposit(rng, state, spec); let mut deposit2 = make_deposit(rng, state, spec); deposit2.index = deposit1.index; @@ -520,7 +531,7 @@ mod tests { fn get_deposits_max() { let rng = &mut XorShiftRng::from_seed([42; 16]); let (spec, mut state) = test_state(rng); - let mut op_pool = OperationPool::new(); + let op_pool = OperationPool::new(); let start = 10000; let max_deposits = spec.max_deposits; let extra = 5; @@ -550,7 +561,7 @@ mod tests { fn prune_deposits() { let rng = &mut XorShiftRng::from_seed([42; 16]); let (spec, state) = test_state(rng); - let mut op_pool = OperationPool::new(); + let op_pool = OperationPool::new(); let start1 = 100; // test is super slow in debug mode if this parameter is too high @@ -734,7 +745,7 @@ mod tests { fn attestation_aggregation_insert_get_prune() { let spec = &ChainSpec::foundation(); let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); - let mut op_pool = OperationPool::new(); + let op_pool = OperationPool::new(); let slot = state.slot - 1; let committees = state @@ -765,7 +776,7 @@ mod tests { } } - assert_eq!(op_pool.attestations.len(), committees.len()); + assert_eq!(op_pool.attestations.read().len(), committees.len()); assert_eq!(op_pool.num_attestations(), committees.len()); // Before the min attestation inclusion delay, get_attestations shouldn't return anything. @@ -799,7 +810,7 @@ mod tests { fn attestation_duplicate() { let spec = &ChainSpec::foundation(); let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); - let mut op_pool = OperationPool::new(); + let op_pool = OperationPool::new(); let slot = state.slot - 1; let committees = state @@ -825,7 +836,7 @@ mod tests { fn attestation_pairwise_overlapping() { let spec = &ChainSpec::foundation(); let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); - let mut op_pool = OperationPool::new(); + let op_pool = OperationPool::new(); let slot = state.slot - 1; let committees = state @@ -854,7 +865,7 @@ mod tests { // The attestations should get aggregated into two attestations that comprise all // validators. - assert_eq!(op_pool.attestations.len(), committees.len()); + assert_eq!(op_pool.attestations.read().len(), committees.len()); assert_eq!(op_pool.num_attestations(), 2 * committees.len()); } @@ -869,7 +880,7 @@ mod tests { let small_step_size = 2; let big_step_size = 4; let (ref mut state, ref keypairs) = attestation_test_state(spec, big_step_size); - let mut op_pool = OperationPool::new(); + let op_pool = OperationPool::new(); let slot = state.slot - 1; let committees = state @@ -907,7 +918,7 @@ mod tests { let num_small = target_committee_size / small_step_size; let num_big = target_committee_size / big_step_size; - assert_eq!(op_pool.attestations.len(), committees.len()); + assert_eq!(op_pool.attestations.read().len(), committees.len()); assert_eq!( op_pool.num_attestations(), (num_small + num_big) * committees.len() From 89cc92572a1764be16c12dcdd8b205fea1770b23 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 13:03:05 +1100 Subject: [PATCH 054/106] Add `test_harness` tests for attestation count --- .../specs/validator_registry.yaml | 2 ++ .../test_harness/src/test_case/state_check.rs | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml b/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml index 0c4f5004b..1674ecffc 100644 --- a/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml +++ b/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml @@ -47,6 +47,8 @@ test_cases: states: - slot: 63 num_validators: 1003 + num_previous_epoch_attestations: 0 + num_current_epoch_attestations: 10 slashed_validators: [11, 12, 13, 14, 42] exited_validators: [] exit_initiated_validators: [50] diff --git a/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs b/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs index 4d2bfd07d..7ac33c86c 100644 --- a/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs +++ b/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs @@ -16,6 +16,10 @@ pub struct StateCheck { pub slot: Slot, /// Checked against `beacon_state.validator_registry.len()`. pub num_validators: Option, + /// The number of pending attestations from the previous epoch that should be in the state. + pub num_previous_epoch_attestations: Option, + /// The number of pending attestations from the current epoch that should be in the state. + pub num_current_epoch_attestations: Option, /// A list of validator indices which have been penalized. Must be in ascending order. pub slashed_validators: Option>, /// A list of validator indices which have been fully exited. Must be in ascending order. @@ -34,6 +38,8 @@ impl StateCheck { Self { slot: Slot::from(as_u64(&yaml, "slot").expect("State must specify slot")), num_validators: as_usize(&yaml, "num_validators"), + num_previous_epoch_attestations: as_usize(&yaml, "num_previous_epoch_attestations"), + num_current_epoch_attestations: as_usize(&yaml, "num_current_epoch_attestations"), slashed_validators: as_vec_u64(&yaml, "slashed_validators"), exited_validators: as_vec_u64(&yaml, "exited_validators"), exit_initiated_validators: as_vec_u64(&yaml, "exit_initiated_validators"), @@ -58,6 +64,7 @@ impl StateCheck { "State slot is invalid." ); + // Check the validator count if let Some(num_validators) = self.num_validators { assert_eq!( state.validator_registry.len(), @@ -67,6 +74,26 @@ impl StateCheck { info!("OK: num_validators = {}.", num_validators); } + // Check the previous epoch attestations + if let Some(n) = self.num_previous_epoch_attestations { + assert_eq!( + state.previous_epoch_attestations.len(), + n, + "previous epoch attestations count != expected." + ); + info!("OK: num_previous_epoch_attestations = {}.", n); + } + + // Check the current epoch attestations + if let Some(n) = self.num_current_epoch_attestations { + assert_eq!( + state.current_epoch_attestations.len(), + n, + "current epoch attestations count != expected." + ); + info!("OK: num_current_epoch_attestations = {}.", n); + } + // Check for slashed validators. if let Some(ref slashed_validators) = self.slashed_validators { let actually_slashed_validators: Vec = state From d3a6d73153eb6de71ed6eb5d2a8ad08324bf5927 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 14:27:37 +1100 Subject: [PATCH 055/106] Implements Signer generic for validator client and epoch duties --- eth2/utils/bls/src/keypair.rs | 7 +++++ .../src/duties/beacon_node_duties.rs | 4 +-- validator_client/src/duties/epoch_duties.rs | 6 ++-- validator_client/src/duties/grpc.rs | 12 ++++---- validator_client/src/duties/mod.rs | 26 +++++++++-------- validator_client/src/main.rs | 5 ++-- validator_client/src/service.rs | 17 +++++------ validator_client/src/signer.rs | 29 +++++++++++++++++-- 8 files changed, 70 insertions(+), 36 deletions(-) diff --git a/eth2/utils/bls/src/keypair.rs b/eth2/utils/bls/src/keypair.rs index c91b13bad..2f0e794a6 100644 --- a/eth2/utils/bls/src/keypair.rs +++ b/eth2/utils/bls/src/keypair.rs @@ -1,5 +1,6 @@ use super::{PublicKey, SecretKey}; use serde_derive::{Deserialize, Serialize}; +use std::fmt; use std::hash::{Hash, Hasher}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -32,3 +33,9 @@ impl Hash for Keypair { self.pk.as_uncompressed_bytes().hash(state) } } + +impl fmt::Display for Keypair { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.pk) + } +} diff --git a/validator_client/src/duties/beacon_node_duties.rs b/validator_client/src/duties/beacon_node_duties.rs index b66b5f704..af1fab60b 100644 --- a/validator_client/src/duties/beacon_node_duties.rs +++ b/validator_client/src/duties/beacon_node_duties.rs @@ -1,5 +1,5 @@ use super::EpochDuties; -use types::{Epoch, Keypair}; +use types::{Epoch, PublicKey}; #[derive(Debug, PartialEq, Clone)] pub enum BeaconNodeDutiesError { @@ -15,6 +15,6 @@ pub trait BeaconNodeDuties: Send + Sync { fn request_duties( &self, epoch: Epoch, - signers: &[Keypair], + pub_keys: &[PublicKey], ) -> Result; } diff --git a/validator_client/src/duties/epoch_duties.rs b/validator_client/src/duties/epoch_duties.rs index 8e710ba9a..0a4f73f72 100644 --- a/validator_client/src/duties/epoch_duties.rs +++ b/validator_client/src/duties/epoch_duties.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::fmt; use std::ops::{Deref, DerefMut}; -use types::{AttestationDuty, Epoch, Keypair, Slot}; +use types::{AttestationDuty, Epoch, PublicKey, Slot}; /// When work needs to be performed by a validator, this type is given back to the main service /// which indicates all the information that required to process the work. @@ -72,7 +72,7 @@ impl fmt::Display for EpochDuty { } /// Maps a list of keypairs (many validators) to an EpochDuty. -pub type EpochDuties = HashMap>; +pub type EpochDuties = HashMap>; pub enum EpochDutiesMapError { UnknownEpoch, @@ -113,7 +113,7 @@ impl EpochDutiesMap { pub fn is_work_slot( &self, slot: Slot, - signer: &Keypair, + signer: &PublicKey, ) -> Result, EpochDutiesMapError> { let epoch = slot.epoch(self.slots_per_epoch); diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index d6e2e5238..66bf368a2 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -6,21 +6,21 @@ use protos::services_grpc::ValidatorServiceClient; use ssz::ssz_encode; use std::collections::HashMap; use std::time::Duration; -use types::{Epoch, Keypair, Slot}; +use types::{Epoch, PublicKey, Slot}; impl BeaconNodeDuties for ValidatorServiceClient { /// Requests all duties (block signing and committee attesting) from the Beacon Node (BN). fn request_duties( &self, epoch: Epoch, - signers: &[Keypair], + pub_keys: &[PublicKey], ) -> Result { // Get the required duties from all validators // build the request let mut req = GetDutiesRequest::new(); req.set_epoch(epoch.as_u64()); let mut validators = Validators::new(); - validators.set_public_keys(signers.iter().map(|v| ssz_encode(&v.pk)).collect()); + validators.set_public_keys(pub_keys.iter().map(|v| ssz_encode(v)).collect()); req.set_validators(validators); // set a timeout for requests @@ -31,11 +31,11 @@ impl BeaconNodeDuties for ValidatorServiceClient { .get_validator_duties(&req) .map_err(|err| BeaconNodeDutiesError::RemoteFailure(format!("{:?}", err)))?; - let mut epoch_duties: HashMap> = HashMap::new(); + let mut epoch_duties: HashMap> = HashMap::new(); for (index, validator_duty) in reply.get_active_validators().iter().enumerate() { if !validator_duty.has_duty() { // validator is inactive - epoch_duties.insert(signers[index].clone(), None); + epoch_duties.insert(pub_keys[index].clone(), None); continue; } // active validator @@ -53,7 +53,7 @@ impl BeaconNodeDuties for ValidatorServiceClient { attestation_shard: active_duty.get_attestation_shard(), committee_index: active_duty.get_committee_index(), }; - epoch_duties.insert(signers[index].clone(), Some(epoch_duty)); + epoch_duties.insert(pub_keys[index].clone(), Some(epoch_duty)); } Ok(epoch_duties) } diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 1019f489d..596d314ed 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -8,11 +8,13 @@ mod grpc; pub use self::beacon_node_duties::{BeaconNodeDuties, BeaconNodeDutiesError}; use self::epoch_duties::{EpochDuties, EpochDutiesMapError}; pub use self::epoch_duties::{EpochDutiesMap, WorkInfo}; +use super::signer::Signer; use futures::Async; use slog::{debug, error, info}; +use std::fmt::Display; use std::sync::Arc; use std::sync::RwLock; -use types::{Epoch, Keypair, Slot}; +use types::{Epoch, PublicKey, Slot}; #[derive(Debug, PartialEq, Clone)] pub enum UpdateOutcome { @@ -38,20 +40,20 @@ pub enum Error { /// Node. /// /// This keeps track of all validator keys and required voting slots. -pub struct DutiesManager { +pub struct DutiesManager { pub duties_map: RwLock, /// A list of all signer objects known to the validator service. - // TODO: Generalise the signers, so that they're not just keypairs - pub signers: Arc>, + pub signers: Arc>, pub beacon_node: Arc, } -impl DutiesManager { +impl DutiesManager { /// Check the Beacon Node for `EpochDuties`. /// /// be a wall-clock (e.g., system time, remote server time, etc.). fn update(&self, epoch: Epoch) -> Result { - let duties = self.beacon_node.request_duties(epoch, &self.signers)?; + let public_keys: Vec = self.signers.iter().map(|s| s.to_public()).collect(); + let duties = self.beacon_node.request_duties(epoch, &public_keys)?; { // If these duties were known, check to see if they're updates or identical. if let Some(known_duties) = self.duties_map.read()?.get(&epoch) { @@ -90,17 +92,17 @@ impl DutiesManager { Ok(Async::Ready(())) } - /// Returns a list of (Public, WorkInfo) indicating all the validators that have work to perform + /// Returns a list of (index, WorkInfo) indicating all the validators that have work to perform /// this slot. - pub fn get_current_work(&self, slot: Slot) -> Option> { - let mut current_work: Vec<(Keypair, WorkInfo)> = Vec::new(); + pub fn get_current_work(&self, slot: Slot) -> Option> { + let mut current_work: Vec<(usize, WorkInfo)> = Vec::new(); // if the map is poisoned, return None let duties = self.duties_map.read().ok()?; - for validator_signer in self.signers.iter() { - match duties.is_work_slot(slot, &validator_signer) { - Ok(Some(work_type)) => current_work.push((validator_signer.clone(), work_type)), + for (index, validator_signer) in self.signers.iter().enumerate() { + match duties.is_work_slot(slot, &validator_signer.to_public()) { + Ok(Some(work_type)) => current_work.push((index, work_type)), Ok(None) => {} // No work for this validator //TODO: This should really log an error, as we shouldn't end up with an err here. Err(_) => {} // Unknown epoch or validator, no work diff --git a/validator_client/src/main.rs b/validator_client/src/main.rs index b3a488fe0..481766734 100644 --- a/validator_client/src/main.rs +++ b/validator_client/src/main.rs @@ -11,6 +11,7 @@ use clap::{App, Arg}; use protos::services_grpc::ValidatorServiceClient; use service::Service as ValidatorService; use slog::{error, info, o, Drain}; +use types::Keypair; fn main() { // Logging @@ -54,8 +55,8 @@ fn main() { .expect("Unable to build a configuration for the validator client."); // start the validator service. - // this specifies the GRPC type to use as the duty manager beacon node. - match ValidatorService::::start(config, log.clone()) { + // this specifies the GRPC and signer type to use as the duty manager beacon node. + match ValidatorService::::start(config, log.clone()) { Ok(_) => info!(log, "Validator client shutdown successfully."), Err(e) => error!(log, "Validator exited due to: {}", e.to_string()), } diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index d92d944cb..d6c0e6638 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -14,6 +14,7 @@ use crate::config::Config as ValidatorConfig; use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap, UpdateOutcome}; use crate::error as error_chain; use crate::error::ErrorKind; +use crate::signer::Signer; use attester::test_utils::EpochMap; use attester::{test_utils::LocalSigner as AttesterLocalSigner, Attester}; use bls::Keypair; @@ -36,14 +37,10 @@ use tokio_timer::clock::Clock; use types::test_utils::generate_deterministic_keypairs; use types::{ChainSpec, Epoch, Fork, Slot}; -//TODO: This service should be simplified in the future. Can be made more steamlined. - -const POLL_INTERVAL_MILLIS: u64 = 100; - /// The validator service. This is the main thread that executes and maintains validator /// duties. //TODO: Generalize the BeaconNode types to use testing -pub struct Service { +pub struct Service { /// The node's current fork version we are processing on. fork: Fork, /// The slot clock for this service. @@ -53,7 +50,7 @@ pub struct Service { /// The chain specification for this clients instance. spec: Arc, /// The duties manager which maintains the state of when to perform actions. - duties_manager: Arc>, + duties_manager: Arc>, // GRPC Clients /// The beacon block GRPC client. beacon_block_client: Arc, @@ -63,7 +60,7 @@ pub struct Service { log: slog::Logger, } -impl Service { +impl Service { /// Initial connection to the beacon node to determine its properties. /// /// This tries to connect to a beacon node. Once connected, it initialised the gRPC clients @@ -71,7 +68,7 @@ impl Service { fn initialize_service( config: ValidatorConfig, log: slog::Logger, - ) -> error_chain::Result> { + ) -> error_chain::Result> { // initialise the beacon node client to check for a connection let env = Arc::new(EnvBuilder::new().build()); @@ -183,6 +180,7 @@ impl Service { // and can check when a validator needs to perform a task. let duties_manager = Arc::new(DutiesManager { duties_map, + // these are abstract objects capable of signing signers: keypairs, beacon_node: validator_client, }); @@ -205,7 +203,8 @@ impl Service { // TODO: Improve handling of generic BeaconNode types, to stub grpcClient pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> { // connect to the node and retrieve its properties and initialize the gRPC clients - let mut service = Service::::initialize_service(config, log)?; + let mut service = + Service::::initialize_service(config, log)?; // we have connected to a node and established its parameters. Spin up the core service diff --git a/validator_client/src/signer.rs b/validator_client/src/signer.rs index 85bf35b16..49dedbb33 100644 --- a/validator_client/src/signer.rs +++ b/validator_client/src/signer.rs @@ -1,7 +1,32 @@ -use types::Signature; +use std::fmt::Display; +use types::{Keypair, PublicKey, Signature}; /// Signs message using an internally-maintained private key. -pub trait Signer { +pub trait Signer: Display + Send + Sync { fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option; fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option; + /// Returns a public key for the signer object. + fn to_public(&self) -> PublicKey; +} + +/* Implements Display and Signer for Keypair */ + +impl Signer for Keypair { + fn to_public(&self) -> PublicKey { + self.pk.clone() + } + + fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option { + Some(Signature::new(message, domain, &self.sk)) + } + + fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option { + Some(Signature::new(message, domain, &self.sk)) + } + + /* + fn sign_attestation_message(&self, message: &[u8], domain: u64) -> Option { + Some(Signature::new(message, domain, &self.sk)) + } + */ } From deb0abd4a811a3c33491a9476755f5466953f010 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 14:28:42 +1100 Subject: [PATCH 056/106] Restores display for validator keys --- validator_client/src/duties/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 596d314ed..9f0998567 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -140,9 +140,9 @@ impl From for Error { fn print_duties(log: &slog::Logger, duties: EpochDuties) { for (pk, duty) in duties.iter() { if let Some(display_duty) = duty { - info!(log, "Validator: {:?}",pk; "Duty" => format!("{}",display_duty)); + info!(log, "Validator: {}",pk; "Duty" => format!("{}",display_duty)); } else { - info!(log, "Validator: {:?}",pk; "Duty" => "None"); + info!(log, "Validator: {}",pk; "Duty" => "None"); } } } From ba9090173023e48d36844ea224bcfafabec57ce5 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 14:48:43 +1100 Subject: [PATCH 057/106] Referenced signer passed to block producer --- validator_client/src/block_producer/mod.rs | 11 +++-------- validator_client/src/service.rs | 18 ++++++++++++------ validator_client/src/signer.rs | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index 8297469ba..77b719666 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -10,11 +10,6 @@ use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; #[derive(Debug, PartialEq)] pub enum Error { - SlotClockError, - SlotUnknowable, - EpochMapPoisoned, - SlotClockPoisoned, - EpochLengthIsZero, BeaconBlockNodeError(BeaconBlockNodeError), } @@ -34,7 +29,7 @@ pub enum ValidatorEvent { /// This struct contains the logic for requesting and signing beacon blocks for a validator. The /// validator can abstractly sign via the Signer trait object. -pub struct BlockProducer { +pub struct BlockProducer<'a, B: BeaconBlockNode, S: Signer> { /// The current fork. pub fork: Fork, /// The current slot to produce a block for. @@ -44,10 +39,10 @@ pub struct BlockProducer { /// The beacon node to connect to. pub beacon_node: Arc, /// The signer to sign the block. - pub signer: Arc, + pub signer: &'a S, } -impl BlockProducer { +impl<'a, B: BeaconBlockNode, S: Signer> BlockProducer<'a, B, S> { /// Produce a block at some slot. /// /// Assumes that a block is required at this slot (does not check the duties). diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index d6c0e6638..4c01d8967 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -299,17 +299,23 @@ impl Service { /// If there are any duties to process, spawn a separate thread and perform required actions. fn process_duties(&mut self) { if let Some(work) = self.duties_manager.get_current_work(self.current_slot) { - for (_public_key, work_type) in work { + for (signer_index, work_type) in work { if work_type.produce_block { // spawns a thread to produce a beacon block + let signers = self.duties_manager.signers.clone(); + let fork = self.fork.clone(); + let slot = self.current_slot.clone(); + let spec = self.spec.clone(); + let beacon_node = self.beacon_block_client.clone(); std::thread::spawn(move || { - /* + let signer = &signers[signer_index]; let block_producer = BlockProducer { - fork: self.fork, - slot: self.current_slot, - spec: self.spec.clone(), + fork, + slot, + spec, + beacon_node, + signer, }; - */ }); // TODO: Produce a beacon block in a new thread diff --git a/validator_client/src/signer.rs b/validator_client/src/signer.rs index 49dedbb33..4bbada08e 100644 --- a/validator_client/src/signer.rs +++ b/validator_client/src/signer.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use types::{Keypair, PublicKey, Signature}; /// Signs message using an internally-maintained private key. -pub trait Signer: Display + Send + Sync { +pub trait Signer: Display + Send + Sync + Clone { fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option; fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option; /// Returns a public key for the signer object. From 6e254551af043f39dadbb7070220f81dc3d0f7f5 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 15:58:31 +1100 Subject: [PATCH 058/106] Implement produce beacon block on gRPC beacon node server --- beacon_node/beacon_chain/src/lib.rs | 2 +- beacon_node/rpc/src/beacon_block.rs | 58 +++++++++++++++---- beacon_node/rpc/src/beacon_chain.rs | 15 ++++- .../testing_beacon_state_builder.rs | 2 +- validator_client/src/block_producer/mod.rs | 24 +++++++- validator_client/src/service.rs | 7 ++- 6 files changed, 90 insertions(+), 18 deletions(-) diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 48a42b941..234a96094 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -7,7 +7,7 @@ pub mod test_utils; pub use self::beacon_chain::{BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock}; pub use self::checkpoint::CheckPoint; -pub use self::errors::BeaconChainError; +pub use self::errors::{BeaconChainError, BlockProductionError}; pub use attestation_aggregator::Outcome as AggregationOutcome; pub use db; pub use fork_choice; diff --git a/beacon_node/rpc/src/beacon_block.rs b/beacon_node/rpc/src/beacon_block.rs index f6b426c18..e8b3cb01b 100644 --- a/beacon_node/rpc/src/beacon_block.rs +++ b/beacon_node/rpc/src/beacon_block.rs @@ -3,7 +3,7 @@ use crossbeam_channel; use eth2_libp2p::rpc::methods::BlockRootSlot; use eth2_libp2p::PubsubMessage; use futures::Future; -use grpcio::{RpcContext, UnarySink}; +use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink}; use network::NetworkMessage; use protos::services::{ BeaconBlock as BeaconBlockProto, ProduceBeaconBlockRequest, ProduceBeaconBlockResponse, @@ -11,10 +11,10 @@ use protos::services::{ }; use protos::services_grpc::BeaconBlockService; use slog::Logger; -use slog::{debug, error, info, warn}; -use ssz::{Decodable, TreeHash}; +use slog::{error, info, trace, warn}; +use ssz::{ssz_encode, Decodable, TreeHash}; use std::sync::Arc; -use types::{BeaconBlock, Hash256, Slot}; +use types::{BeaconBlock, Hash256, Signature, Slot}; #[derive(Clone)] pub struct BeaconBlockServiceInstance { @@ -31,11 +31,44 @@ impl BeaconBlockService for BeaconBlockServiceInstance { req: ProduceBeaconBlockRequest, sink: UnarySink, ) { - println!("producing at slot {}", req.get_slot()); + trace!(self.log, "Generating a beacon block"; "req" => format!("{:?}", req)); + + // decode the request + // TODO: requested slot currently unused, see: https://github.com/sigp/lighthouse/issues/336 + let _requested_slot = Slot::from(req.get_slot()); + let (randao_reveal, _index) = match Signature::ssz_decode(req.get_randao_reveal(), 0) { + Ok(v) => v, + Err(_) => { + // decode error, incorrect signature + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::InvalidArgument, + Some(format!("Invalid randao reveal signature")), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); + return ctx.spawn(f); + } + }; + + let produced_block = match self.chain.produce_block(randao_reveal) { + Ok((block, _state)) => block, + Err(e) => { + // could not produce a block + let log_clone = self.log.clone(); + warn!(self.log, "RPC Error"; "Error" => format!("Could not produce a block:{:?}",e)); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::Unknown, + Some(format!("Could not produce a block: {:?}", e)), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); + return ctx.spawn(f); + } + }; - // TODO: build a legit block. let mut block = BeaconBlockProto::new(); - block.set_ssz(b"cats".to_vec()); + block.set_ssz(ssz_encode(&produced_block)); let mut resp = ProduceBeaconBlockResponse::new(); resp.set_block(block); @@ -81,11 +114,16 @@ impl BeaconBlockService for BeaconBlockServiceInstance { slot: block.slot, }); - println!("Sending beacon block to gossipsub"); - self.network_chan.send(NetworkMessage::Publish { + match self.network_chan.send(NetworkMessage::Publish { topics: vec![topic], message, - }); + }) { + Ok(_) => {} + Err(_) => warn!( + self.log, + "Could not send published block to the network service" + ), + } resp.set_success(true); } else if outcome.is_invalid() { diff --git a/beacon_node/rpc/src/beacon_chain.rs b/beacon_node/rpc/src/beacon_chain.rs index 0551a8024..f21b8df7b 100644 --- a/beacon_node/rpc/src/beacon_chain.rs +++ b/beacon_node/rpc/src/beacon_chain.rs @@ -4,7 +4,8 @@ use beacon_chain::{ fork_choice::ForkChoice, parking_lot::RwLockReadGuard, slot_clock::SlotClock, - types::{BeaconState, ChainSpec}, + types::{BeaconState, ChainSpec, Signature}, + BlockProductionError, }; pub use beacon_chain::{BeaconChainError, BlockProcessingOutcome}; use types::BeaconBlock; @@ -17,6 +18,11 @@ pub trait BeaconChain: Send + Sync { fn process_block(&self, block: BeaconBlock) -> Result; + + fn produce_block( + &self, + randao_reveal: Signature, + ) -> Result<(BeaconBlock, BeaconState), BlockProductionError>; } impl BeaconChain for RawBeaconChain @@ -39,4 +45,11 @@ where ) -> Result { self.process_block(block) } + + fn produce_block( + &self, + randao_reveal: Signature, + ) -> Result<(BeaconBlock, BeaconState), BlockProductionError> { + self.produce_block(randao_reveal) + } } diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index 5e4cebd57..7c231b20b 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -120,7 +120,7 @@ impl TestingBeaconStateBuilder { }) .collect(); - let genesis_time = 1553776331; // arbitrary + let genesis_time = 1553918534; // arbitrary let mut state = BeaconState::genesis( genesis_time, diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index 77b719666..7def97e03 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -4,6 +4,7 @@ mod grpc; use self::beacon_block_node::{BeaconBlockNode, BeaconBlockNodeError}; pub use self::grpc::BeaconBlockGrpcClient; use crate::signer::Signer; +use slog::{error, info}; use ssz::{SignedRoot, TreeHash}; use std::sync::Arc; use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; @@ -23,8 +24,6 @@ pub enum ValidatorEvent { BeaconNodeUnableToProduceBlock(Slot), /// The signer failed to sign the message. SignerRejection(Slot), - /// The public key for this validator is not an active validator. - ValidatorIsUnknown(Slot), } /// This struct contains the logic for requesting and signing beacon blocks for a validator. The @@ -43,6 +42,25 @@ pub struct BlockProducer<'a, B: BeaconBlockNode, S: Signer> { } impl<'a, B: BeaconBlockNode, S: Signer> BlockProducer<'a, B, S> { + /// Handle outputs and results from block production. + pub fn handle_produce_block(&mut self, log: slog::Logger) { + match self.produce_block() { + Ok(ValidatorEvent::BlockProduced(_slot)) => { + info!(log, "Block produced"; "Validator" => format!("{}", self.signer)) + } + Err(e) => error!(log, "Block production error"; "Error" => format!("{:?}", e)), + Ok(ValidatorEvent::SignerRejection(_slot)) => { + error!(log, "Block production error"; "Error" => format!("Signer Could not sign the block")) + } + Ok(ValidatorEvent::SlashableBlockNotProduced(_slot)) => { + error!(log, "Block production error"; "Error" => format!("Rejected the block as it could have been slashed")) + } + Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(_slot)) => { + error!(log, "Block production error"; "Error" => format!("Beacon node was unable to produce a block")) + } + } + } + /// Produce a block at some slot. /// /// Assumes that a block is required at this slot (does not check the duties). @@ -53,7 +71,7 @@ impl<'a, B: BeaconBlockNode, S: Signer> BlockProducer<'a, B, S> { /// /// The slash-protection code is not yet implemented. There is zero protection against /// slashing. - fn produce_block(&mut self) -> Result { + pub fn produce_block(&mut self) -> Result { let epoch = self.slot.epoch(self.spec.slots_per_epoch); let randao_reveal = { diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 4c01d8967..621fb03a3 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -302,20 +302,23 @@ impl Service { for (signer_index, work_type) in work { if work_type.produce_block { // spawns a thread to produce a beacon block - let signers = self.duties_manager.signers.clone(); + let signers = self.duties_manager.signers.clone(); // this is an arc let fork = self.fork.clone(); let slot = self.current_slot.clone(); let spec = self.spec.clone(); let beacon_node = self.beacon_block_client.clone(); + let log = self.log.clone(); std::thread::spawn(move || { + info!(log, "Producing a block"; "Validator"=> format!("{}", signers[signer_index])); let signer = &signers[signer_index]; - let block_producer = BlockProducer { + let mut block_producer = BlockProducer { fork, slot, spec, beacon_node, signer, }; + block_producer.handle_produce_block(log); }); // TODO: Produce a beacon block in a new thread From 397e104f9b4b65649ef60922059d3a4b0f375b3e Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 16:02:09 +1100 Subject: [PATCH 059/106] Implement `Attestation` building in test harness --- beacon_node/beacon_chain/src/beacon_chain.rs | 33 +---- .../test_harness/src/beacon_chain_harness.rs | 114 ++++++++++-------- .../validator_harness/direct_beacon_node.rs | 2 +- eth2/types/src/attestation_duty.rs | 2 +- .../generate_deterministic_keypairs.rs | 2 +- 5 files changed, 69 insertions(+), 84 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 5e83fdd81..614cc46d8 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -1,4 +1,3 @@ -use crate::attestation_aggregator::{AttestationAggregator, Outcome as AggregationOutcome}; use crate::checkpoint::CheckPoint; use crate::errors::{BeaconChainError as Error, BlockProductionError}; use db::{ @@ -88,7 +87,6 @@ pub struct BeaconChain { pub block_store: Arc>, pub state_store: Arc>, pub slot_clock: U, - pub attestation_aggregator: RwLock, pub op_pool: OperationPool, canonical_head: RwLock, finalized_head: RwLock, @@ -131,7 +129,6 @@ where genesis_state.clone(), state_root, )); - let attestation_aggregator = RwLock::new(AttestationAggregator::new()); genesis_state.build_epoch_cache(RelativeEpoch::Previous, &spec)?; genesis_state.build_epoch_cache(RelativeEpoch::Current, &spec)?; @@ -142,7 +139,6 @@ where block_store, state_store, slot_clock, - attestation_aggregator, op_pool: OperationPool::new(), state: RwLock::new(genesis_state), finalized_head, @@ -477,7 +473,7 @@ where } /// Produce an `AttestationData` that is valid for the present `slot` and given `shard`. - pub fn produce_attestation(&self, shard: u64) -> Result { + pub fn produce_attestation_data(&self, shard: u64) -> Result { trace!("BeaconChain::produce_attestation: shard: {}", shard); let source_epoch = self.state.read().current_justified_epoch; let source_root = *self.state.read().get_block_root( @@ -509,33 +505,6 @@ where }) } - /// Validate a `FreeAttestation` and either: - /// - /// - Create a new `Attestation`. - /// - Aggregate it to an existing `Attestation`. - pub fn process_free_attestation( - &self, - free_attestation: FreeAttestation, - ) -> Result { - let aggregation_outcome = self - .attestation_aggregator - .write() - .process_free_attestation(&self.state.read(), &free_attestation, &self.spec)?; - - // return if the attestation is invalid - if !aggregation_outcome.valid { - return Ok(aggregation_outcome); - } - - // valid attestation, proceed with fork-choice logic - self.fork_choice.write().add_attestation( - free_attestation.validator_index, - &free_attestation.data.beacon_block_root, - &self.spec, - )?; - Ok(aggregation_outcome) - } - /// Accept a new attestation from the network. /// /// If valid, the attestation is added to the `op_pool` and aggregated with another attestation diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index 7d6a690e0..b7acac9e1 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -10,8 +10,6 @@ use log::debug; use rayon::prelude::*; use slot_clock::TestingSlotClock; use ssz::TreeHash; -use std::collections::HashSet; -use std::iter::FromIterator; use std::sync::Arc; use types::{test_utils::TestingBeaconStateBuilder, *}; @@ -137,51 +135,64 @@ impl BeaconChainHarness { slot } - /// Gather the `FreeAttestation`s from the valiators. - /// - /// Note: validators will only produce attestations _once per slot_. So, if you call this twice - /// you'll only get attestations on the first run. - pub fn gather_free_attesations(&mut self) -> Vec { + pub fn gather_attesations(&mut self) -> Vec { let present_slot = self.beacon_chain.present_slot(); + let state = self.beacon_chain.state.read(); - let attesting_validators = self - .beacon_chain - .state - .read() + let mut attestations = vec![]; + + for committee in state .get_crosslink_committees_at_slot(present_slot, &self.spec) .unwrap() - .iter() - .fold(vec![], |mut acc, c| { - acc.append(&mut c.committee.clone()); - acc - }); - let attesting_validators: HashSet = - HashSet::from_iter(attesting_validators.iter().cloned()); + { + for &validator in &committee.committee { + let duties = state + .get_attestation_duties(validator, &self.spec) + .unwrap() + .expect("Attesting validators by definition have duties"); - let free_attestations: Vec = self - .validators - .par_iter_mut() - .enumerate() - .filter_map(|(i, validator)| { - if attesting_validators.contains(&i) { - // Advance the validator slot. - validator.set_slot(present_slot); + // Obtain `AttestationData` from the beacon chain. + let data = self + .beacon_chain + .produce_attestation_data(duties.shard) + .unwrap(); - // Prompt the validator to produce an attestation (if required). - validator.produce_free_attestation().ok() - } else { - None - } - }) - .collect(); + // Produce an aggregate signature with a single signature. + let aggregate_signature = { + let message = AttestationDataAndCustodyBit { + data: data.clone(), + custody_bit: false, + } + .hash_tree_root(); + let domain = self.spec.get_domain( + state.slot.epoch(self.spec.slots_per_epoch), + Domain::Attestation, + &state.fork, + ); + let sig = + Signature::new(&message, domain, &self.validators[validator].keypair.sk); - debug!( - "Gathered {} FreeAttestations for slot {}.", - free_attestations.len(), - present_slot - ); + let mut agg_sig = AggregateSignature::new(); + agg_sig.add(&sig); - free_attestations + agg_sig + }; + + let mut aggregation_bitfield = Bitfield::with_capacity(committee.committee.len()); + let custody_bitfield = Bitfield::with_capacity(committee.committee.len()); + + aggregation_bitfield.set(duties.committee_index, true); + + attestations.push(Attestation { + aggregation_bitfield, + data, + custody_bitfield, + aggregate_signature, + }) + } + } + + attestations } /// Get the block from the proposer for the slot. @@ -200,7 +211,9 @@ impl BeaconChainHarness { // Ensure the validators slot clock is accurate. self.validators[proposer].set_slot(present_slot); - self.validators[proposer].produce_block().unwrap() + let block = self.validators[proposer].produce_block().unwrap(); + + block } /// Advances the chain with a BeaconBlock and attestations from all validators. @@ -219,20 +232,23 @@ impl BeaconChainHarness { }; debug!("...block processed by BeaconChain."); - debug!("Producing free attestations..."); + debug!("Producing attestations..."); // Produce new attestations. - let free_attestations = self.gather_free_attesations(); + let attestations = self.gather_attesations(); - debug!("Processing free attestations..."); + debug!("Processing {} attestations...", attestations.len()); - free_attestations.par_iter().for_each(|free_attestation| { - self.beacon_chain - .process_free_attestation(free_attestation.clone()) - .unwrap(); - }); + attestations + .par_iter() + .enumerate() + .for_each(|(i, attestation)| { + self.beacon_chain + .process_attestation(attestation.clone()) + .expect(&format!("Attestation {} invalid: {:?}", i, attestation)); + }); - debug!("Free attestations processed."); + debug!("Attestations processed."); block } diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs index fde8211ab..7853459d7 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs @@ -55,7 +55,7 @@ impl AttesterBeaconNode for DirectBeac _slot: Slot, shard: u64, ) -> Result, NodeError> { - match self.beacon_chain.produce_attestation(shard) { + match self.beacon_chain.produce_attestation_data(shard) { Ok(attestation_data) => Ok(Some(attestation_data)), Err(e) => Err(NodeError::RemoteFailure(format!("{:?}", e))), } diff --git a/eth2/types/src/attestation_duty.rs b/eth2/types/src/attestation_duty.rs index f6e86d263..80d912a83 100644 --- a/eth2/types/src/attestation_duty.rs +++ b/eth2/types/src/attestation_duty.rs @@ -1,7 +1,7 @@ use crate::*; use serde_derive::{Deserialize, Serialize}; -#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize)] pub struct AttestationDuty { pub slot: Slot, pub shard: Shard, diff --git a/eth2/types/src/test_utils/generate_deterministic_keypairs.rs b/eth2/types/src/test_utils/generate_deterministic_keypairs.rs index f2ce8709e..37880a988 100644 --- a/eth2/types/src/test_utils/generate_deterministic_keypairs.rs +++ b/eth2/types/src/test_utils/generate_deterministic_keypairs.rs @@ -19,7 +19,7 @@ pub fn generate_deterministic_keypairs(validator_count: usize) -> Vec { .collect::>() .par_iter() .map(|&i| { - let secret = int_to_bytes48(i as u64 + 1); + let secret = int_to_bytes48(i as u64 + 1000); let sk = SecretKey::from_bytes(&secret).unwrap(); let pk = PublicKey::from_secret_key(&sk); Keypair { sk, pk } From 25d1ddfbb0c50155cab86eb42db542eee2fe076a Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 16:34:43 +1100 Subject: [PATCH 060/106] Renames BeaconBlockNode to BeaconNodeBlock for future consistency --- .../attestation_grpc_client.rs | 45 ------------------- validator_client/src/attester_service/mod.rs | 7 ++- .../src/block_producer/beacon_block_node.rs | 33 -------------- validator_client/src/block_producer/grpc.rs | 21 ++++----- validator_client/src/block_producer/mod.rs | 16 +++---- validator_client/src/service.rs | 2 +- 6 files changed, 21 insertions(+), 103 deletions(-) delete mode 100644 validator_client/src/attester_service/attestation_grpc_client.rs delete mode 100644 validator_client/src/block_producer/beacon_block_node.rs diff --git a/validator_client/src/attester_service/attestation_grpc_client.rs b/validator_client/src/attester_service/attestation_grpc_client.rs deleted file mode 100644 index 502e51cac..000000000 --- a/validator_client/src/attester_service/attestation_grpc_client.rs +++ /dev/null @@ -1,45 +0,0 @@ -use protos::services_grpc::AttestationServiceClient; -use std::sync::Arc; - -use attester::{BeaconNode, BeaconNodeError, PublishOutcome}; -use protos::services::ProduceAttestationDataRequest; -use types::{Attestation, AttestationData, Slot}; - -pub struct AttestationGrpcClient { - client: Arc, -} - -impl AttestationGrpcClient { - pub fn new(client: Arc) -> Self { - Self { client } - } -} -/* -impl BeaconNode for AttestationGrpcClient { - fn produce_attestation_data( - &self, - slot: Slot, - shard: u64, - ) -> Result, BeaconNodeError> { - let mut req = ProduceAttestationDataRequest::new(); - req.set_slot(slot.as_u64()); - req.set_shard(shard); - - let reply = self - .client - .produce_attestation_data(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - - // TODO: return correct Attestation - Err(BeaconNodeError::DecodeFailure) - } - - fn publish_attestation( - &self, - attestation: Attestation, - ) -> Result { - // TODO: return correct PublishOutcome - Err(BeaconNodeError::DecodeFailure) - } -} -*/ diff --git a/validator_client/src/attester_service/mod.rs b/validator_client/src/attester_service/mod.rs index c14669445..1695ec0fb 100644 --- a/validator_client/src/attester_service/mod.rs +++ b/validator_client/src/attester_service/mod.rs @@ -1,4 +1,5 @@ -mod attestation_grpc_client; +mod grpc; +/* use attester::{Attester, BeaconNode, DutiesReader, PollOutcome as AttesterPollOutcome, Signer}; use slog::{error, info, warn, Logger}; use slot_clock::SlotClock; @@ -6,10 +7,8 @@ use std::time::Duration; pub use self::attestation_grpc_client::AttestationGrpcClient; -pub struct AttesterService {} -/* pub struct AttesterService { - // pub attester: Attester, + pub attester: Attester, pub poll_interval_millis: u64, pub log: Logger, } diff --git a/validator_client/src/block_producer/beacon_block_node.rs b/validator_client/src/block_producer/beacon_block_node.rs deleted file mode 100644 index 5a581a4a7..000000000 --- a/validator_client/src/block_producer/beacon_block_node.rs +++ /dev/null @@ -1,33 +0,0 @@ -use types::{BeaconBlock, Signature, Slot}; -#[derive(Debug, PartialEq, Clone)] -pub enum BeaconBlockNodeError { - RemoteFailure(String), - DecodeFailure, -} - -#[derive(Debug, PartialEq, Clone)] -pub enum PublishOutcome { - ValidBlock, - InvalidBlock(String), -} - -/// Defines the methods required to produce and publish blocks on a Beacon Node. Abstracts the -/// actual beacon node. -pub trait BeaconBlockNode: Send + Sync { - /// Request that the node produces a block. - /// - /// Returns Ok(None) if the Beacon Node is unable to produce at the given slot. - fn produce_beacon_block( - &self, - slot: Slot, - randao_reveal: &Signature, - ) -> Result, BeaconBlockNodeError>; - - /// Request that the node publishes a block. - /// - /// Returns `true` if the publish was successful. - fn publish_beacon_block( - &self, - block: BeaconBlock, - ) -> Result; -} diff --git a/validator_client/src/block_producer/grpc.rs b/validator_client/src/block_producer/grpc.rs index 23477ece1..ab0d5d421 100644 --- a/validator_client/src/block_producer/grpc.rs +++ b/validator_client/src/block_producer/grpc.rs @@ -1,4 +1,4 @@ -use super::beacon_block_node::*; +use super::beacon_node_block::*; use protos::services::{ BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, }; @@ -19,7 +19,7 @@ impl BeaconBlockGrpcClient { } } -impl BeaconBlockNode for BeaconBlockGrpcClient { +impl BeaconNodeBlock for BeaconBlockGrpcClient { /// Request a Beacon Node (BN) to produce a new block at the supplied slot. /// /// Returns `None` if it is not possible to produce at the supplied slot. For example, if the @@ -28,7 +28,7 @@ impl BeaconBlockNode for BeaconBlockGrpcClient { &self, slot: Slot, randao_reveal: &Signature, - ) -> Result, BeaconBlockNodeError> { + ) -> Result, BeaconNodeError> { // request a beacon block from the node let mut req = ProduceBeaconBlockRequest::new(); req.set_slot(slot.as_u64()); @@ -38,15 +38,15 @@ impl BeaconBlockNode for BeaconBlockGrpcClient { let reply = self .client .produce_beacon_block(&req) - .map_err(|err| BeaconBlockNodeError::RemoteFailure(format!("{:?}", err)))?; + .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; // format the reply if reply.has_block() { let block = reply.get_block(); let ssz = block.get_ssz(); - let (block, _i) = BeaconBlock::ssz_decode(&ssz, 0) - .map_err(|_| BeaconBlockNodeError::DecodeFailure)?; + let (block, _i) = + BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| BeaconNodeError::DecodeFailure)?; Ok(Some(block)) } else { @@ -58,10 +58,7 @@ impl BeaconBlockNode for BeaconBlockGrpcClient { /// /// Generally, this will be called after a `produce_beacon_block` call with a block that has /// been completed (signed) by the validator client. - fn publish_beacon_block( - &self, - block: BeaconBlock, - ) -> Result { + fn publish_beacon_block(&self, block: BeaconBlock) -> Result { let mut req = PublishBeaconBlockRequest::new(); let ssz = ssz_encode(&block); @@ -74,10 +71,10 @@ impl BeaconBlockNode for BeaconBlockGrpcClient { let reply = self .client .publish_beacon_block(&req) - .map_err(|err| BeaconBlockNodeError::RemoteFailure(format!("{:?}", err)))?; + .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; if reply.get_success() { - Ok(PublishOutcome::ValidBlock) + Ok(PublishOutcome::Valid) } else { // TODO: distinguish between different errors Ok(PublishOutcome::InvalidBlock("Publish failed".to_string())) diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index 7def97e03..09ce9bffa 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -1,7 +1,7 @@ -mod beacon_block_node; +mod beacon_node_block; mod grpc; -use self::beacon_block_node::{BeaconBlockNode, BeaconBlockNodeError}; +use self::beacon_node_block::{BeaconNodeBlock, BeaconNodeError}; pub use self::grpc::BeaconBlockGrpcClient; use crate::signer::Signer; use slog::{error, info}; @@ -11,7 +11,7 @@ use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; #[derive(Debug, PartialEq)] pub enum Error { - BeaconBlockNodeError(BeaconBlockNodeError), + BeaconNodeError(BeaconNodeError), } #[derive(Debug, PartialEq)] @@ -28,7 +28,7 @@ pub enum ValidatorEvent { /// This struct contains the logic for requesting and signing beacon blocks for a validator. The /// validator can abstractly sign via the Signer trait object. -pub struct BlockProducer<'a, B: BeaconBlockNode, S: Signer> { +pub struct BlockProducer<'a, B: BeaconNodeBlock, S: Signer> { /// The current fork. pub fork: Fork, /// The current slot to produce a block for. @@ -41,7 +41,7 @@ pub struct BlockProducer<'a, B: BeaconBlockNode, S: Signer> { pub signer: &'a S, } -impl<'a, B: BeaconBlockNode, S: Signer> BlockProducer<'a, B, S> { +impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { /// Handle outputs and results from block production. pub fn handle_produce_block(&mut self, log: slog::Logger) { match self.produce_block() { @@ -147,9 +147,9 @@ impl<'a, B: BeaconBlockNode, S: Signer> BlockProducer<'a, B, S> { } } -impl From for Error { - fn from(e: BeaconBlockNodeError) -> Error { - Error::BeaconBlockNodeError(e) +impl From for Error { + fn from(e: BeaconNodeError) -> Error { + Error::BeaconNodeError(e) } } diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 621fb03a3..fd24744ac 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -8,7 +8,7 @@ /// When a validator needs to either produce a block or sign an attestation, it requests the /// data from the beacon node and performs the signing before publishing the block to the beacon /// node. -use crate::attester_service::{AttestationGrpcClient, AttesterService}; +//use crate::attester_service::{AttestationGrpcClient, AttesterService}; use crate::block_producer::{BeaconBlockGrpcClient, BlockProducer}; use crate::config::Config as ValidatorConfig; use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap, UpdateOutcome}; From c107ebf9aa353f74559643d32295584eb43662fd Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 17:06:43 +1100 Subject: [PATCH 061/106] Initial implementation of AttestationProducer --- .../beacon_node_attestation.rs | 22 +++ validator_client/src/attester_service/grpc.rs | 45 +++++ validator_client/src/attester_service/mod.rs | 172 +++++++++++++----- .../src/block_producer/beacon_node_block.rs | 31 ++++ validator_client/src/signer.rs | 15 +- 5 files changed, 222 insertions(+), 63 deletions(-) create mode 100644 validator_client/src/attester_service/beacon_node_attestation.rs create mode 100644 validator_client/src/attester_service/grpc.rs create mode 100644 validator_client/src/block_producer/beacon_node_block.rs diff --git a/validator_client/src/attester_service/beacon_node_attestation.rs b/validator_client/src/attester_service/beacon_node_attestation.rs new file mode 100644 index 000000000..fa8d54031 --- /dev/null +++ b/validator_client/src/attester_service/beacon_node_attestation.rs @@ -0,0 +1,22 @@ +//TODO: generalise these enums to the crate +use super::block_producer::{BeaconNodeError, PublishOutcome}; + +/// Defines the methods required to produce and publish attestations on a Beacon Node. Abstracts the +/// actual beacon node. +pub trait BeaconNodeAttestation: Send + Sync { + /// Request that the node produces the required attestation data. + /// + fn produce_attestation_data( + &self, + slot: Slot, + shard: u64, + ) -> Result; + + /// Request that the node publishes a attestation. + /// + /// Returns `true` if the publish was successful. + fn publish_attestation( + &self, + attestation: Attestation, + ) -> Result; +} diff --git a/validator_client/src/attester_service/grpc.rs b/validator_client/src/attester_service/grpc.rs new file mode 100644 index 000000000..502e51cac --- /dev/null +++ b/validator_client/src/attester_service/grpc.rs @@ -0,0 +1,45 @@ +use protos::services_grpc::AttestationServiceClient; +use std::sync::Arc; + +use attester::{BeaconNode, BeaconNodeError, PublishOutcome}; +use protos::services::ProduceAttestationDataRequest; +use types::{Attestation, AttestationData, Slot}; + +pub struct AttestationGrpcClient { + client: Arc, +} + +impl AttestationGrpcClient { + pub fn new(client: Arc) -> Self { + Self { client } + } +} +/* +impl BeaconNode for AttestationGrpcClient { + fn produce_attestation_data( + &self, + slot: Slot, + shard: u64, + ) -> Result, BeaconNodeError> { + let mut req = ProduceAttestationDataRequest::new(); + req.set_slot(slot.as_u64()); + req.set_shard(shard); + + let reply = self + .client + .produce_attestation_data(&req) + .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; + + // TODO: return correct Attestation + Err(BeaconNodeError::DecodeFailure) + } + + fn publish_attestation( + &self, + attestation: Attestation, + ) -> Result { + // TODO: return correct PublishOutcome + Err(BeaconNodeError::DecodeFailure) + } +} +*/ diff --git a/validator_client/src/attester_service/mod.rs b/validator_client/src/attester_service/mod.rs index 1695ec0fb..7178e28d7 100644 --- a/validator_client/src/attester_service/mod.rs +++ b/validator_client/src/attester_service/mod.rs @@ -1,59 +1,131 @@ mod grpc; -/* -use attester::{Attester, BeaconNode, DutiesReader, PollOutcome as AttesterPollOutcome, Signer}; -use slog::{error, info, warn, Logger}; -use slot_clock::SlotClock; -use std::time::Duration; +mod beacon_node_attestation; -pub use self::attestation_grpc_client::AttestationGrpcClient; +use std::sync::Arc; +use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; -pub struct AttesterService { - pub attester: Attester, - pub poll_interval_millis: u64, - pub log: Logger, +#[derive(Debug, PartialEq)] +pub enum Error { + BeaconNodeError(BeaconNodeError), } +/// This struct contains the logic for requesting and signing beacon attestations for a validator. The +/// validator can abstractly sign via the Signer trait object. +pub struct AttestationProducer<'a, B: BeaconNodeAttestation, S: Signer> { + /// The current fork. + pub fork: Fork, + /// The current slot to produce an attestation for. + pub slot: Slot, + /// The current epoch. + pub spec: Arc, + /// The beacon node to connect to. + pub beacon_node: Arc, + /// The signer to sign the block. + pub signer: &'a S, +} -impl AttesterService { - /// Run a loop which polls the Attester each `poll_interval_millis` millseconds. +impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { + /// Handle outputs and results from attestation production. + pub fn handle_produce_attestation(&mut self, log: slog::Logger) { + match self.produce_attestation() { + Ok(ValidatorEvent::AttestationProduced(_slot)) => { + info!(log, "Attestation produced"; "Validator" => format!("{}", self.signer)) + } + Err(e) => error!(log, "Attestation production error"; "Error" => format!("{:?}", e)), + Ok(ValidatorEvent::SignerRejection(_slot)) => { + error!(log, "Attestation production error"; "Error" => format!("Signer could not sign the attestation")) + } + Ok(ValidatorEvent::SlashableAttestationNotProduced(_slot)) => { + error!(log, "Attestation production error"; "Error" => format!("Rejected the attestation as it could have been slashed")) + } + Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(_slot)) => { + error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to produce an attestation")) + } + } + } + + /// Produce an attestation, sign it and send it back /// - /// Logs the results of the polls. - pub fn run(&mut self) { - loop { - /* We don't do the polling any more... - match self.attester.poll() { - Err(error) => { - error!(self.log, "Attester poll error"; "error" => format!("{:?}", error)) + /// Assumes that an attestation is required at this slot (does not check the duties). + /// + /// Ensures the message is not slashable. + /// + /// !!! UNSAFE !!! + /// + /// The slash-protection code is not yet implemented. There is zero protection against + /// slashing. + pub fn produce_attestation(&mut self) -> Result { + let epoch = self.slot.epoch(self.spec.slots_per_epoch); + + if let Some(attestation) = self + .beacon_node + .produce_attestation_data(self.slot, self.shard)? + { + if self.safe_to_produce(&attestation) { + let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork); + if let Some(attestation) = self.sign_attestation(attestation, domain) { + self.beacon_node.publish_attestation(attestation)?; + Ok(ValidatorEvent::AttestationProduced(self.slot)) + } else { + Ok(ValidatorEvent::SignerRejection(self.slot)) } - Ok(AttesterPollOutcome::AttestationProduced(slot)) => { - info!(self.log, "Produced Attestation"; "slot" => slot) - } - Ok(AttesterPollOutcome::SlashableAttestationNotProduced(slot)) => { - warn!(self.log, "Slashable attestation was not produced"; "slot" => slot) - } - Ok(AttesterPollOutcome::AttestationNotRequired(slot)) => { - info!(self.log, "Attestation not required"; "slot" => slot) - } - Ok(AttesterPollOutcome::ProducerDutiesUnknown(slot)) => { - error!(self.log, "Attestation duties unknown"; "slot" => slot) - } - Ok(AttesterPollOutcome::SlotAlreadyProcessed(slot)) => { - warn!(self.log, "Attempted to re-process slot"; "slot" => slot) - } - Ok(AttesterPollOutcome::BeaconNodeUnableToProduceAttestation(slot)) => { - error!(self.log, "Beacon node unable to produce attestation"; "slot" => slot) - } - Ok(AttesterPollOutcome::SignerRejection(slot)) => { - error!(self.log, "The cryptographic signer refused to sign the attestation"; "slot" => slot) - } - Ok(AttesterPollOutcome::ValidatorIsUnknown(slot)) => { - error!(self.log, "The Beacon Node does not recognise the validator"; "slot" => slot) - } - }; - */ -println!("Legacy polling still happening..."); -std::thread::sleep(Duration::from_millis(self.poll_interval_millis)); + } else { + Ok(ValidatorEvent::SlashableAttestationNotProduced(self.slot)) + } + } else { + Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(self.slot)) + } + } + + /// Consumes an attestation, returning the attestation signed by the validators private key. + /// + /// Important: this function will not check to ensure the attestation is not slashable. This must be + /// done upstream. + fn sign_attestation(&mut self, mut attestation: Attestation, duties: AttestationDuties, domain: u64) -> Option { + self.store_produce(&attestation); + + // build the aggregate signature + let aggregate_sig = { + let message = AttestationDataAndCustodyBit { + data: attestation.clone(), + custody_bit: false, + }.hash_tree_root(); + + let sig = self.signer.sign_message(&message, domain)?; + + let mut agg_sig = AggregateSignature::new(); + agg_sig.add(&sig); + agg_sig + } + + let mut aggregation_bitfield = Bitfield::with_capacity(duties.comitee_size); + let custody_bitfield = Bitfield::with_capacity(duties.committee_size); + aggregation_bitfield.set(duties.committee_index, true); + + Attestation { + aggregation_bitfield, + data, + custody_bitfield, + aggregate_signature, + } + } + + /// Returns `true` if signing an attestation is safe (non-slashable). + /// + /// !!! UNSAFE !!! + /// + /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. + fn safe_to_produce(&self, _block: &Attestation) -> bool { + //TODO: Implement slash protection + true + } + + /// Record that an attestation was produced so that slashable votes may not be made in the future. + /// + /// !!! UNSAFE !!! + /// + /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. + fn store_produce(&mut self, _block: &BeaconBlock) { + // TODO: Implement slash protection + } } -} -} -*/ diff --git a/validator_client/src/block_producer/beacon_node_block.rs b/validator_client/src/block_producer/beacon_node_block.rs new file mode 100644 index 000000000..65ccb2104 --- /dev/null +++ b/validator_client/src/block_producer/beacon_node_block.rs @@ -0,0 +1,31 @@ +use types::{BeaconBlock, Signature, Slot}; +#[derive(Debug, PartialEq, Clone)] +pub enum BeaconNodeError { + RemoteFailure(String), + DecodeFailure, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum PublishOutcome { + Valid, + InvalidBlock(String), + InvalidAttestation(String), +} + +/// Defines the methods required to produce and publish blocks on a Beacon Node. Abstracts the +/// actual beacon node. +pub trait BeaconNodeBlock: Send + Sync { + /// Request that the node produces a block. + /// + /// Returns Ok(None) if the Beacon Node is unable to produce at the given slot. + fn produce_beacon_block( + &self, + slot: Slot, + randao_reveal: &Signature, + ) -> Result, BeaconNodeError>; + + /// Request that the node publishes a block. + /// + /// Returns `true` if the publish was successful. + fn publish_beacon_block(&self, block: BeaconBlock) -> Result; +} diff --git a/validator_client/src/signer.rs b/validator_client/src/signer.rs index 4bbada08e..018142322 100644 --- a/validator_client/src/signer.rs +++ b/validator_client/src/signer.rs @@ -3,8 +3,7 @@ use types::{Keypair, PublicKey, Signature}; /// Signs message using an internally-maintained private key. pub trait Signer: Display + Send + Sync + Clone { - fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option; - fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option; + fn sign_message(&self, message: &[u8], domain: u64) -> Option; /// Returns a public key for the signer object. fn to_public(&self) -> PublicKey; } @@ -16,17 +15,7 @@ impl Signer for Keypair { self.pk.clone() } - fn sign_block_proposal(&self, message: &[u8], domain: u64) -> Option { + fn sign_message(&self, message: &[u8], domain: u64) -> Option { Some(Signature::new(message, domain, &self.sk)) } - - fn sign_randao_reveal(&self, message: &[u8], domain: u64) -> Option { - Some(Signature::new(message, domain, &self.sk)) - } - - /* - fn sign_attestation_message(&self, message: &[u8], domain: u64) -> Option { - Some(Signature::new(message, domain, &self.sk)) - } - */ } From 7b3f317abfe3439e20f3148596fec58d42c33016 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 17:12:43 +1100 Subject: [PATCH 062/106] Fix bug with attestation production It was being produced with the wrong source root. I will raise an issue on the spec as it's a tricky one. --- beacon_node/beacon_chain/src/beacon_chain.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 614cc46d8..45a28b782 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -475,11 +475,7 @@ where /// Produce an `AttestationData` that is valid for the present `slot` and given `shard`. pub fn produce_attestation_data(&self, shard: u64) -> Result { trace!("BeaconChain::produce_attestation: shard: {}", shard); - let source_epoch = self.state.read().current_justified_epoch; - let source_root = *self.state.read().get_block_root( - source_epoch.start_slot(self.spec.slots_per_epoch), - &self.spec, - )?; + let state = self.state.read(); let target_root = *self.state.read().get_block_root( self.state @@ -500,8 +496,8 @@ where epoch: self.state.read().slot.epoch(self.spec.slots_per_epoch), crosslink_data_root: Hash256::zero(), }, - source_epoch, - source_root, + source_epoch: state.current_justified_epoch, + source_root: state.current_justified_root, }) } From dbcc88ad67aff419a9af00037809d599dc3dc1e9 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 17:13:23 +1100 Subject: [PATCH 063/106] Ensure BitVec is initialized using a multiple of 8 I found it was panic-ing when supplied a non-power-of-zero len. --- beacon_node/beacon_chain/src/beacon_chain.rs | 5 ++++- eth2/utils/boolean-bitfield/src/lib.rs | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 45a28b782..7c2336a28 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -692,7 +692,10 @@ where }, }; - trace!("BeaconChain::produce_block: updating state for new block.",); + debug!( + "Produced block with {} attestations, updating state.", + block.body.attestations.len() + ); per_block_processing_without_verifying_block_signature(&mut state, &block, &self.spec)?; diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index cdd0bc3d7..d90b28dc5 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -33,9 +33,11 @@ impl BooleanBitfield { } /// Create a new bitfield with the given length `initial_len` and all values set to `bit`. - pub fn from_elem(inital_len: usize, bit: bool) -> Self { + pub fn from_elem(initial_len: usize, bit: bool) -> Self { + // BitVec can panic if we don't set the len to be a multiple of 8. + let len = ((initial_len + 7) / 8) * 8; Self { - 0: BitVec::from_elem(inital_len, bit), + 0: BitVec::from_elem(len, bit), } } From bb8938c564d77a1ca5e8d18958f3ce6d9a75f7ab Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 17:14:38 +1100 Subject: [PATCH 064/106] Use AttestationDuty in epoch duties --- eth2/types/src/attestation_duty.rs | 1 + validator_client/src/duties/epoch_duties.rs | 12 +++--------- validator_client/src/duties/grpc.rs | 12 +++++++++--- validator_client/src/duties/mod.rs | 1 - 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/eth2/types/src/attestation_duty.rs b/eth2/types/src/attestation_duty.rs index 80d912a83..9612dd868 100644 --- a/eth2/types/src/attestation_duty.rs +++ b/eth2/types/src/attestation_duty.rs @@ -6,4 +6,5 @@ pub struct AttestationDuty { pub slot: Slot, pub shard: Shard, pub committee_index: usize, + pub comittee_size: usize, } diff --git a/validator_client/src/duties/epoch_duties.rs b/validator_client/src/duties/epoch_duties.rs index 0a4f73f72..d0753a2a6 100644 --- a/validator_client/src/duties/epoch_duties.rs +++ b/validator_client/src/duties/epoch_duties.rs @@ -23,9 +23,7 @@ pub struct WorkInfo { #[derive(Debug, PartialEq, Clone, Copy, Default)] pub struct EpochDuty { pub block_production_slot: Option, - pub attestation_slot: Slot, - pub attestation_shard: u64, - pub committee_index: u64, + pub attestation_duty: AttestationDuty, } impl EpochDuty { @@ -39,12 +37,8 @@ impl EpochDuty { // if the validator is required to attest to a shard, create the data let mut attestation_duty = None; - if self.attestation_slot == slot { - attestation_duty = Some(AttestationDuty { - slot, - shard: self.attestation_shard, - committee_index: self.committee_index as usize, - }); + if self.attestation_duty.slot == slot { + attestation_duty = self.attestation_duty } if produce_block | attestation_duty.is_some() { diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index 66bf368a2..f0d892e98 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -47,11 +47,17 @@ impl BeaconNodeDuties for ValidatorServiceClient { None } }; + + let attestation_duty = AttestationDuty { + slot: Slot::from(active_duty.get_attestation_slot()), + shard: active_duty.get_attestation_shard(), + committee_index: active_duty.get_committee_index(), + comittee_size: 10, + } + let epoch_duty = EpochDuty { block_production_slot, - attestation_slot: Slot::from(active_duty.get_attestation_slot()), - attestation_shard: active_duty.get_attestation_shard(), - committee_index: active_duty.get_committee_index(), + attestation_duty, }; epoch_duties.insert(pub_keys[index].clone(), Some(epoch_duty)); } diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index 9f0998567..d52cc3254 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -30,7 +30,6 @@ pub enum UpdateOutcome { #[derive(Debug, PartialEq)] pub enum Error { DutiesMapPoisoned, - EpochMapPoisoned, BeaconNodeDutiesError(BeaconNodeDutiesError), UnknownEpoch, UnknownValidator, From ed6d0b46d03b088f5074b3b17c723723c19d9437 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 17:16:04 +1100 Subject: [PATCH 065/106] Add committee len to AttesterDuties --- eth2/types/src/attestation_duty.rs | 1 + eth2/types/src/beacon_state/epoch_cache.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/eth2/types/src/attestation_duty.rs b/eth2/types/src/attestation_duty.rs index 80d912a83..299fdd44c 100644 --- a/eth2/types/src/attestation_duty.rs +++ b/eth2/types/src/attestation_duty.rs @@ -6,4 +6,5 @@ pub struct AttestationDuty { pub slot: Slot, pub shard: Shard, pub committee_index: usize, + pub committee_len: usize, } diff --git a/eth2/types/src/beacon_state/epoch_cache.rs b/eth2/types/src/beacon_state/epoch_cache.rs index 32d9a643e..62df90271 100644 --- a/eth2/types/src/beacon_state/epoch_cache.rs +++ b/eth2/types/src/beacon_state/epoch_cache.rs @@ -92,6 +92,7 @@ impl EpochCache { slot, shard, committee_index: k, + committee_len: crosslink_committee.committee.len(), }; attestation_duties[*validator_index] = Some(attestation_duty) } From 64507950dd1193d3c5032c33afe496b83975e227 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 17:31:58 +1100 Subject: [PATCH 066/106] Use committe_len in test_harness --- .../beacon_chain/test_harness/src/beacon_chain_harness.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index b7acac9e1..33c12d7c7 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -178,8 +178,8 @@ impl BeaconChainHarness { agg_sig }; - let mut aggregation_bitfield = Bitfield::with_capacity(committee.committee.len()); - let custody_bitfield = Bitfield::with_capacity(committee.committee.len()); + let mut aggregation_bitfield = Bitfield::with_capacity(duties.committee_len); + let custody_bitfield = Bitfield::with_capacity(duties.committee_len); aggregation_bitfield.set(duties.committee_index, true); From 145cabc427da8fe460375aa11e37e988d868802e Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 17:56:43 +1100 Subject: [PATCH 067/106] Build validator client AttestationProducer --- .../beacon_node_attestation.rs | 3 +- validator_client/src/attester_service/mod.rs | 95 ++++++++++++------- validator_client/src/block_producer/mod.rs | 21 ++-- validator_client/src/duties/epoch_duties.rs | 4 +- validator_client/src/duties/grpc.rs | 12 +-- 5 files changed, 83 insertions(+), 52 deletions(-) diff --git a/validator_client/src/attester_service/beacon_node_attestation.rs b/validator_client/src/attester_service/beacon_node_attestation.rs index fa8d54031..b5ff777de 100644 --- a/validator_client/src/attester_service/beacon_node_attestation.rs +++ b/validator_client/src/attester_service/beacon_node_attestation.rs @@ -1,5 +1,6 @@ //TODO: generalise these enums to the crate -use super::block_producer::{BeaconNodeError, PublishOutcome}; +use crate::block_producer::{BeaconNodeError, PublishOutcome}; +use types::{Attestation, AttestationData, Slot}; /// Defines the methods required to produce and publish attestations on a Beacon Node. Abstracts the /// actual beacon node. diff --git a/validator_client/src/attester_service/mod.rs b/validator_client/src/attester_service/mod.rs index 20488b1c1..7b2174b0c 100644 --- a/validator_client/src/attester_service/mod.rs +++ b/validator_client/src/attester_service/mod.rs @@ -1,22 +1,38 @@ -mod grpc; mod beacon_node_attestation; +mod grpc; use std::sync::Arc; use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; -use super::block_proposer::beacon_node_block::BeaconNodeError; +//TODO: Move these higher up in the crate +use super::block_producer::{BeaconNodeError, ValidatorEvent}; +use crate::signer::Signer; +use beacon_node_attestation::BeaconNodeAttestation; +use slog::{error, info, warn}; +use ssz::TreeHash; +use types::{ + AggregateSignature, Attestation, AttestationData, AttestationDataAndCustodyBit, + AttestationDuty, Bitfield, +}; +//TODO: Group these errors at a crate level #[derive(Debug, PartialEq)] pub enum Error { BeaconNodeError(BeaconNodeError), } +impl From for Error { + fn from(e: BeaconNodeError) -> Error { + Error::BeaconNodeError(e) + } +} + /// This struct contains the logic for requesting and signing beacon attestations for a validator. The /// validator can abstractly sign via the Signer trait object. pub struct AttestationProducer<'a, B: BeaconNodeAttestation, S: Signer> { /// The current fork. pub fork: Fork, - /// The current slot to produce an attestation for. - pub slot: Slot, + /// The attestation duty to perform. + pub duty: AttestationDuty, /// The current epoch. pub spec: Arc, /// The beacon node to connect to. @@ -42,6 +58,9 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(_slot)) => { error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to produce an attestation")) } + Ok(v) => { + warn!(log, "Unknown result for attestation production"; "Error" => format!("{:?}",v)) + } } } @@ -56,25 +75,23 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// The slash-protection code is not yet implemented. There is zero protection against /// slashing. pub fn produce_attestation(&mut self) -> Result { - let epoch = self.slot.epoch(self.spec.slots_per_epoch); + let epoch = self.duty.slot.epoch(self.spec.slots_per_epoch); - if let Some(attestation) = self + let attestation = self .beacon_node - .produce_attestation_data(self.slot, self.shard)? - { - if self.safe_to_produce(&attestation) { - let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork); - if let Some(attestation) = self.sign_attestation(attestation, domain) { - self.beacon_node.publish_attestation(attestation)?; - Ok(ValidatorEvent::AttestationProduced(self.slot)) - } else { - Ok(ValidatorEvent::SignerRejection(self.slot)) - } + .produce_attestation_data(self.duty.slot, self.duty.shard)?; + if self.safe_to_produce(&attestation) { + let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork); + if let Some(attestation) = self.sign_attestation(attestation, self.duty, domain) { + self.beacon_node.publish_attestation(attestation)?; + Ok(ValidatorEvent::AttestationProduced(self.duty.slot)) } else { - Ok(ValidatorEvent::SlashableAttestationNotProduced(self.slot)) + Ok(ValidatorEvent::SignerRejection(self.duty.slot)) } } else { - Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(self.slot)) + Ok(ValidatorEvent::SlashableAttestationNotProduced( + self.duty.slot, + )) } } @@ -82,33 +99,39 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// /// Important: this function will not check to ensure the attestation is not slashable. This must be /// done upstream. - fn sign_attestation(&mut self, mut attestation: Attestation, duties: AttestationDuties, domain: u64) -> Option { + fn sign_attestation( + &mut self, + mut attestation: AttestationData, + duties: AttestationDuty, + domain: u64, + ) -> Option { self.store_produce(&attestation); // build the aggregate signature - let aggregate_sig = { + let aggregate_signature = { let message = AttestationDataAndCustodyBit { - data: attestation.clone(), - custody_bit: false, - }.hash_tree_root(); + data: attestation.clone(), + custody_bit: false, + } + .hash_tree_root(); let sig = self.signer.sign_message(&message, domain)?; let mut agg_sig = AggregateSignature::new(); agg_sig.add(&sig); agg_sig - } + }; - let mut aggregation_bitfield = Bitfield::with_capacity(duties.comitee_size); - let custody_bitfield = Bitfield::with_capacity(duties.committee_size); - aggregation_bitfield.set(duties.committee_index, true); + let mut aggregation_bitfield = Bitfield::with_capacity(duties.committee_len); + let custody_bitfield = Bitfield::with_capacity(duties.committee_len); + aggregation_bitfield.set(duties.committee_index, true); - Attestation { - aggregation_bitfield, - data, - custody_bitfield, - aggregate_signature, - } + Some(Attestation { + aggregation_bitfield, + data: attestation, + custody_bitfield, + aggregate_signature, + }) } /// Returns `true` if signing an attestation is safe (non-slashable). @@ -116,8 +139,8 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// !!! UNSAFE !!! /// /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn safe_to_produce(&self, _block: &Attestation) -> bool { - //TODO: Implement slash protection + fn safe_to_produce(&self, _attestation: &AttestationData) -> bool { + //TODO: Implement slash protection true } @@ -126,7 +149,7 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// !!! UNSAFE !!! /// /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn store_produce(&mut self, _block: &BeaconBlock) { + fn store_produce(&mut self, _attestation: &AttestationData) { // TODO: Implement slash protection } } diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index 09ce9bffa..592c0b919 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -1,10 +1,11 @@ mod beacon_node_block; mod grpc; -use self::beacon_node_block::{BeaconNodeBlock, BeaconNodeError}; +use self::beacon_node_block::BeaconNodeBlock; +pub use self::beacon_node_block::{BeaconNodeError, PublishOutcome}; pub use self::grpc::BeaconBlockGrpcClient; use crate::signer::Signer; -use slog::{error, info}; +use slog::{error, info, warn}; use ssz::{SignedRoot, TreeHash}; use std::sync::Arc; use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; @@ -18,10 +19,16 @@ pub enum Error { pub enum ValidatorEvent { /// A new block was produced. BlockProduced(Slot), + /// A new attestation was produced. + AttestationProduced(Slot), /// A block was not produced as it would have been slashable. SlashableBlockNotProduced(Slot), + /// An attestation was not produced as it would have been slashable. + SlashableAttestationNotProduced(Slot), /// The Beacon Node was unable to produce a block at that slot. BeaconNodeUnableToProduceBlock(Slot), + /// The Beacon Node was unable to produce an attestation at that slot. + BeaconNodeUnableToProduceAttestation(Slot), /// The signer failed to sign the message. SignerRejection(Slot), } @@ -58,6 +65,9 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(_slot)) => { error!(log, "Block production error"; "Error" => format!("Beacon node was unable to produce a block")) } + Ok(v) => { + warn!(log, "Unknown result for block production"; "Error" => format!("{:?}",v)) + } } } @@ -76,7 +86,7 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { let randao_reveal = { let message = epoch.hash_tree_root(); - let randao_reveal = match self.signer.sign_randao_reveal( + let randao_reveal = match self.signer.sign_message( &message, self.spec.get_domain(epoch, Domain::Randao, &self.fork), ) { @@ -113,10 +123,7 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option { self.store_produce(&block); - match self - .signer - .sign_block_proposal(&block.signed_root()[..], domain) - { + match self.signer.sign_message(&block.signed_root()[..], domain) { None => None, Some(signature) => { block.signature = signature; diff --git a/validator_client/src/duties/epoch_duties.rs b/validator_client/src/duties/epoch_duties.rs index d0753a2a6..692a8d6a6 100644 --- a/validator_client/src/duties/epoch_duties.rs +++ b/validator_client/src/duties/epoch_duties.rs @@ -38,7 +38,7 @@ impl EpochDuty { // if the validator is required to attest to a shard, create the data let mut attestation_duty = None; if self.attestation_duty.slot == slot { - attestation_duty = self.attestation_duty + attestation_duty = Some(self.attestation_duty) } if produce_block | attestation_duty.is_some() { @@ -60,7 +60,7 @@ impl fmt::Display for EpochDuty { write!( f, "produce block slot: {}, attestation slot: {}, attestation shard: {}", - display_block, self.attestation_slot, self.attestation_shard + display_block, self.attestation_duty.slot, self.attestation_duty.shard ) } } diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index f0d892e98..ab87b602e 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -6,7 +6,7 @@ use protos::services_grpc::ValidatorServiceClient; use ssz::ssz_encode; use std::collections::HashMap; use std::time::Duration; -use types::{Epoch, PublicKey, Slot}; +use types::{AttestationDuty, Epoch, PublicKey, Slot}; impl BeaconNodeDuties for ValidatorServiceClient { /// Requests all duties (block signing and committee attesting) from the Beacon Node (BN). @@ -49,11 +49,11 @@ impl BeaconNodeDuties for ValidatorServiceClient { }; let attestation_duty = AttestationDuty { - slot: Slot::from(active_duty.get_attestation_slot()), - shard: active_duty.get_attestation_shard(), - committee_index: active_duty.get_committee_index(), - comittee_size: 10, - } + slot: Slot::from(active_duty.get_attestation_slot()), + shard: active_duty.get_attestation_shard(), + committee_index: active_duty.get_committee_index() as usize, + committee_len: 10, + }; let epoch_duty = EpochDuty { block_production_slot, From d12ddae24763683eac3f9844719de8bcbc9e5ecb Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 18:14:04 +1100 Subject: [PATCH 068/106] Builds attestation grpc implemention --- protos/src/services.proto | 28 +--- .../beacon_node_attestation.rs | 23 --- validator_client/src/attester_service/grpc.rs | 45 ----- validator_client/src/attester_service/mod.rs | 155 ------------------ validator_client/src/block_producer/grpc.rs | 1 + validator_client/src/main.rs | 2 +- 6 files changed, 8 insertions(+), 246 deletions(-) delete mode 100644 validator_client/src/attester_service/beacon_node_attestation.rs delete mode 100644 validator_client/src/attester_service/grpc.rs delete mode 100644 validator_client/src/attester_service/mod.rs diff --git a/protos/src/services.proto b/protos/src/services.proto index 7cd653a60..c5bd8a91d 100644 --- a/protos/src/services.proto +++ b/protos/src/services.proto @@ -141,7 +141,11 @@ message ProduceAttestationDataResponse { } message PublishAttestationRequest { - FreeAttestation free_attestation = 1; + Attestation attestation = 1; +} + +message Attestation { + bytes ssz = 1; } message PublishAttestationResponse { @@ -149,26 +153,6 @@ message PublishAttestationResponse { bytes msg = 2; } -message Crosslink { - uint64 epoch = 1; - bytes crosslink_data_root = 2; - -} - message AttestationData { - uint64 slot = 1; - uint64 shard = 2; - bytes beacon_block_root = 3; - bytes epoch_boundary_root = 4; - bytes crosslink_data_root = 5; - Crosslink latest_crosslink = 6; - uint64 justified_epoch = 7; - bytes justified_block_root = 8; - -} - -message FreeAttestation { - AttestationData data = 1; - bytes signature = 2; - uint64 validator_index = 3; + bytes ssz = 1; } diff --git a/validator_client/src/attester_service/beacon_node_attestation.rs b/validator_client/src/attester_service/beacon_node_attestation.rs deleted file mode 100644 index b5ff777de..000000000 --- a/validator_client/src/attester_service/beacon_node_attestation.rs +++ /dev/null @@ -1,23 +0,0 @@ -//TODO: generalise these enums to the crate -use crate::block_producer::{BeaconNodeError, PublishOutcome}; -use types::{Attestation, AttestationData, Slot}; - -/// Defines the methods required to produce and publish attestations on a Beacon Node. Abstracts the -/// actual beacon node. -pub trait BeaconNodeAttestation: Send + Sync { - /// Request that the node produces the required attestation data. - /// - fn produce_attestation_data( - &self, - slot: Slot, - shard: u64, - ) -> Result; - - /// Request that the node publishes a attestation. - /// - /// Returns `true` if the publish was successful. - fn publish_attestation( - &self, - attestation: Attestation, - ) -> Result; -} diff --git a/validator_client/src/attester_service/grpc.rs b/validator_client/src/attester_service/grpc.rs deleted file mode 100644 index 502e51cac..000000000 --- a/validator_client/src/attester_service/grpc.rs +++ /dev/null @@ -1,45 +0,0 @@ -use protos::services_grpc::AttestationServiceClient; -use std::sync::Arc; - -use attester::{BeaconNode, BeaconNodeError, PublishOutcome}; -use protos::services::ProduceAttestationDataRequest; -use types::{Attestation, AttestationData, Slot}; - -pub struct AttestationGrpcClient { - client: Arc, -} - -impl AttestationGrpcClient { - pub fn new(client: Arc) -> Self { - Self { client } - } -} -/* -impl BeaconNode for AttestationGrpcClient { - fn produce_attestation_data( - &self, - slot: Slot, - shard: u64, - ) -> Result, BeaconNodeError> { - let mut req = ProduceAttestationDataRequest::new(); - req.set_slot(slot.as_u64()); - req.set_shard(shard); - - let reply = self - .client - .produce_attestation_data(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - - // TODO: return correct Attestation - Err(BeaconNodeError::DecodeFailure) - } - - fn publish_attestation( - &self, - attestation: Attestation, - ) -> Result { - // TODO: return correct PublishOutcome - Err(BeaconNodeError::DecodeFailure) - } -} -*/ diff --git a/validator_client/src/attester_service/mod.rs b/validator_client/src/attester_service/mod.rs deleted file mode 100644 index 7b2174b0c..000000000 --- a/validator_client/src/attester_service/mod.rs +++ /dev/null @@ -1,155 +0,0 @@ -mod beacon_node_attestation; -mod grpc; - -use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; -//TODO: Move these higher up in the crate -use super::block_producer::{BeaconNodeError, ValidatorEvent}; -use crate::signer::Signer; -use beacon_node_attestation::BeaconNodeAttestation; -use slog::{error, info, warn}; -use ssz::TreeHash; -use types::{ - AggregateSignature, Attestation, AttestationData, AttestationDataAndCustodyBit, - AttestationDuty, Bitfield, -}; - -//TODO: Group these errors at a crate level -#[derive(Debug, PartialEq)] -pub enum Error { - BeaconNodeError(BeaconNodeError), -} - -impl From for Error { - fn from(e: BeaconNodeError) -> Error { - Error::BeaconNodeError(e) - } -} - -/// This struct contains the logic for requesting and signing beacon attestations for a validator. The -/// validator can abstractly sign via the Signer trait object. -pub struct AttestationProducer<'a, B: BeaconNodeAttestation, S: Signer> { - /// The current fork. - pub fork: Fork, - /// The attestation duty to perform. - pub duty: AttestationDuty, - /// The current epoch. - pub spec: Arc, - /// The beacon node to connect to. - pub beacon_node: Arc, - /// The signer to sign the block. - pub signer: &'a S, -} - -impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { - /// Handle outputs and results from attestation production. - pub fn handle_produce_attestation(&mut self, log: slog::Logger) { - match self.produce_attestation() { - Ok(ValidatorEvent::AttestationProduced(_slot)) => { - info!(log, "Attestation produced"; "Validator" => format!("{}", self.signer)) - } - Err(e) => error!(log, "Attestation production error"; "Error" => format!("{:?}", e)), - Ok(ValidatorEvent::SignerRejection(_slot)) => { - error!(log, "Attestation production error"; "Error" => format!("Signer could not sign the attestation")) - } - Ok(ValidatorEvent::SlashableAttestationNotProduced(_slot)) => { - error!(log, "Attestation production error"; "Error" => format!("Rejected the attestation as it could have been slashed")) - } - Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(_slot)) => { - error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to produce an attestation")) - } - Ok(v) => { - warn!(log, "Unknown result for attestation production"; "Error" => format!("{:?}",v)) - } - } - } - - /// Produce an attestation, sign it and send it back - /// - /// Assumes that an attestation is required at this slot (does not check the duties). - /// - /// Ensures the message is not slashable. - /// - /// !!! UNSAFE !!! - /// - /// The slash-protection code is not yet implemented. There is zero protection against - /// slashing. - pub fn produce_attestation(&mut self) -> Result { - let epoch = self.duty.slot.epoch(self.spec.slots_per_epoch); - - let attestation = self - .beacon_node - .produce_attestation_data(self.duty.slot, self.duty.shard)?; - if self.safe_to_produce(&attestation) { - let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork); - if let Some(attestation) = self.sign_attestation(attestation, self.duty, domain) { - self.beacon_node.publish_attestation(attestation)?; - Ok(ValidatorEvent::AttestationProduced(self.duty.slot)) - } else { - Ok(ValidatorEvent::SignerRejection(self.duty.slot)) - } - } else { - Ok(ValidatorEvent::SlashableAttestationNotProduced( - self.duty.slot, - )) - } - } - - /// Consumes an attestation, returning the attestation signed by the validators private key. - /// - /// Important: this function will not check to ensure the attestation is not slashable. This must be - /// done upstream. - fn sign_attestation( - &mut self, - mut attestation: AttestationData, - duties: AttestationDuty, - domain: u64, - ) -> Option { - self.store_produce(&attestation); - - // build the aggregate signature - let aggregate_signature = { - let message = AttestationDataAndCustodyBit { - data: attestation.clone(), - custody_bit: false, - } - .hash_tree_root(); - - let sig = self.signer.sign_message(&message, domain)?; - - let mut agg_sig = AggregateSignature::new(); - agg_sig.add(&sig); - agg_sig - }; - - let mut aggregation_bitfield = Bitfield::with_capacity(duties.committee_len); - let custody_bitfield = Bitfield::with_capacity(duties.committee_len); - aggregation_bitfield.set(duties.committee_index, true); - - Some(Attestation { - aggregation_bitfield, - data: attestation, - custody_bitfield, - aggregate_signature, - }) - } - - /// Returns `true` if signing an attestation is safe (non-slashable). - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn safe_to_produce(&self, _attestation: &AttestationData) -> bool { - //TODO: Implement slash protection - true - } - - /// Record that an attestation was produced so that slashable votes may not be made in the future. - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn store_produce(&mut self, _attestation: &AttestationData) { - // TODO: Implement slash protection - } -} diff --git a/validator_client/src/block_producer/grpc.rs b/validator_client/src/block_producer/grpc.rs index ab0d5d421..fd1a70fa2 100644 --- a/validator_client/src/block_producer/grpc.rs +++ b/validator_client/src/block_producer/grpc.rs @@ -7,6 +7,7 @@ use ssz::{ssz_encode, Decodable}; use std::sync::Arc; use types::{BeaconBlock, Signature, Slot}; +//TODO: Remove this new type. Do not need to wrap /// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be /// implemented upon it. pub struct BeaconBlockGrpcClient { diff --git a/validator_client/src/main.rs b/validator_client/src/main.rs index 481766734..7a353e0dc 100644 --- a/validator_client/src/main.rs +++ b/validator_client/src/main.rs @@ -1,4 +1,4 @@ -mod attester_service; +mod attestation_producer; mod block_producer; mod config; mod duties; From c2b6f949c0e6ab0693f5cf036078d1f7a4b16408 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 18:25:32 +1100 Subject: [PATCH 069/106] Restrict blop pool from re-including attestations --- .../specs/validator_registry.yaml | 3 ++- eth2/operation_pool/src/lib.rs | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml b/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml index 1674ecffc..ad9c899cf 100644 --- a/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml +++ b/beacon_node/beacon_chain/test_harness/specs/validator_registry.yaml @@ -48,7 +48,8 @@ test_cases: - slot: 63 num_validators: 1003 num_previous_epoch_attestations: 0 - num_current_epoch_attestations: 10 + # slots_per_epoch - attestation_inclusion_delay - skip_slots + num_current_epoch_attestations: 57 slashed_validators: [11, 12, 13, 14, 42] exited_validators: [] exit_initiated_validators: [50] diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index c42527b60..9d4d0091a 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -172,6 +172,8 @@ impl OperationPool { || key.domain_bytes_match(&curr_domain_bytes) }) .flat_map(|(_, attestations)| attestations) + // That are not superseded by an attestation included in the state... + .filter(|attestation| !superior_attestation_exists_in_state(state, attestation)) // That are valid... .filter(|attestation| validate_attestation(state, attestation, spec).is_ok()) // Scored by the number of new attestations they introduce (descending) @@ -462,6 +464,31 @@ impl OperationPool { } } +/// Returns `true` if the state already contains a `PendingAttestation` that is superior to the +/// given `attestation`. +/// +/// A validator has nothing to gain from re-including an attestation and it adds load to the +/// network. +/// +/// An existing `PendingAttestation` is superior to an existing `attestation` if: +/// +/// - Their `AttestationData` is equal. +/// - `attestation` does not contain any signatures that `PendingAttestation` does not have. +fn superior_attestation_exists_in_state(state: &BeaconState, attestation: &Attestation) -> bool { + state + .current_epoch_attestations + .iter() + .chain(state.previous_epoch_attestations.iter()) + .any(|existing_attestation| { + let bitfield = &attestation.aggregation_bitfield; + let existing_bitfield = &existing_attestation.aggregation_bitfield; + + existing_attestation.data == attestation.data + && bitfield.intersection(existing_bitfield).num_set_bits() + == bitfield.num_set_bits() + }) +} + /// Filter up to a maximum number of operations out of an iterator. fn filter_limit_operations<'a, T: 'a, I, F>(operations: I, filter: F, limit: u64) -> Vec where From d8fd7c8803f3ed780177463a060fb0e3fa44a7d8 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 18:36:38 +1100 Subject: [PATCH 070/106] Implement beacon node side of attestation production gRPC --- beacon_node/rpc/src/beacon_attester.rs | 100 +++++++++++++++++++------ 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/beacon_node/rpc/src/beacon_attester.rs b/beacon_node/rpc/src/beacon_attester.rs index 4166c30d4..d787d1e5f 100644 --- a/beacon_node/rpc/src/beacon_attester.rs +++ b/beacon_node/rpc/src/beacon_attester.rs @@ -7,9 +7,7 @@ use protos::services::{ PublishAttestation }; use protos::services_grpc::BeaconBlockService; -use slog::{Logger, info, warn, error}; - -const TEST_SHARD_PHASE_ZERO: u8 = 0; +use slog::{Logger, info, warn, error, trace}; #[derive(Clone)] pub struct AttestationServiceInstance { @@ -25,30 +23,47 @@ impl AttestationService for AttestationServiceInstance { req: ProduceAttestationDataRequest, sink: UnarySink, ) { - info!(&self.log, "Attempting to produce attestation at slot {}", req.get_slot()); + trace!(&self.log, "Attempting to produce attestation at slot {}", req.get_slot()); - // get the chain spec & state - let spec = self.chain.get_spec(); - let state = self.chain.get_state(); + // verify the slot, drop lock on state afterwards + { + let slot_requested = req.get_slot(); + let state = self.chain.get_state(); - let slot_requested = req.get_slot(); - - // Start by performing some checks - // Check that the the AttestionData is for the current slot (otherwise it will not be valid) - if slot_requested != state.slot { - let f = sink - .fail(RpcStatus::new( - RpcStatusCode::OutOfRange, - "AttestationData request for a slot that is not the current slot." - )) - .map_err(move |e| error!(&self.log, "Failed to reply with failure {:?}: {:?}", req, e)); + // Start by performing some checks + // Check that the the AttestionData is for the current slot (otherwise it will not be valid) + if slot_requested != state.slot { + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::OutOfRange, + "AttestationData request for a slot that is not the current slot." + )) + .map_err(move |e| error!(&self.log, "Failed to reply with failure {:?}: {:?}", req, e)); + } } - // Then get the AttestationData from the beacon chain (for shard 0 for now) - let attestation_data = self.chain.produce_attestation_data(TEST_SHARD_PHASE_ZERO); + // Then get the AttestationData from the beacon chain + let attestation_data = match self.chain.produce_attestation_data(req.get_shard()){ + Ok(v) => v, + Err(e) => { + // Could not produce an attestation + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::Unknown + Some(format!("Could not produce an attestation: {:?}",e)), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); + return ctx.spawn(f); + } + }; + + + let mut attestation_data_proto = AttestationDataProto::new(); + attestation_data_proto.set_ssz(ssz_encode(&attestation_data)); let mut resp = ProduceAttestationDataResponse::new(); - resp.set_attestation_data(attestation_data); + resp.set_attestation_data(attestation_data_proto); let f = sink .success(resp) @@ -64,12 +79,49 @@ impl AttestationService for AttestationServiceInstance { req: PublishAttestationRequest, sink: UnarySink, ) { - println!("publishing attestation {:?}", req.get_block()); + trace!(self.log, "Publishing attestation"); - // TODO: actually process the block. let mut resp = PublishAttestationResponse::new(); + let ssz_serialized_attestation = req.get_attestation().get_ssz(); - resp.set_success(true); + let attestation = match Attestation::ssz_decode(ssz_serialized_attestation, 0) { + Ok((v, _index)) => v, + Err(_) => { + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::InvalidArgument, + Some("Invalid attestation".to_string()), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?}", req)); + return ctx.spawn(f); + } + }; + + match self.chain.process_attestation(attestation) { + Ok(_) => { + // Attestation was successfully processed. + info!( + self.log, + "PublishAttestation"; + "type" => "valid_attestation", + ); + + resp.set_success(true); + }, + Err(e)=> { + // Attestation was invalid + warn!( + self.log, + "PublishAttestation"; + "type" => "invalid_attestation", + ); + resp.set_success(false); + resp.set_msg( + format!("InvalidAttestation: {:?}", e).as_bytes().to_vec(), + ); + } + }; let f = sink .success(resp) From e1befe9d3a22fe8d1c2414757ad6be0672221ae6 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 18:46:06 +1100 Subject: [PATCH 071/106] Adds attestation producer to the validation client --- validator_client/src/service.rs | 53 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index fd24744ac..ba0795ec1 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -8,15 +8,13 @@ /// When a validator needs to either produce a block or sign an attestation, it requests the /// data from the beacon node and performs the signing before publishing the block to the beacon /// node. -//use crate::attester_service::{AttestationGrpcClient, AttesterService}; +use crate::attestation_producer::AttestationProducer; use crate::block_producer::{BeaconBlockGrpcClient, BlockProducer}; use crate::config::Config as ValidatorConfig; -use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap, UpdateOutcome}; +use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap}; use crate::error as error_chain; use crate::error::ErrorKind; use crate::signer::Signer; -use attester::test_utils::EpochMap; -use attester::{test_utils::LocalSigner as AttesterLocalSigner, Attester}; use bls::Keypair; use grpcio::{ChannelBuilder, EnvBuilder}; use protos::services::Empty; @@ -24,11 +22,10 @@ use protos::services_grpc::{ AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient, ValidatorServiceClient, }; -use slog::{debug, error, info, warn}; +use slog::{error, info, warn}; use slot_clock::{SlotClock, SystemTimeSlotClock}; use std::sync::Arc; use std::sync::RwLock; -use std::thread; use std::time::{Duration, Instant, SystemTime}; use tokio::prelude::*; use tokio::runtime::Builder; @@ -55,7 +52,7 @@ pub struct Service { /// The beacon block GRPC client. beacon_block_client: Arc, /// The attester GRPC client. - attester_client: Arc, + attestation_client: Arc, /// The validator client logger. log: slog::Logger, } @@ -148,7 +145,7 @@ impl Service { }; //Beacon node gRPC attester endpoints. - let attester_client = { + let attestation_client = { let ch = ChannelBuilder::new(env.clone()).connect(&config.server); Arc::new(AttestationServiceClient::new(ch)) }; @@ -194,7 +191,7 @@ impl Service { spec, duties_manager, beacon_block_client, - attester_client, + attestation_client, log, }) } @@ -301,6 +298,7 @@ impl Service { if let Some(work) = self.duties_manager.get_current_work(self.current_slot) { for (signer_index, work_type) in work { if work_type.produce_block { + // we need to produce a block // spawns a thread to produce a beacon block let signers = self.duties_manager.signers.clone(); // this is an arc let fork = self.fork.clone(); @@ -320,26 +318,27 @@ impl Service { }; block_producer.handle_produce_block(log); }); - - // TODO: Produce a beacon block in a new thread } if work_type.attestation_duty.is_some() { - // available AttestationDuty info - /* - let attestation_duty = - work_type.attestation_duty.expect("Cannot be None"); - let attester_grpc_client = Arc::new(AttestationGrpcClient::new( - service.attester_client.clone(), - )); - let signer = Arc::new(AttesterLocalSigner::new(keypair.clone())); - let attester = Attester::new(attester_grpc_client, signer); - let mut attester_service = AttesterService { - attester, - poll_interval_millis: POLL_INTERVAL_MILLIS, - log: log.clone(), - }; - attester_service.run(); - */ + // we need to produce an attestation + // spawns a thread to produce and sign an attestation + let signers = self.duties_manager.signers.clone(); // this is an arc + let fork = self.fork.clone(); + let spec = self.spec.clone(); + let beacon_node = self.attestation_client.clone(); + let log = self.log.clone(); + std::thread::spawn(move || { + info!(log, "Producing an attestation"; "Validator"=> format!("{}", signers[signer_index])); + let signer = &signers[signer_index]; + let mut attestation_producer = AttestationProducer { + fork, + duty: work_type.attestation_duty.expect("Should never be none"), + spec, + beacon_node, + signer, + }; + attestation_producer.handle_produce_attestation(log); + }); } } } From 935c64deef97431d71e20272c9411e99ecfd2722 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 19:11:52 +1100 Subject: [PATCH 072/106] Adds attestation validation to `SimpleSync` --- beacon_node/beacon_chain/src/beacon_chain.rs | 2 +- beacon_node/beacon_chain/src/lib.rs | 4 ++++ beacon_node/network/src/beacon_chain.rs | 15 +++++---------- beacon_node/network/src/sync/simple_sync.rs | 7 ++----- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 7c2336a28..6ca0bff73 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -11,7 +11,7 @@ use operation_pool::OperationPool; use parking_lot::{RwLock, RwLockReadGuard}; use slot_clock::SlotClock; use ssz::ssz_encode; -pub use state_processing::per_block_processing::errors::{ +use state_processing::per_block_processing::errors::{ AttestationValidationError, AttesterSlashingValidationError, DepositValidationError, ExitValidationError, ProposerSlashingValidationError, TransferValidationError, }; diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 48a42b941..409b86e02 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -13,4 +13,8 @@ pub use db; pub use fork_choice; pub use parking_lot; pub use slot_clock; +pub use state_processing::per_block_processing::errors::{ + AttestationValidationError, AttesterSlashingValidationError, DepositValidationError, + ExitValidationError, ProposerSlashingValidationError, TransferValidationError, +}; pub use types; diff --git a/beacon_node/network/src/beacon_chain.rs b/beacon_node/network/src/beacon_chain.rs index 8ec8162ff..7a8efb254 100644 --- a/beacon_node/network/src/beacon_chain.rs +++ b/beacon_node/network/src/beacon_chain.rs @@ -5,7 +5,7 @@ use beacon_chain::{ parking_lot::RwLockReadGuard, slot_clock::SlotClock, types::{BeaconState, ChainSpec}, - AggregationOutcome, CheckPoint, + AttestationValidationError, CheckPoint, }; use eth2_libp2p::rpc::HelloMessage; use types::{Attestation, BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Epoch, Hash256, Slot}; @@ -40,7 +40,7 @@ pub trait BeaconChain: Send + Sync { fn process_attestation( &self, attestation: Attestation, - ) -> Result; + ) -> Result<(), AttestationValidationError>; fn get_block_roots( &self, @@ -126,14 +126,9 @@ where fn process_attestation( &self, - _attestation: Attestation, - ) -> Result { - // Awaiting a proper operations pool before we can import attestations. - // - // Returning a useless error for now. - // - // https://github.com/sigp/lighthouse/issues/281 - return Err(BeaconChainError::DBInconsistent("CANNOT PROCESS".into())); + attestation: Attestation, + ) -> Result<(), AttestationValidationError> { + self.process_attestation(attestation) } fn get_block_roots( diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 85949fa98..1afba018d 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -563,12 +563,9 @@ impl SimpleSync { "peer" => format!("{:?}", peer_id), ); - // Awaiting a proper operations pool before we can import attestations. - // - // https://github.com/sigp/lighthouse/issues/281 match self.chain.process_attestation(msg) { - Ok(_) => panic!("Impossible, method not implemented."), - Err(_) => error!(self.log, "Attestation processing not implemented!"), + Ok(()) => info!(self.log, "ImportedAttestation"), + Err(e) => warn!(self.log, "InvalidAttestation"; "error" => format!("{:?}", e)), } } From 65ae8fda47cc323d7ed591037e3968b97ee978ec Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 30 Mar 2019 19:15:15 +1100 Subject: [PATCH 073/106] Remove old attestation aggregator --- .../src/attestation_aggregator.rs | 218 ------------------ beacon_node/beacon_chain/src/lib.rs | 2 - 2 files changed, 220 deletions(-) delete mode 100644 beacon_node/beacon_chain/src/attestation_aggregator.rs diff --git a/beacon_node/beacon_chain/src/attestation_aggregator.rs b/beacon_node/beacon_chain/src/attestation_aggregator.rs deleted file mode 100644 index 9b4e5a687..000000000 --- a/beacon_node/beacon_chain/src/attestation_aggregator.rs +++ /dev/null @@ -1,218 +0,0 @@ -use ssz::TreeHash; -use state_processing::per_block_processing::validate_attestation_without_signature; -use std::collections::{HashMap, HashSet}; -use types::*; - -const PHASE_0_CUSTODY_BIT: bool = false; - -/// Provides the functionality to: -/// -/// - Recieve a `FreeAttestation` and aggregate it into an `Attestation` (or create a new if it -/// doesn't exist). -/// - Store all aggregated or created `Attestation`s. -/// - Produce a list of attestations that would be valid for inclusion in some `BeaconState` (and -/// therefore valid for inclusion in a `BeaconBlock`. -/// -/// Note: `Attestations` are stored in memory and never deleted. This is not scalable and must be -/// rectified in a future revision. -#[derive(Default)] -pub struct AttestationAggregator { - store: HashMap, Attestation>, -} - -pub struct Outcome { - pub valid: bool, - pub message: Message, -} - -pub enum Message { - /// The free attestation was added to an existing attestation. - Aggregated, - /// The free attestation has already been aggregated to an existing attestation. - AggregationNotRequired, - /// The free attestation was transformed into a new attestation. - NewAttestationCreated, - /// The supplied `validator_index` is not in the committee for the given `shard` and `slot`. - BadValidatorIndex, - /// The given `signature` did not match the `pubkey` in the given - /// `state.validator_registry`. - BadSignature, - /// The given `slot` does not match the validators committee assignment. - BadSlot, - /// The given `shard` does not match the validators committee assignment, or is not included in - /// a committee for the given slot. - BadShard, - /// Attestation is from the epoch prior to this, ignoring. - TooOld, -} - -macro_rules! valid_outcome { - ($error: expr) => { - return Ok(Outcome { - valid: true, - message: $error, - }); - }; -} - -macro_rules! invalid_outcome { - ($error: expr) => { - return Ok(Outcome { - valid: false, - message: $error, - }); - }; -} - -impl AttestationAggregator { - /// Instantiates a new AttestationAggregator with an empty database. - pub fn new() -> Self { - Self { - store: HashMap::new(), - } - } - - /// Accepts some `FreeAttestation`, validates it and either aggregates it upon some existing - /// `Attestation` or produces a new `Attestation`. - /// - /// The "validation" provided is not complete, instead the following points are checked: - /// - The given `validator_index` is in the committee for the given `shard` for the given - /// `slot`. - /// - The signature is verified against that of the validator at `validator_index`. - pub fn process_free_attestation( - &mut self, - state: &BeaconState, - free_attestation: &FreeAttestation, - spec: &ChainSpec, - ) -> Result { - let duties = - match state.get_attestation_duties(free_attestation.validator_index as usize, spec) { - Err(BeaconStateError::EpochCacheUninitialized(e)) => { - panic!("Attempted to access unbuilt cache {:?}.", e) - } - Err(BeaconStateError::EpochOutOfBounds) => invalid_outcome!(Message::TooOld), - Err(BeaconStateError::ShardOutOfBounds) => invalid_outcome!(Message::BadShard), - Err(e) => return Err(e), - Ok(None) => invalid_outcome!(Message::BadValidatorIndex), - Ok(Some(attestation_duties)) => attestation_duties, - }; - - if free_attestation.data.slot != duties.slot { - invalid_outcome!(Message::BadSlot); - } - if free_attestation.data.shard != duties.shard { - invalid_outcome!(Message::BadShard); - } - - let signable_message = AttestationDataAndCustodyBit { - data: free_attestation.data.clone(), - custody_bit: PHASE_0_CUSTODY_BIT, - } - .hash_tree_root(); - - let validator_record = match state - .validator_registry - .get(free_attestation.validator_index as usize) - { - None => invalid_outcome!(Message::BadValidatorIndex), - Some(validator_record) => validator_record, - }; - - if !free_attestation.signature.verify( - &signable_message, - spec.get_domain(state.current_epoch(spec), Domain::Attestation, &state.fork), - &validator_record.pubkey, - ) { - invalid_outcome!(Message::BadSignature); - } - - if let Some(existing_attestation) = self.store.get(&signable_message) { - if let Some(updated_attestation) = aggregate_attestation( - existing_attestation, - &free_attestation.signature, - duties.committee_index as usize, - ) { - self.store.insert(signable_message, updated_attestation); - valid_outcome!(Message::Aggregated); - } else { - valid_outcome!(Message::AggregationNotRequired); - } - } else { - let mut aggregate_signature = AggregateSignature::new(); - aggregate_signature.add(&free_attestation.signature); - let mut aggregation_bitfield = Bitfield::new(); - aggregation_bitfield.set(duties.committee_index as usize, true); - let new_attestation = Attestation { - data: free_attestation.data.clone(), - aggregation_bitfield, - custody_bitfield: Bitfield::new(), - aggregate_signature, - }; - self.store.insert(signable_message, new_attestation); - valid_outcome!(Message::NewAttestationCreated); - } - } - - /// Returns all known attestations which are: - /// - /// - Valid for the given state - /// - Not already in `state.latest_attestations`. - pub fn get_attestations_for_state( - &self, - state: &BeaconState, - spec: &ChainSpec, - ) -> Vec { - let mut known_attestation_data: HashSet = HashSet::new(); - - state - .previous_epoch_attestations - .iter() - .chain(state.current_epoch_attestations.iter()) - .for_each(|attestation| { - known_attestation_data.insert(attestation.data.clone()); - }); - - self.store - .values() - .filter_map(|attestation| { - if validate_attestation_without_signature(&state, attestation, spec).is_ok() - && !known_attestation_data.contains(&attestation.data) - { - Some(attestation.clone()) - } else { - None - } - }) - .collect() - } -} - -/// Produces a new `Attestation` where: -/// -/// - `signature` is added to `Attestation.aggregate_signature` -/// - Attestation.aggregation_bitfield[committee_index]` is set to true. -fn aggregate_attestation( - existing_attestation: &Attestation, - signature: &Signature, - committee_index: usize, -) -> Option { - let already_signed = existing_attestation - .aggregation_bitfield - .get(committee_index) - .unwrap_or(false); - - if already_signed { - None - } else { - let mut aggregation_bitfield = existing_attestation.aggregation_bitfield.clone(); - aggregation_bitfield.set(committee_index, true); - let mut aggregate_signature = existing_attestation.aggregate_signature.clone(); - aggregate_signature.add(&signature); - - Some(Attestation { - aggregation_bitfield, - aggregate_signature, - ..existing_attestation.clone() - }) - } -} diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 409b86e02..8b8fcb5e6 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -1,4 +1,3 @@ -mod attestation_aggregator; mod beacon_chain; mod checkpoint; mod errors; @@ -8,7 +7,6 @@ pub mod test_utils; pub use self::beacon_chain::{BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock}; pub use self::checkpoint::CheckPoint; pub use self::errors::BeaconChainError; -pub use attestation_aggregator::Outcome as AggregationOutcome; pub use db; pub use fork_choice; pub use parking_lot; From fc5142c09abbe11597f1ac302c13125a554e42a6 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 19:32:32 +1100 Subject: [PATCH 074/106] Registers the attester service to the beacon node RPC client --- beacon_node/beacon_chain/src/lib.rs | 4 +- beacon_node/rpc/src/attestation.rs | 143 ++++++++++++++++ beacon_node/rpc/src/beacon_attester.rs | 131 --------------- beacon_node/rpc/src/beacon_block.rs | 6 +- beacon_node/rpc/src/beacon_chain.rs | 22 ++- beacon_node/rpc/src/lib.rs | 17 +- .../testing_beacon_state_builder.rs | 2 +- .../beacon_node_attestation.rs | 23 +++ .../src/attestation_producer/grpc.rs | 59 +++++++ .../src/attestation_producer/mod.rs | 155 ++++++++++++++++++ validator_client/src/service.rs | 3 + 11 files changed, 425 insertions(+), 140 deletions(-) create mode 100644 beacon_node/rpc/src/attestation.rs delete mode 100644 beacon_node/rpc/src/beacon_attester.rs create mode 100644 validator_client/src/attestation_producer/beacon_node_attestation.rs create mode 100644 validator_client/src/attestation_producer/grpc.rs create mode 100644 validator_client/src/attestation_producer/mod.rs diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 234a96094..69ff14671 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -5,7 +5,9 @@ mod errors; pub mod initialise; pub mod test_utils; -pub use self::beacon_chain::{BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock}; +pub use self::beacon_chain::{ + AttestationValidationError, BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock, +}; pub use self::checkpoint::CheckPoint; pub use self::errors::{BeaconChainError, BlockProductionError}; pub use attestation_aggregator::Outcome as AggregationOutcome; diff --git a/beacon_node/rpc/src/attestation.rs b/beacon_node/rpc/src/attestation.rs new file mode 100644 index 000000000..f9423df61 --- /dev/null +++ b/beacon_node/rpc/src/attestation.rs @@ -0,0 +1,143 @@ +use crate::beacon_chain::BeaconChain; +use futures::Future; +use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink}; +use protos::services::{ + AttestationData as AttestationDataProto, ProduceAttestationDataRequest, + ProduceAttestationDataResponse, PublishAttestationRequest, PublishAttestationResponse, +}; +use protos::services_grpc::AttestationService; +use slog::{error, info, trace, warn, Logger}; +use ssz::{ssz_encode, Decodable}; +use std::sync::Arc; +use types::Attestation; + +#[derive(Clone)] +pub struct AttestationServiceInstance { + pub chain: Arc, + pub log: slog::Logger, +} + +impl AttestationService for AttestationServiceInstance { + /// Produce the `AttestationData` for signing by a validator. + fn produce_attestation_data( + &mut self, + ctx: RpcContext, + req: ProduceAttestationDataRequest, + sink: UnarySink, + ) { + warn!( + &self.log, + "Attempting to produce attestation at slot {}", + req.get_slot() + ); + + // verify the slot, drop lock on state afterwards + { + let slot_requested = req.get_slot(); + let state = self.chain.get_state(); + + // Start by performing some checks + // Check that the the AttestionData is for the current slot (otherwise it will not be valid) + if slot_requested != state.slot.as_u64() { + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::OutOfRange, + Some(format!( + "AttestationData request for a slot that is not the current slot." + )), + )) + .map_err(move |e| { + error!(log_clone, "Failed to reply with failure {:?}: {:?}", req, e) + }); + return ctx.spawn(f); + } + } + + // Then get the AttestationData from the beacon chain + let shard = req.get_shard(); + let attestation_data = match self.chain.produce_attestation_data(shard) { + Ok(v) => v, + Err(e) => { + // Could not produce an attestation + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::Unknown, + Some(format!("Could not produce an attestation: {:?}", e)), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); + return ctx.spawn(f); + } + }; + + let mut attestation_data_proto = AttestationDataProto::new(); + attestation_data_proto.set_ssz(ssz_encode(&attestation_data)); + + let mut resp = ProduceAttestationDataResponse::new(); + resp.set_attestation_data(attestation_data_proto); + + let error_log = self.log.clone(); + let f = sink + .success(resp) + .map_err(move |e| error!(error_log, "Failed to reply with success {:?}: {:?}", req, e)); + ctx.spawn(f) + } + + /// Accept some fully-formed `FreeAttestation` from the validator, + /// store it, and aggregate it into an `Attestation`. + fn publish_attestation( + &mut self, + ctx: RpcContext, + req: PublishAttestationRequest, + sink: UnarySink, + ) { + warn!(self.log, "Publishing attestation"); + + let mut resp = PublishAttestationResponse::new(); + let ssz_serialized_attestation = req.get_attestation().get_ssz(); + + let attestation = match Attestation::ssz_decode(ssz_serialized_attestation, 0) { + Ok((v, _index)) => v, + Err(_) => { + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::InvalidArgument, + Some("Invalid attestation".to_string()), + )) + .map_err(move |_| warn!(log_clone, "failed to reply {:?}", req)); + return ctx.spawn(f); + } + }; + + match self.chain.process_attestation(attestation) { + Ok(_) => { + // Attestation was successfully processed. + info!( + self.log, + "PublishAttestation"; + "type" => "valid_attestation", + ); + + resp.set_success(true); + } + Err(e) => { + // Attestation was invalid + warn!( + self.log, + "PublishAttestation"; + "type" => "invalid_attestation", + ); + resp.set_success(false); + resp.set_msg(format!("InvalidAttestation: {:?}", e).as_bytes().to_vec()); + } + }; + + let error_log = self.log.clone(); + let f = sink + .success(resp) + .map_err(move |e| error!(error_log, "failed to reply {:?}: {:?}", req, e)); + ctx.spawn(f) + } +} diff --git a/beacon_node/rpc/src/beacon_attester.rs b/beacon_node/rpc/src/beacon_attester.rs deleted file mode 100644 index d787d1e5f..000000000 --- a/beacon_node/rpc/src/beacon_attester.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::beacon_chain::BeaconChain; -use futures::Future; -use grpcio::{RpcContext, UnarySink, RpcStatus, RpcStatusCode}; -use protos::services::{ - AttestationData as AttestationDataProto, ProduceAttestationData, ProduceAttestationDataResponse, - ProduceAttestationDataRequest, PublishAttestationResponse, PublishAttestationRequest, - PublishAttestation -}; -use protos::services_grpc::BeaconBlockService; -use slog::{Logger, info, warn, error, trace}; - -#[derive(Clone)] -pub struct AttestationServiceInstance { - pub chain: Arc, - pub log: Logger, -} - -impl AttestationService for AttestationServiceInstance { - /// Produce the `AttestationData` for signing by a validator. - fn produce_attestation_data( - &mut self, - ctx: RpcContext, - req: ProduceAttestationDataRequest, - sink: UnarySink, - ) { - trace!(&self.log, "Attempting to produce attestation at slot {}", req.get_slot()); - - // verify the slot, drop lock on state afterwards - { - let slot_requested = req.get_slot(); - let state = self.chain.get_state(); - - // Start by performing some checks - // Check that the the AttestionData is for the current slot (otherwise it will not be valid) - if slot_requested != state.slot { - let f = sink - .fail(RpcStatus::new( - RpcStatusCode::OutOfRange, - "AttestationData request for a slot that is not the current slot." - )) - .map_err(move |e| error!(&self.log, "Failed to reply with failure {:?}: {:?}", req, e)); - } - } - - // Then get the AttestationData from the beacon chain - let attestation_data = match self.chain.produce_attestation_data(req.get_shard()){ - Ok(v) => v, - Err(e) => { - // Could not produce an attestation - let log_clone = self.log.clone(); - let f = sink - .fail(RpcStatus::new( - RpcStatusCode::Unknown - Some(format!("Could not produce an attestation: {:?}",e)), - )) - .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); - return ctx.spawn(f); - } - }; - - - let mut attestation_data_proto = AttestationDataProto::new(); - attestation_data_proto.set_ssz(ssz_encode(&attestation_data)); - - let mut resp = ProduceAttestationDataResponse::new(); - resp.set_attestation_data(attestation_data_proto); - - let f = sink - .success(resp) - .map_err(move |e| error!("Failed to reply with success {:?}: {:?}", req, e)); - ctx.spawn(f) - } - - /// Accept some fully-formed `FreeAttestation` from the validator, - /// store it, and aggregate it into an `Attestation`. - fn publish_attestation( - &mut self, - ctx: RpcContext, - req: PublishAttestationRequest, - sink: UnarySink, - ) { - trace!(self.log, "Publishing attestation"); - - let mut resp = PublishAttestationResponse::new(); - let ssz_serialized_attestation = req.get_attestation().get_ssz(); - - let attestation = match Attestation::ssz_decode(ssz_serialized_attestation, 0) { - Ok((v, _index)) => v, - Err(_) => { - let log_clone = self.log.clone(); - let f = sink - .fail(RpcStatus::new( - RpcStatusCode::InvalidArgument, - Some("Invalid attestation".to_string()), - )) - .map_err(move |e| warn!(log_clone, "failed to reply {:?}", req)); - return ctx.spawn(f); - } - }; - - match self.chain.process_attestation(attestation) { - Ok(_) => { - // Attestation was successfully processed. - info!( - self.log, - "PublishAttestation"; - "type" => "valid_attestation", - ); - - resp.set_success(true); - }, - Err(e)=> { - // Attestation was invalid - warn!( - self.log, - "PublishAttestation"; - "type" => "invalid_attestation", - ); - resp.set_success(false); - resp.set_msg( - format!("InvalidAttestation: {:?}", e).as_bytes().to_vec(), - ); - } - }; - - let f = sink - .success(resp) - .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e)); - ctx.spawn(f) - } -} diff --git a/beacon_node/rpc/src/beacon_block.rs b/beacon_node/rpc/src/beacon_block.rs index e8b3cb01b..adb0a3c22 100644 --- a/beacon_node/rpc/src/beacon_block.rs +++ b/beacon_node/rpc/src/beacon_block.rs @@ -36,8 +36,8 @@ impl BeaconBlockService for BeaconBlockServiceInstance { // decode the request // TODO: requested slot currently unused, see: https://github.com/sigp/lighthouse/issues/336 let _requested_slot = Slot::from(req.get_slot()); - let (randao_reveal, _index) = match Signature::ssz_decode(req.get_randao_reveal(), 0) { - Ok(v) => v, + let randao_reveal = match Signature::ssz_decode(req.get_randao_reveal(), 0) { + Ok((reveal, _index)) => reveal, Err(_) => { // decode error, incorrect signature let log_clone = self.log.clone(); @@ -86,6 +86,8 @@ impl BeaconBlockService for BeaconBlockServiceInstance { req: PublishBeaconBlockRequest, sink: UnarySink, ) { + trace!(&self.log, "Attempting to publish a block"); + let mut resp = PublishBeaconBlockResponse::new(); let ssz_serialized_block = req.get_block().get_ssz(); diff --git a/beacon_node/rpc/src/beacon_chain.rs b/beacon_node/rpc/src/beacon_chain.rs index f21b8df7b..7de48efa1 100644 --- a/beacon_node/rpc/src/beacon_chain.rs +++ b/beacon_node/rpc/src/beacon_chain.rs @@ -5,10 +5,10 @@ use beacon_chain::{ parking_lot::RwLockReadGuard, slot_clock::SlotClock, types::{BeaconState, ChainSpec, Signature}, - BlockProductionError, + AttestationValidationError, BlockProductionError, }; pub use beacon_chain::{BeaconChainError, BlockProcessingOutcome}; -use types::BeaconBlock; +use types::{Attestation, AttestationData, BeaconBlock}; /// The RPC's API to the beacon chain. pub trait BeaconChain: Send + Sync { @@ -23,6 +23,13 @@ pub trait BeaconChain: Send + Sync { &self, randao_reveal: Signature, ) -> Result<(BeaconBlock, BeaconState), BlockProductionError>; + + fn produce_attestation_data(&self, shard: u64) -> Result; + + fn process_attestation( + &self, + attestation: Attestation, + ) -> Result<(), AttestationValidationError>; } impl BeaconChain for RawBeaconChain @@ -52,4 +59,15 @@ where ) -> Result<(BeaconBlock, BeaconState), BlockProductionError> { self.produce_block(randao_reveal) } + + fn produce_attestation_data(&self, shard: u64) -> Result { + self.produce_attestation_data(shard) + } + + fn process_attestation( + &self, + attestation: Attestation, + ) -> Result<(), AttestationValidationError> { + self.process_attestation(attestation) + } } diff --git a/beacon_node/rpc/src/lib.rs b/beacon_node/rpc/src/lib.rs index 2d47b4a69..5aac4ce55 100644 --- a/beacon_node/rpc/src/lib.rs +++ b/beacon_node/rpc/src/lib.rs @@ -1,19 +1,22 @@ +mod attestation; mod beacon_block; pub mod beacon_chain; mod beacon_node; pub mod config; mod validator; +use self::attestation::AttestationServiceInstance; use self::beacon_block::BeaconBlockServiceInstance; use self::beacon_chain::BeaconChain; use self::beacon_node::BeaconNodeServiceInstance; use self::validator::ValidatorServiceInstance; pub use config::Config as RPCConfig; -use futures::{future, Future}; -use grpcio::{Environment, Server, ServerBuilder}; +use futures::Future; +use grpcio::{Environment, ServerBuilder}; use network::NetworkMessage; use protos::services_grpc::{ - create_beacon_block_service, create_beacon_node_service, create_validator_service, + create_attestation_service, create_beacon_block_service, create_beacon_node_service, + create_validator_service, }; use slog::{info, o, warn}; use std::sync::Arc; @@ -56,11 +59,19 @@ pub fn start_server( }; create_validator_service(instance) }; + let attestation_service = { + let instance = AttestationServiceInstance { + chain: beacon_chain.clone(), + log: log.clone(), + }; + create_attestation_service(instance) + }; let mut server = ServerBuilder::new(env) .register_service(beacon_block_service) .register_service(validator_service) .register_service(beacon_node_service) + .register_service(attestation_service) .bind(config.listen_address.to_string(), config.port) .build() .unwrap(); diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index 7c231b20b..8d0aa6af6 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -120,7 +120,7 @@ impl TestingBeaconStateBuilder { }) .collect(); - let genesis_time = 1553918534; // arbitrary + let genesis_time = 1553932445; // arbitrary let mut state = BeaconState::genesis( genesis_time, diff --git a/validator_client/src/attestation_producer/beacon_node_attestation.rs b/validator_client/src/attestation_producer/beacon_node_attestation.rs new file mode 100644 index 000000000..b5ff777de --- /dev/null +++ b/validator_client/src/attestation_producer/beacon_node_attestation.rs @@ -0,0 +1,23 @@ +//TODO: generalise these enums to the crate +use crate::block_producer::{BeaconNodeError, PublishOutcome}; +use types::{Attestation, AttestationData, Slot}; + +/// Defines the methods required to produce and publish attestations on a Beacon Node. Abstracts the +/// actual beacon node. +pub trait BeaconNodeAttestation: Send + Sync { + /// Request that the node produces the required attestation data. + /// + fn produce_attestation_data( + &self, + slot: Slot, + shard: u64, + ) -> Result; + + /// Request that the node publishes a attestation. + /// + /// Returns `true` if the publish was successful. + fn publish_attestation( + &self, + attestation: Attestation, + ) -> Result; +} diff --git a/validator_client/src/attestation_producer/grpc.rs b/validator_client/src/attestation_producer/grpc.rs new file mode 100644 index 000000000..49c577e24 --- /dev/null +++ b/validator_client/src/attestation_producer/grpc.rs @@ -0,0 +1,59 @@ +use super::beacon_node_attestation::BeaconNodeAttestation; +use crate::block_producer::{BeaconNodeError, PublishOutcome}; +use protos::services_grpc::AttestationServiceClient; +use ssz::{ssz_encode, Decodable}; + +use protos::services::{ + Attestation as GrpcAttestation, ProduceAttestationDataRequest, PublishAttestationRequest, +}; +use types::{Attestation, AttestationData, Slot}; + +impl BeaconNodeAttestation for AttestationServiceClient { + fn produce_attestation_data( + &self, + slot: Slot, + shard: u64, + ) -> Result { + let mut req = ProduceAttestationDataRequest::new(); + req.set_slot(slot.as_u64()); + req.set_shard(shard); + + let reply = self + .produce_attestation_data(&req) + .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; + + dbg!("Produced Attestation Data"); + + let (attestation_data, _index) = + AttestationData::ssz_decode(reply.get_attestation_data().get_ssz(), 0) + .map_err(|_| BeaconNodeError::DecodeFailure)?; + Ok(attestation_data) + } + + fn publish_attestation( + &self, + attestation: Attestation, + ) -> Result { + let mut req = PublishAttestationRequest::new(); + + let ssz = ssz_encode(&attestation); + + let mut grpc_attestation = GrpcAttestation::new(); + grpc_attestation.set_ssz(ssz); + + req.set_attestation(grpc_attestation); + + let reply = self + .publish_attestation(&req) + .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; + + if reply.get_success() { + Ok(PublishOutcome::Valid) + } else { + // TODO: distinguish between different errors + Ok(PublishOutcome::InvalidAttestation( + "Publish failed".to_string(), + )) + } + } +} diff --git a/validator_client/src/attestation_producer/mod.rs b/validator_client/src/attestation_producer/mod.rs new file mode 100644 index 000000000..7b2174b0c --- /dev/null +++ b/validator_client/src/attestation_producer/mod.rs @@ -0,0 +1,155 @@ +mod beacon_node_attestation; +mod grpc; + +use std::sync::Arc; +use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; +//TODO: Move these higher up in the crate +use super::block_producer::{BeaconNodeError, ValidatorEvent}; +use crate::signer::Signer; +use beacon_node_attestation::BeaconNodeAttestation; +use slog::{error, info, warn}; +use ssz::TreeHash; +use types::{ + AggregateSignature, Attestation, AttestationData, AttestationDataAndCustodyBit, + AttestationDuty, Bitfield, +}; + +//TODO: Group these errors at a crate level +#[derive(Debug, PartialEq)] +pub enum Error { + BeaconNodeError(BeaconNodeError), +} + +impl From for Error { + fn from(e: BeaconNodeError) -> Error { + Error::BeaconNodeError(e) + } +} + +/// This struct contains the logic for requesting and signing beacon attestations for a validator. The +/// validator can abstractly sign via the Signer trait object. +pub struct AttestationProducer<'a, B: BeaconNodeAttestation, S: Signer> { + /// The current fork. + pub fork: Fork, + /// The attestation duty to perform. + pub duty: AttestationDuty, + /// The current epoch. + pub spec: Arc, + /// The beacon node to connect to. + pub beacon_node: Arc, + /// The signer to sign the block. + pub signer: &'a S, +} + +impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { + /// Handle outputs and results from attestation production. + pub fn handle_produce_attestation(&mut self, log: slog::Logger) { + match self.produce_attestation() { + Ok(ValidatorEvent::AttestationProduced(_slot)) => { + info!(log, "Attestation produced"; "Validator" => format!("{}", self.signer)) + } + Err(e) => error!(log, "Attestation production error"; "Error" => format!("{:?}", e)), + Ok(ValidatorEvent::SignerRejection(_slot)) => { + error!(log, "Attestation production error"; "Error" => format!("Signer could not sign the attestation")) + } + Ok(ValidatorEvent::SlashableAttestationNotProduced(_slot)) => { + error!(log, "Attestation production error"; "Error" => format!("Rejected the attestation as it could have been slashed")) + } + Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(_slot)) => { + error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to produce an attestation")) + } + Ok(v) => { + warn!(log, "Unknown result for attestation production"; "Error" => format!("{:?}",v)) + } + } + } + + /// Produce an attestation, sign it and send it back + /// + /// Assumes that an attestation is required at this slot (does not check the duties). + /// + /// Ensures the message is not slashable. + /// + /// !!! UNSAFE !!! + /// + /// The slash-protection code is not yet implemented. There is zero protection against + /// slashing. + pub fn produce_attestation(&mut self) -> Result { + let epoch = self.duty.slot.epoch(self.spec.slots_per_epoch); + + let attestation = self + .beacon_node + .produce_attestation_data(self.duty.slot, self.duty.shard)?; + if self.safe_to_produce(&attestation) { + let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork); + if let Some(attestation) = self.sign_attestation(attestation, self.duty, domain) { + self.beacon_node.publish_attestation(attestation)?; + Ok(ValidatorEvent::AttestationProduced(self.duty.slot)) + } else { + Ok(ValidatorEvent::SignerRejection(self.duty.slot)) + } + } else { + Ok(ValidatorEvent::SlashableAttestationNotProduced( + self.duty.slot, + )) + } + } + + /// Consumes an attestation, returning the attestation signed by the validators private key. + /// + /// Important: this function will not check to ensure the attestation is not slashable. This must be + /// done upstream. + fn sign_attestation( + &mut self, + mut attestation: AttestationData, + duties: AttestationDuty, + domain: u64, + ) -> Option { + self.store_produce(&attestation); + + // build the aggregate signature + let aggregate_signature = { + let message = AttestationDataAndCustodyBit { + data: attestation.clone(), + custody_bit: false, + } + .hash_tree_root(); + + let sig = self.signer.sign_message(&message, domain)?; + + let mut agg_sig = AggregateSignature::new(); + agg_sig.add(&sig); + agg_sig + }; + + let mut aggregation_bitfield = Bitfield::with_capacity(duties.committee_len); + let custody_bitfield = Bitfield::with_capacity(duties.committee_len); + aggregation_bitfield.set(duties.committee_index, true); + + Some(Attestation { + aggregation_bitfield, + data: attestation, + custody_bitfield, + aggregate_signature, + }) + } + + /// Returns `true` if signing an attestation is safe (non-slashable). + /// + /// !!! UNSAFE !!! + /// + /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. + fn safe_to_produce(&self, _attestation: &AttestationData) -> bool { + //TODO: Implement slash protection + true + } + + /// Record that an attestation was produced so that slashable votes may not be made in the future. + /// + /// !!! UNSAFE !!! + /// + /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. + fn store_produce(&mut self, _attestation: &AttestationData) { + // TODO: Implement slash protection + } +} diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index ba0795ec1..91c91e0b1 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -290,6 +290,7 @@ impl Service { // the return value is a future which returns ready. // built to be compatible with the tokio runtime. let _empty = cloned_manager.run_update(current_epoch.clone(), cloned_log.clone()); + dbg!("Duties Thread Ended"); }); } @@ -317,6 +318,7 @@ impl Service { signer, }; block_producer.handle_produce_block(log); + dbg!("Block produce Thread Ended"); }); } if work_type.attestation_duty.is_some() { @@ -338,6 +340,7 @@ impl Service { signer, }; attestation_producer.handle_produce_attestation(log); + dbg!("Attestation Thread Ended"); }); } } From 51ffbc07d25644ef7a8ef0cea64a5d316ec8ec18 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 19:48:45 +1100 Subject: [PATCH 075/106] Correct attestation error handling --- beacon_node/rpc/src/attestation.rs | 5 +++-- .../src/attestation_producer/mod.rs | 21 +++++++++++++++---- validator_client/src/block_producer/mod.rs | 4 ++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/beacon_node/rpc/src/attestation.rs b/beacon_node/rpc/src/attestation.rs index f9423df61..aec948abb 100644 --- a/beacon_node/rpc/src/attestation.rs +++ b/beacon_node/rpc/src/attestation.rs @@ -25,7 +25,7 @@ impl AttestationService for AttestationServiceInstance { req: ProduceAttestationDataRequest, sink: UnarySink, ) { - warn!( + trace!( &self.log, "Attempting to produce attestation at slot {}", req.get_slot() @@ -92,7 +92,7 @@ impl AttestationService for AttestationServiceInstance { req: PublishAttestationRequest, sink: UnarySink, ) { - warn!(self.log, "Publishing attestation"); + trace!(self.log, "Publishing attestation"); let mut resp = PublishAttestationResponse::new(); let ssz_serialized_attestation = req.get_attestation().get_ssz(); @@ -128,6 +128,7 @@ impl AttestationService for AttestationServiceInstance { self.log, "PublishAttestation"; "type" => "invalid_attestation", + "error" => format!("{:?}", e), ); resp.set_success(false); resp.set_msg(format!("InvalidAttestation: {:?}", e).as_bytes().to_vec()); diff --git a/validator_client/src/attestation_producer/mod.rs b/validator_client/src/attestation_producer/mod.rs index 7b2174b0c..db9028c40 100644 --- a/validator_client/src/attestation_producer/mod.rs +++ b/validator_client/src/attestation_producer/mod.rs @@ -4,7 +4,7 @@ mod grpc; use std::sync::Arc; use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; //TODO: Move these higher up in the crate -use super::block_producer::{BeaconNodeError, ValidatorEvent}; +use super::block_producer::{BeaconNodeError, PublishOutcome, ValidatorEvent}; use crate::signer::Signer; use beacon_node_attestation::BeaconNodeAttestation; use slog::{error, info, warn}; @@ -58,6 +58,12 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(_slot)) => { error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to produce an attestation")) } + Ok(ValidatorEvent::PublishAttestationFailed) => { + error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to publish an attestation")) + } + Ok(ValidatorEvent::InvalidAttestation) => { + error!(log, "Attestation production error"; "Error" => format!("The signed attestation was invalid")) + } Ok(v) => { warn!(log, "Unknown result for attestation production"; "Error" => format!("{:?}",v)) } @@ -83,8 +89,15 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { if self.safe_to_produce(&attestation) { let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork); if let Some(attestation) = self.sign_attestation(attestation, self.duty, domain) { - self.beacon_node.publish_attestation(attestation)?; - Ok(ValidatorEvent::AttestationProduced(self.duty.slot)) + match self.beacon_node.publish_attestation(attestation) { + Ok(PublishOutcome::InvalidAttestation(_string)) => { + Ok(ValidatorEvent::InvalidAttestation) + } + Ok(PublishOutcome::Valid) => { + Ok(ValidatorEvent::AttestationProduced(self.duty.slot)) + } + Err(_) | Ok(_) => Ok(ValidatorEvent::PublishAttestationFailed), + } } else { Ok(ValidatorEvent::SignerRejection(self.duty.slot)) } @@ -101,7 +114,7 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// done upstream. fn sign_attestation( &mut self, - mut attestation: AttestationData, + attestation: AttestationData, duties: AttestationDuty, domain: u64, ) -> Option { diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index 592c0b919..dc7f6c3ee 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -31,6 +31,10 @@ pub enum ValidatorEvent { BeaconNodeUnableToProduceAttestation(Slot), /// The signer failed to sign the message. SignerRejection(Slot), + /// Publishing an attestation failed. + PublishAttestationFailed, + /// Beacon node rejected the attestation. + InvalidAttestation, } /// This struct contains the logic for requesting and signing beacon blocks for a validator. The From 9a6ecc46657305f4f07e1974e896918244b2a9e7 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sat, 30 Mar 2019 19:58:19 +1100 Subject: [PATCH 076/106] Add clippy suggestions --- .../src/attestation_producer/mod.rs | 13 ++++------ validator_client/src/block_producer/mod.rs | 25 ++++++++----------- validator_client/src/duties/grpc.rs | 5 ++-- validator_client/src/duties/mod.rs | 2 +- validator_client/src/service.rs | 9 +++---- 5 files changed, 22 insertions(+), 32 deletions(-) diff --git a/validator_client/src/attestation_producer/mod.rs b/validator_client/src/attestation_producer/mod.rs index db9028c40..0fbc7bcba 100644 --- a/validator_client/src/attestation_producer/mod.rs +++ b/validator_client/src/attestation_producer/mod.rs @@ -2,7 +2,7 @@ mod beacon_node_attestation; mod grpc; use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; +use types::{ChainSpec, Domain, Fork}; //TODO: Move these higher up in the crate use super::block_producer::{BeaconNodeError, PublishOutcome, ValidatorEvent}; use crate::signer::Signer; @@ -50,19 +50,16 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { } Err(e) => error!(log, "Attestation production error"; "Error" => format!("{:?}", e)), Ok(ValidatorEvent::SignerRejection(_slot)) => { - error!(log, "Attestation production error"; "Error" => format!("Signer could not sign the attestation")) + error!(log, "Attestation production error"; "Error" => "Signer could not sign the attestation".to_string()) } Ok(ValidatorEvent::SlashableAttestationNotProduced(_slot)) => { - error!(log, "Attestation production error"; "Error" => format!("Rejected the attestation as it could have been slashed")) - } - Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(_slot)) => { - error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to produce an attestation")) + error!(log, "Attestation production error"; "Error" => "Rejected the attestation as it could have been slashed".to_string()) } Ok(ValidatorEvent::PublishAttestationFailed) => { - error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to publish an attestation")) + error!(log, "Attestation production error"; "Error" => "Beacon node was unable to publish an attestation".to_string()) } Ok(ValidatorEvent::InvalidAttestation) => { - error!(log, "Attestation production error"; "Error" => format!("The signed attestation was invalid")) + error!(log, "Attestation production error"; "Error" => "The signed attestation was invalid".to_string()) } Ok(v) => { warn!(log, "Unknown result for attestation production"; "Error" => format!("{:?}",v)) diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index dc7f6c3ee..8b4f5abda 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -27,8 +27,6 @@ pub enum ValidatorEvent { SlashableAttestationNotProduced(Slot), /// The Beacon Node was unable to produce a block at that slot. BeaconNodeUnableToProduceBlock(Slot), - /// The Beacon Node was unable to produce an attestation at that slot. - BeaconNodeUnableToProduceAttestation(Slot), /// The signer failed to sign the message. SignerRejection(Slot), /// Publishing an attestation failed. @@ -61,13 +59,13 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { } Err(e) => error!(log, "Block production error"; "Error" => format!("{:?}", e)), Ok(ValidatorEvent::SignerRejection(_slot)) => { - error!(log, "Block production error"; "Error" => format!("Signer Could not sign the block")) + error!(log, "Block production error"; "Error" => "Signer Could not sign the block".to_string()) } Ok(ValidatorEvent::SlashableBlockNotProduced(_slot)) => { - error!(log, "Block production error"; "Error" => format!("Rejected the block as it could have been slashed")) + error!(log, "Block production error"; "Error" => "Rejected the block as it could have been slashed".to_string()) } Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(_slot)) => { - error!(log, "Block production error"; "Error" => format!("Beacon node was unable to produce a block")) + error!(log, "Block production error"; "Error" => "Beacon node was unable to produce a block".to_string()) } Ok(v) => { warn!(log, "Unknown result for block production"; "Error" => format!("{:?}",v)) @@ -88,16 +86,13 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { pub fn produce_block(&mut self) -> Result { let epoch = self.slot.epoch(self.spec.slots_per_epoch); - let randao_reveal = { - let message = epoch.hash_tree_root(); - let randao_reveal = match self.signer.sign_message( - &message, - self.spec.get_domain(epoch, Domain::Randao, &self.fork), - ) { - None => return Ok(ValidatorEvent::SignerRejection(self.slot)), - Some(signature) => signature, - }; - randao_reveal + let message = epoch.hash_tree_root(); + let randao_reveal = match self.signer.sign_message( + &message, + self.spec.get_domain(epoch, Domain::Randao, &self.fork), + ) { + None => return Ok(ValidatorEvent::SignerRejection(self.slot)), + Some(signature) => signature, }; if let Some(block) = self diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index ab87b602e..954ee194e 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -1,11 +1,12 @@ use super::beacon_node_duties::{BeaconNodeDuties, BeaconNodeDutiesError}; use super::epoch_duties::{EpochDuties, EpochDuty}; -use grpcio::CallOption; +// to use if we manually specify a timeout +//use grpcio::CallOption; use protos::services::{GetDutiesRequest, Validators}; use protos::services_grpc::ValidatorServiceClient; use ssz::ssz_encode; use std::collections::HashMap; -use std::time::Duration; +// use std::time::Duration; use types::{AttestationDuty, Epoch, PublicKey, Slot}; impl BeaconNodeDuties for ValidatorServiceClient { diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs index d52cc3254..7db4672e3 100644 --- a/validator_client/src/duties/mod.rs +++ b/validator_client/src/duties/mod.rs @@ -69,7 +69,7 @@ impl DutiesManager { // duties have changed //TODO: Duties could be large here. Remove from display and avoid the clone. self.duties_map.write()?.insert(epoch, duties.clone()); - return Ok(UpdateOutcome::DutiesChanged(epoch, duties)); + Ok(UpdateOutcome::DutiesChanged(epoch, duties)) } /// A future wrapping around `update()`. This will perform logic based upon the update diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 91c91e0b1..ce9e35266 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -157,7 +157,7 @@ impl Service { let current_slot = slot_clock .present_slot() - .map_err(|e| ErrorKind::SlotClockError(e))? + .map_err(ErrorKind::SlotClockError)? .expect("Genesis must be in the future"); /* Generate the duties manager */ @@ -289,8 +289,7 @@ impl Service { std::thread::spawn(move || { // the return value is a future which returns ready. // built to be compatible with the tokio runtime. - let _empty = cloned_manager.run_update(current_epoch.clone(), cloned_log.clone()); - dbg!("Duties Thread Ended"); + let _empty = cloned_manager.run_update(current_epoch, cloned_log.clone()); }); } @@ -303,7 +302,7 @@ impl Service { // spawns a thread to produce a beacon block let signers = self.duties_manager.signers.clone(); // this is an arc let fork = self.fork.clone(); - let slot = self.current_slot.clone(); + let slot = self.current_slot; let spec = self.spec.clone(); let beacon_node = self.beacon_block_client.clone(); let log = self.log.clone(); @@ -318,7 +317,6 @@ impl Service { signer, }; block_producer.handle_produce_block(log); - dbg!("Block produce Thread Ended"); }); } if work_type.attestation_duty.is_some() { @@ -340,7 +338,6 @@ impl Service { signer, }; attestation_producer.handle_produce_attestation(log); - dbg!("Attestation Thread Ended"); }); } } From 4fb95d06d1062e1779f24d4cda23a89c4f9a6f9f Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 31 Mar 2019 00:08:55 +1100 Subject: [PATCH 077/106] Correct cache race condition --- beacon_node/rpc/src/beacon_chain.rs | 8 +++++++- beacon_node/rpc/src/validator.rs | 18 ++++++++++++++---- .../test_utils/testing_beacon_state_builder.rs | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/beacon_node/rpc/src/beacon_chain.rs b/beacon_node/rpc/src/beacon_chain.rs index 7de48efa1..ddc91b73c 100644 --- a/beacon_node/rpc/src/beacon_chain.rs +++ b/beacon_node/rpc/src/beacon_chain.rs @@ -2,7 +2,7 @@ use beacon_chain::BeaconChain as RawBeaconChain; use beacon_chain::{ db::ClientDB, fork_choice::ForkChoice, - parking_lot::RwLockReadGuard, + parking_lot::{RwLockReadGuard, RwLockWriteGuard}, slot_clock::SlotClock, types::{BeaconState, ChainSpec, Signature}, AttestationValidationError, BlockProductionError, @@ -16,6 +16,8 @@ pub trait BeaconChain: Send + Sync { fn get_state(&self) -> RwLockReadGuard; + fn get_mut_state(&self) -> RwLockWriteGuard; + fn process_block(&self, block: BeaconBlock) -> Result; @@ -46,6 +48,10 @@ where self.state.read() } + fn get_mut_state(&self) -> RwLockWriteGuard { + self.state.write() + } + fn process_block( &self, block: BeaconBlock, diff --git a/beacon_node/rpc/src/validator.rs b/beacon_node/rpc/src/validator.rs index 936c95f52..a60cb4394 100644 --- a/beacon_node/rpc/src/validator.rs +++ b/beacon_node/rpc/src/validator.rs @@ -4,7 +4,7 @@ use futures::Future; use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink}; use protos::services::{ActiveValidator, GetDutiesRequest, GetDutiesResponse, ValidatorDuty}; use protos::services_grpc::ValidatorService; -use slog::{debug, info, warn, Logger}; +use slog::{trace, warn}; use ssz::Decodable; use std::sync::Arc; use types::{Epoch, RelativeEpoch}; @@ -12,7 +12,7 @@ use types::{Epoch, RelativeEpoch}; #[derive(Clone)] pub struct ValidatorServiceInstance { pub chain: Arc, - pub log: Logger, + pub log: slog::Logger, } //TODO: Refactor Errors @@ -27,13 +27,23 @@ impl ValidatorService for ValidatorServiceInstance { sink: UnarySink, ) { let validators = req.get_validators(); - debug!(self.log, "RPC request"; "endpoint" => "GetValidatorDuties", "epoch" => req.get_epoch()); + trace!(self.log, "RPC request"; "endpoint" => "GetValidatorDuties", "epoch" => req.get_epoch()); + + let spec = self.chain.get_spec(); + // update the caches if necessary + { + let mut mut_state = self.chain.get_mut_state(); + + let _ = mut_state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, spec); + + let _ = mut_state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, spec); + let _ = mut_state.update_pubkey_cache(); + } let epoch = Epoch::from(req.get_epoch()); let mut resp = GetDutiesResponse::new(); let resp_validators = resp.mut_active_validators(); - let spec = self.chain.get_spec(); let state = self.chain.get_state(); let relative_epoch = diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index 8d0aa6af6..c04188920 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -120,7 +120,7 @@ impl TestingBeaconStateBuilder { }) .collect(); - let genesis_time = 1553932445; // arbitrary + let genesis_time = 1553950542; // arbitrary let mut state = BeaconState::genesis( genesis_time, From ee693fb3e3942ad175cc5f441903795afdedcf16 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 31 Mar 2019 00:34:35 +1100 Subject: [PATCH 078/106] Add committe_len to gRPC parameters --- beacon_node/rpc/src/attestation.rs | 2 +- beacon_node/rpc/src/validator.rs | 1 + protos/src/services.proto | 1 + validator_client/src/duties/grpc.rs | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/beacon_node/rpc/src/attestation.rs b/beacon_node/rpc/src/attestation.rs index aec948abb..c6e5c68ee 100644 --- a/beacon_node/rpc/src/attestation.rs +++ b/beacon_node/rpc/src/attestation.rs @@ -6,7 +6,7 @@ use protos::services::{ ProduceAttestationDataResponse, PublishAttestationRequest, PublishAttestationResponse, }; use protos::services_grpc::AttestationService; -use slog::{error, info, trace, warn, Logger}; +use slog::{error, info, trace, warn}; use ssz::{ssz_encode, Decodable}; use std::sync::Arc; use types::Attestation; diff --git a/beacon_node/rpc/src/validator.rs b/beacon_node/rpc/src/validator.rs index a60cb4394..3dbbbdd17 100644 --- a/beacon_node/rpc/src/validator.rs +++ b/beacon_node/rpc/src/validator.rs @@ -167,6 +167,7 @@ impl ValidatorService for ValidatorServiceInstance { duty.set_committee_index(attestation_duties.committee_index as u64); duty.set_attestation_slot(attestation_duties.slot.as_u64()); duty.set_attestation_shard(attestation_duties.shard); + duty.set_committee_len(attestation_duties.committee_len as u64); active_validator.set_duty(duty); resp_validators.push(active_validator); diff --git a/protos/src/services.proto b/protos/src/services.proto index c5bd8a91d..ecc75ee26 100644 --- a/protos/src/services.proto +++ b/protos/src/services.proto @@ -125,6 +125,7 @@ message ValidatorDuty { uint64 attestation_slot = 3; uint64 attestation_shard = 4; uint64 committee_index = 5; + uint64 committee_len = 6; } /* diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index 954ee194e..58fb5c992 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -53,7 +53,7 @@ impl BeaconNodeDuties for ValidatorServiceClient { slot: Slot::from(active_duty.get_attestation_slot()), shard: active_duty.get_attestation_shard(), committee_index: active_duty.get_committee_index() as usize, - committee_len: 10, + committee_len: active_duty.get_committee_len() as usize, }; let epoch_duty = EpochDuty { From d2b5cf5a32eeee3ff69dbcf436f2dfba23600891 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 09:44:58 +1100 Subject: [PATCH 079/106] Improve queueing in SimpleSync --- beacon_node/eth2-libp2p/src/rpc/methods.rs | 13 ++++ beacon_node/network/src/sync/import_queue.rs | 54 ++++++++++--- beacon_node/network/src/sync/simple_sync.rs | 78 +++++++++++++------ .../testing_beacon_state_builder.rs | 2 +- 4 files changed, 115 insertions(+), 32 deletions(-) diff --git a/beacon_node/eth2-libp2p/src/rpc/methods.rs b/beacon_node/eth2-libp2p/src/rpc/methods.rs index ad3233be7..f9adb93c1 100644 --- a/beacon_node/eth2-libp2p/src/rpc/methods.rs +++ b/beacon_node/eth2-libp2p/src/rpc/methods.rs @@ -179,6 +179,19 @@ pub struct BeaconBlockRootsResponse { pub roots: Vec, } +impl BeaconBlockRootsResponse { + /// Returns `true` if each `self.roots.slot[i]` is higher than the preceeding `i`. + pub fn slots_are_ascending(&self) -> bool { + for i in 1..self.roots.len() { + if self.roots[i - 1].slot >= self.roots[i].slot { + return false; + } + } + + true + } +} + /// Contains a block root and associated slot. #[derive(Encode, Decode, Clone, Debug, PartialEq)] pub struct BlockRootSlot { diff --git a/beacon_node/network/src/sync/import_queue.rs b/beacon_node/network/src/sync/import_queue.rs index 17cbd2f12..8680993aa 100644 --- a/beacon_node/network/src/sync/import_queue.rs +++ b/beacon_node/network/src/sync/import_queue.rs @@ -5,7 +5,7 @@ use slog::{debug, error}; use ssz::TreeHash; use std::sync::Arc; use std::time::{Duration, Instant}; -use types::{BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Hash256}; +use types::{BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Hash256, Slot}; /// Provides a queue for fully and partially built `BeaconBlock`s. /// @@ -120,6 +120,38 @@ impl ImportQueue { .position(|brs| self.is_new_block(&brs.block_root)) } + /// Adds the `block_roots` to the partials queue. + /// + /// If a `block_root` is not in the queue and has not been processed by the chain it is added + /// to the queue and it's block root is included in the output. + pub fn enqueue_block_roots( + &mut self, + block_roots: &[BlockRootSlot], + sender: PeerId, + ) -> Vec { + let new_roots: Vec = block_roots + .iter() + // Ignore any roots already processed by the chain. + .filter(|brs| self.is_new_block(&brs.block_root)) + // Ignore any roots already stored in the queue. + .filter(|brs| !self.partials.iter().any(|p| p.block_root == brs.block_root)) + .cloned() + .collect(); + + new_roots.iter().for_each(|brs| { + self.partials.push(PartialBeaconBlock { + slot: brs.slot, + block_root: brs.block_root, + sender: sender.clone(), + header: None, + body: None, + inserted: Instant::now(), + }) + }); + + new_roots + } + /// Adds the `headers` to the `partials` queue. Returns a list of `Hash256` block roots for /// which we should use to request `BeaconBlockBodies`. /// @@ -174,8 +206,9 @@ impl ImportQueue { self.partials[i].inserted = Instant::now(); } else { self.partials.push(PartialBeaconBlock { + slot: header.slot, block_root, - header, + header: Some(header), body: None, inserted: Instant::now(), sender, @@ -192,12 +225,14 @@ impl ImportQueue { let body_root = Hash256::from_slice(&body.hash_tree_root()[..]); self.partials.iter_mut().for_each(|mut p| { - if body_root == p.header.block_body_root { - p.inserted = Instant::now(); + if let Some(header) = &mut p.header { + if body_root == header.block_body_root { + p.inserted = Instant::now(); - if p.body.is_none() { - p.body = Some(body.clone()); - p.sender = sender.clone(); + if p.body.is_none() { + p.body = Some(body.clone()); + p.sender = sender.clone(); + } } } }); @@ -208,9 +243,10 @@ impl ImportQueue { /// `BeaconBlock`. #[derive(Clone, Debug)] pub struct PartialBeaconBlock { + pub slot: Slot, /// `BeaconBlock` root. pub block_root: Hash256, - pub header: BeaconBlockHeader, + pub header: Option, pub body: Option, /// The instant at which this record was created or last meaningfully modified. Used to /// determine if an entry is stale and should be removed. @@ -225,7 +261,7 @@ impl PartialBeaconBlock { pub fn complete(self) -> Option<(Hash256, BeaconBlock, PeerId)> { Some(( self.block_root, - self.header.into_block(self.body?), + self.header?.into_block(self.body?), self.sender, )) } diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 1afba018d..21b261268 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -358,31 +358,48 @@ impl SimpleSync { if res.roots.is_empty() { warn!( self.log, - "Peer returned empty block roots response. PeerId: {:?}", peer_id + "Peer returned empty block roots response"; + "peer_id" => format!("{:?}", peer_id) ); return; } - let new_root_index = self.import_queue.first_new_root(&res.roots); - - // If a new block root is found, request it and all the headers following it. - // - // We make an assumption here that if we don't know a block then we don't know of all - // it's parents. This might not be the case if syncing becomes more sophisticated. - if let Some(i) = new_root_index { - let new = &res.roots[i]; - - self.request_block_headers( - peer_id, - BeaconBlockHeadersRequest { - start_root: new.block_root, - start_slot: new.slot, - max_headers: (res.roots.len() - i) as u64, - skip_slots: 0, - }, - network, - ) + // The wire protocol specifies that slots must be in ascending order. + if !res.slots_are_ascending() { + warn!( + self.log, + "Peer returned block roots response with bad slot ordering"; + "peer_id" => format!("{:?}", peer_id) + ); + return; } + + let new_roots = self.import_queue.enqueue_block_roots(&res.roots, peer_id.clone()); + + // No new roots means nothing to do. + // + // This check protects against future panics. + if new_roots.is_empty() { + return; + } + + // Determine the first (earliest) and last (latest) `BlockRootSlot` items. + // + // This logic relies upon slots to be in ascending order, which is enforced earlier. + let first = new_roots.first().expect("Non-empty list must have first"); + let last = new_roots.last().expect("Non-empty list must have last"); + + // Request all headers between the earliest and latest new `BlockRootSlot` items. + self.request_block_headers( + peer_id, + BeaconBlockHeadersRequest { + start_root: first.block_root, + start_slot: first.slot, + max_headers: (last.slot - first.slot + 1).as_u64(), + skip_slots: 0, + }, + network, + ) } /// Handle a `BeaconBlockHeaders` request from the peer. @@ -528,8 +545,17 @@ impl SimpleSync { "NewGossipBlock"; "peer" => format!("{:?}", peer_id), ); - // TODO: filter out messages that a prior to the finalized slot. - // + + // Ignore any block from a finalized slot. + if self.slot_is_finalized(msg.slot) { + warn!( + self.log, "NewGossipBlock"; + "msg" => "new block slot is finalized.", + "slot" => msg.slot, + ); + return; + } + // TODO: if the block is a few more slots ahead, try to get all block roots from then until // now. // @@ -675,6 +701,14 @@ impl SimpleSync { network.send_rpc_request(peer_id.clone(), RPCRequest::BeaconBlockBodies(req)); } + fn slot_is_finalized(&self, slot: Slot) -> bool { + slot <= self + .chain + .hello_message() + .latest_finalized_epoch + .start_slot(self.chain.get_spec().slots_per_epoch) + } + /// Generates our current state in the form of a HELLO RPC message. pub fn generate_hello(&self) -> HelloMessage { self.chain.hello_message() diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index b38e8b527..f437240dc 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -120,7 +120,7 @@ impl TestingBeaconStateBuilder { }) .collect(); - let genesis_time = 1553753928; // arbitrary + let genesis_time = 1553977336; // arbitrary let mut state = BeaconState::genesis( genesis_time, From 5cc2fdd3d4bb932196da410f852082442c5e43d0 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 10:15:01 +1100 Subject: [PATCH 080/106] Change `beacon_node` and `network` slog features Allows printing debug messages in --release --- beacon_node/Cargo.toml | 2 +- beacon_node/network/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index a090c1cc5..37d96a497 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -9,7 +9,7 @@ types = { path = "../eth2/types" } client = { path = "client" } version = { path = "version" } clap = "2.32.0" -slog = "^2.2.3" +slog = { version = "^2.2.3" , features = ["max_level_trace", "release_max_level_debug"] } slog-term = "^2.4.0" slog-async = "^2.3.0" ctrlc = { version = "3.1.1", features = ["termination"] } diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index c6411a020..cd2c2269a 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -13,7 +13,7 @@ beacon_chain = { path = "../beacon_chain" } eth2-libp2p = { path = "../eth2-libp2p" } version = { path = "../version" } types = { path = "../../eth2/types" } -slog = "2.4.1" +slog = { version = "^2.2.3" , features = ["max_level_trace", "release_max_level_debug"] } ssz = { path = "../../eth2/utils/ssz" } futures = "0.1.25" error-chain = "0.12.0" From c99a742aae515564a575fc65279dca18cb92d5fe Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 10:15:42 +1100 Subject: [PATCH 081/106] Fix bug in SimpleSync queue. It was not completing partials with bodies. --- beacon_node/network/src/sync/import_queue.rs | 16 +++++++++------- beacon_node/network/src/sync/simple_sync.rs | 4 +++- beacon_node/network/tests/tests.rs | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/beacon_node/network/src/sync/import_queue.rs b/beacon_node/network/src/sync/import_queue.rs index 8680993aa..b9280440b 100644 --- a/beacon_node/network/src/sync/import_queue.rs +++ b/beacon_node/network/src/sync/import_queue.rs @@ -113,13 +113,6 @@ impl ImportQueue { }) } - /// Returns the index of the first new root in the list of block roots. - pub fn first_new_root(&mut self, roots: &[BlockRootSlot]) -> Option { - roots - .iter() - .position(|brs| self.is_new_block(&brs.block_root)) - } - /// Adds the `block_roots` to the partials queue. /// /// If a `block_root` is not in the queue and has not been processed by the chain it is added @@ -203,8 +196,17 @@ impl ImportQueue { .iter() .position(|p| p.block_root == block_root) { + // Case 1: there already exists a partial with a matching block root. + // + // The `inserted` time is set to now and the header is replaced, regardless of whether + // it existed or not. + self.partials[i].header = Some(header); self.partials[i].inserted = Instant::now(); } else { + // Case 2: there was no partial with a matching block root. + // + // A new partial is added. This case permits adding a header without already known the + // root -- this is not possible in the wire protocol however we support it anyway. self.partials.push(PartialBeaconBlock { slot: header.slot, block_root, diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 21b261268..39fe772b4 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -374,7 +374,9 @@ impl SimpleSync { return; } - let new_roots = self.import_queue.enqueue_block_roots(&res.roots, peer_id.clone()); + let new_roots = self + .import_queue + .enqueue_block_roots(&res.roots, peer_id.clone()); // No new roots means nothing to do. // diff --git a/beacon_node/network/tests/tests.rs b/beacon_node/network/tests/tests.rs index 9cead1b55..47d5482d3 100644 --- a/beacon_node/network/tests/tests.rs +++ b/beacon_node/network/tests/tests.rs @@ -543,7 +543,7 @@ fn sync_two_nodes() { // A provides block bodies to B. node_a.tee_block_body_response(&node_b); - std::thread::sleep(Duration::from_secs(10)); + std::thread::sleep(Duration::from_secs(20)); node_b.harness.run_fork_choice(); From e0680f97711b64b97e477e0d948ca968d59d6ab7 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 31 Mar 2019 11:04:50 +1100 Subject: [PATCH 082/106] Correct compile error --- beacon_node/beacon_chain/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 7605ced15..d8d85a8a6 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -4,9 +4,7 @@ mod errors; pub mod initialise; pub mod test_utils; -pub use self::beacon_chain::{ - AttestationValidationError, BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock, -}; +pub use self::beacon_chain::{BeaconChain, BlockProcessingOutcome, InvalidBlock, ValidBlock}; pub use self::checkpoint::CheckPoint; pub use self::errors::{BeaconChainError, BlockProductionError}; pub use db; From 2c1fa86cd317b970aed03fbebe23329051f54062 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 12:28:35 +1100 Subject: [PATCH 083/106] Swap to gossiping whole block. Processing for gossiped blocks is broken in `SimpleSync`, will be fixed next. --- beacon_node/eth2-libp2p/src/behaviour.rs | 13 +++----- beacon_node/network/src/sync/simple_sync.rs | 35 ++++++++++++++++----- beacon_node/rpc/src/beacon_block.rs | 33 ++++++++++--------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/beacon_node/eth2-libp2p/src/behaviour.rs b/beacon_node/eth2-libp2p/src/behaviour.rs index 286597183..fdf12f0bf 100644 --- a/beacon_node/eth2-libp2p/src/behaviour.rs +++ b/beacon_node/eth2-libp2p/src/behaviour.rs @@ -1,4 +1,3 @@ -use crate::rpc::methods::BlockRootSlot; use crate::rpc::{RPCEvent, RPCMessage, Rpc}; use crate::NetworkConfig; use futures::prelude::*; @@ -15,8 +14,7 @@ use libp2p::{ }; use slog::{debug, o, warn}; use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream}; -use ssz_derive::{Decode, Encode}; -use types::Attestation; +use types::{Attestation, BeaconBlock}; use types::{Topic, TopicHash}; /// Builds the network behaviour for the libp2p Swarm. @@ -198,7 +196,7 @@ pub enum BehaviourEvent { #[derive(Debug, Clone, PartialEq)] pub enum PubsubMessage { /// Gossipsub message providing notification of a new block. - Block(BlockRootSlot), + Block(BeaconBlock), /// Gossipsub message providing notification of a new attestation. Attestation(Attestation), } @@ -224,7 +222,7 @@ impl Decodable for PubsubMessage { let (id, index) = u32::ssz_decode(bytes, index)?; match id { 0 => { - let (block, index) = BlockRootSlot::ssz_decode(bytes, index)?; + let (block, index) = BeaconBlock::ssz_decode(bytes, index)?; Ok((PubsubMessage::Block(block), index)) } 1 => { @@ -243,10 +241,7 @@ mod test { #[test] fn ssz_encoding() { - let original = PubsubMessage::Block(BlockRootSlot { - block_root: Hash256::from_slice(&[42; 32]), - slot: Slot::new(4), - }); + let original = PubsubMessage::Block(BeaconBlock::empty(&ChainSpec::foundation())); let encoded = ssz_encode(&original); diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 39fe772b4..e8a3da656 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -8,7 +8,7 @@ use slog::{debug, error, info, o, warn}; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; -use types::{Attestation, Epoch, Hash256, Slot}; +use types::{Attestation, BeaconBlock, Epoch, Hash256, Slot}; /// The number of slots that we can import blocks ahead of us, before going into full Sync mode. const SLOT_IMPORT_TOLERANCE: u64 = 100; @@ -539,7 +539,7 @@ impl SimpleSync { pub fn on_block_gossip( &mut self, peer_id: PeerId, - msg: BlockRootSlot, + block: BeaconBlock, network: &mut NetworkContext, ) { info!( @@ -548,6 +548,7 @@ impl SimpleSync { "peer" => format!("{:?}", peer_id), ); + /* // Ignore any block from a finalized slot. if self.slot_is_finalized(msg.slot) { warn!( @@ -558,11 +559,13 @@ impl SimpleSync { return; } - // TODO: if the block is a few more slots ahead, try to get all block roots from then until - // now. - // - // Note: only requests the new block -- will fail if we don't have its parents. - if self.import_queue.is_new_block(&msg.block_root) { + // Ignore any block that the chain already knows about. + if self.chain_has_seen_block(&msg.block_root) { + return; + } + + // k + if msg.slot == self.chain.hello_message().best_slot + 1 { self.request_block_headers( peer_id, BeaconBlockHeadersRequest { @@ -574,6 +577,24 @@ impl SimpleSync { network, ) } + + // TODO: if the block is a few more slots ahead, try to get all block roots from then until + // now. + // + // Note: only requests the new block -- will fail if we don't have its parents. + if !self.chain_has_seen_block(&msg.block_root) { + self.request_block_headers( + peer_id, + BeaconBlockHeadersRequest { + start_root: msg.block_root, + start_slot: msg.slot, + max_headers: 1, + skip_slots: 0, + }, + network, + ) + } + */ } /// Process a gossip message declaring a new attestation. diff --git a/beacon_node/rpc/src/beacon_block.rs b/beacon_node/rpc/src/beacon_block.rs index f6b426c18..6978e0f0e 100644 --- a/beacon_node/rpc/src/beacon_block.rs +++ b/beacon_node/rpc/src/beacon_block.rs @@ -1,6 +1,5 @@ use crate::beacon_chain::BeaconChain; use crossbeam_channel; -use eth2_libp2p::rpc::methods::BlockRootSlot; use eth2_libp2p::PubsubMessage; use futures::Future; use grpcio::{RpcContext, UnarySink}; @@ -11,10 +10,10 @@ use protos::services::{ }; use protos::services_grpc::BeaconBlockService; use slog::Logger; -use slog::{debug, error, info, warn}; -use ssz::{Decodable, TreeHash}; +use slog::{error, info, warn}; +use ssz::Decodable; use std::sync::Arc; -use types::{BeaconBlock, Hash256, Slot}; +use types::BeaconBlock; #[derive(Clone)] pub struct BeaconBlockServiceInstance { @@ -59,8 +58,6 @@ impl BeaconBlockService for BeaconBlockServiceInstance { match BeaconBlock::ssz_decode(ssz_serialized_block, 0) { Ok((block, _i)) => { - let block_root = Hash256::from_slice(&block.hash_tree_root()[..]); - match self.chain.process_block(block.clone()) { Ok(outcome) => { if outcome.sucessfully_processed() { @@ -76,16 +73,22 @@ impl BeaconBlockService for BeaconBlockServiceInstance { // TODO: Obtain topics from the network service properly. let topic = types::TopicBuilder::new("beacon_chain".to_string()).build(); - let message = PubsubMessage::Block(BlockRootSlot { - block_root, - slot: block.slot, - }); + let message = PubsubMessage::Block(block); - println!("Sending beacon block to gossipsub"); - self.network_chan.send(NetworkMessage::Publish { - topics: vec![topic], - message, - }); + // Publish the block to the p2p network via gossipsub. + self.network_chan + .send(NetworkMessage::Publish { + topics: vec![topic], + message, + }) + .unwrap_or_else(|e| { + error!( + self.log, + "PublishBeaconBlock"; + "type" => "failed to publish to gossipsub", + "error" => format!("{:?}", e) + ); + }); resp.set_success(true); } else if outcome.is_invalid() { From 4e71ed69721dd7d665169a043389e7c3062679b9 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 12:54:42 +1100 Subject: [PATCH 084/106] Fix `produce_attestation` bug. It was referencing the wrong crosslink. --- beacon_node/beacon_chain/src/beacon_chain.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 6ca0bff73..efa83bdd3 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -492,10 +492,7 @@ where beacon_block_root: self.head().beacon_block_root, target_root, crosslink_data_root: Hash256::zero(), - previous_crosslink: Crosslink { - epoch: self.state.read().slot.epoch(self.spec.slots_per_epoch), - crosslink_data_root: Hash256::zero(), - }, + previous_crosslink: state.latest_crosslinks[shard as usize].clone(), source_epoch: state.current_justified_epoch, source_root: state.current_justified_root, }) From b26f1f8e1cfd357f2991d1e8230a52305f491a44 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 13:40:12 +1100 Subject: [PATCH 085/106] Add `build_all_caches` method to `BeaconState` Also adds a few more cache builds in BeaconChain. --- beacon_node/beacon_chain/src/beacon_chain.rs | 23 ++++++++++++-------- eth2/types/src/beacon_state.rs | 11 ++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index efa83bdd3..046f37a81 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -130,10 +130,7 @@ where state_root, )); - genesis_state.build_epoch_cache(RelativeEpoch::Previous, &spec)?; - genesis_state.build_epoch_cache(RelativeEpoch::Current, &spec)?; - genesis_state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, &spec)?; - genesis_state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, &spec)?; + genesis_state.build_all_caches(&spec)?; Ok(Self { block_store, @@ -318,6 +315,8 @@ where per_slot_processing(&mut state, &latest_block_header, &self.spec)?; } + state.build_all_caches(&self.spec)?; + *self.state.write() = state; Ok(()) @@ -342,11 +341,17 @@ where per_slot_processing(&mut *state, &latest_block_header, &self.spec)?; } - state.build_epoch_cache(RelativeEpoch::Previous, &self.spec)?; - state.build_epoch_cache(RelativeEpoch::Current, &self.spec)?; - state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, &self.spec)?; - state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, &self.spec)?; - state.update_pubkey_cache()?; + + state.build_all_caches(&self.spec)?; + + Ok(()) + } + + /// Build all of the caches on the current state. + /// + /// Ideally this shouldn't be required, however we leave it here for testing. + pub fn ensure_state_caches_are_built(&self) -> Result<(), Error> { + self.state.write().build_all_caches(&self.spec)?; Ok(()) } diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 1e5278124..774e8eb76 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -661,6 +661,17 @@ impl BeaconState { }) } + /// Build all the caches, if they need to be built. + pub fn build_all_caches(&mut self, spec: &ChainSpec) -> Result<(), Error> { + self.build_epoch_cache(RelativeEpoch::Previous, spec)?; + self.build_epoch_cache(RelativeEpoch::Current, spec)?; + self.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, spec)?; + self.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, spec)?; + self.update_pubkey_cache()?; + + Ok(()) + } + /// Build an epoch cache, unless it is has already been built. pub fn build_epoch_cache( &mut self, From 33473892f27df37fdec79fb4a7d76c8fe241083c Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 31 Mar 2019 14:26:58 +1100 Subject: [PATCH 086/106] Validator client fixes. Hack fix for genesis start time --- beacon_node/rpc/src/attestation.rs | 24 ++++++++++++++++--- beacon_node/rpc/src/validator.rs | 13 +--------- .../validate_attestation.rs | 3 +++ .../testing_beacon_state_builder.rs | 10 +++++++- validator_client/src/service.rs | 8 ++++++- 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/beacon_node/rpc/src/attestation.rs b/beacon_node/rpc/src/attestation.rs index c6e5c68ee..494b24067 100644 --- a/beacon_node/rpc/src/attestation.rs +++ b/beacon_node/rpc/src/attestation.rs @@ -37,14 +37,29 @@ impl AttestationService for AttestationServiceInstance { let state = self.chain.get_state(); // Start by performing some checks - // Check that the the AttestionData is for the current slot (otherwise it will not be valid) - if slot_requested != state.slot.as_u64() { + // Check that the AttestionData is for the current slot (otherwise it will not be valid) + if slot_requested > state.slot.as_u64() { let log_clone = self.log.clone(); let f = sink .fail(RpcStatus::new( RpcStatusCode::OutOfRange, Some(format!( - "AttestationData request for a slot that is not the current slot." + "AttestationData request for a slot that is in the future." + )), + )) + .map_err(move |e| { + error!(log_clone, "Failed to reply with failure {:?}: {:?}", req, e) + }); + return ctx.spawn(f); + } + // currently cannot handle past slots. TODO: Handle this case + else if slot_requested < state.slot.as_u64() { + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::InvalidArgument, + Some(format!( + "AttestationData request for a slot that is in the past." )), )) .map_err(move |e| { @@ -71,6 +86,9 @@ impl AttestationService for AttestationServiceInstance { } }; + dbg!("Produced attestation"); + dbg!(attestation_data.clone()); + let mut attestation_data_proto = AttestationDataProto::new(); attestation_data_proto.set_ssz(ssz_encode(&attestation_data)); diff --git a/beacon_node/rpc/src/validator.rs b/beacon_node/rpc/src/validator.rs index 3dbbbdd17..0a9d7015c 100644 --- a/beacon_node/rpc/src/validator.rs +++ b/beacon_node/rpc/src/validator.rs @@ -30,22 +30,11 @@ impl ValidatorService for ValidatorServiceInstance { trace!(self.log, "RPC request"; "endpoint" => "GetValidatorDuties", "epoch" => req.get_epoch()); let spec = self.chain.get_spec(); - // update the caches if necessary - { - let mut mut_state = self.chain.get_mut_state(); - - let _ = mut_state.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, spec); - - let _ = mut_state.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, spec); - let _ = mut_state.update_pubkey_cache(); - } - + let state = self.chain.get_state(); let epoch = Epoch::from(req.get_epoch()); let mut resp = GetDutiesResponse::new(); let resp_validators = resp.mut_active_validators(); - let state = self.chain.get_state(); - let relative_epoch = match RelativeEpoch::from_epoch(state.slot.epoch(spec.slots_per_epoch), epoch) { Ok(v) => v, diff --git a/eth2/state_processing/src/per_block_processing/validate_attestation.rs b/eth2/state_processing/src/per_block_processing/validate_attestation.rs index 3b89bec99..76b415796 100644 --- a/eth2/state_processing/src/per_block_processing/validate_attestation.rs +++ b/eth2/state_processing/src/per_block_processing/validate_attestation.rs @@ -99,6 +99,9 @@ fn validate_attestation_parametric( crosslink_data_root: attestation.data.crosslink_data_root, epoch: attestation.data.slot.epoch(spec.slots_per_epoch), }; + dbg!(attestation.clone()); + dbg!(state.latest_crosslinks[attestation.data.shard as usize].clone()); + dbg!(potential_crosslink.clone()); verify!( (attestation.data.previous_crosslink == state.latest_crosslinks[attestation.data.shard as usize]) diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index f437240dc..518f55e3c 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -6,6 +6,8 @@ use dirs; use log::debug; use rayon::prelude::*; use std::path::{Path, PathBuf}; +//TODO: testing only +use std::time::{Duration, SystemTime}; pub const KEYPAIRS_FILE: &str = "keypairs.raw_keypairs"; @@ -120,7 +122,13 @@ impl TestingBeaconStateBuilder { }) .collect(); - let genesis_time = 1553977336; // arbitrary + //TODO: Testing only + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs() + - 30; + let genesis_time = now; // arbitrary let mut state = BeaconState::genesis( genesis_time, diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index ce9e35266..38883e68f 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -29,11 +29,15 @@ use std::sync::RwLock; use std::time::{Duration, Instant, SystemTime}; use tokio::prelude::*; use tokio::runtime::Builder; -use tokio::timer::Interval; +use tokio::timer::{Delay, Interval}; use tokio_timer::clock::Clock; use types::test_utils::generate_deterministic_keypairs; use types::{ChainSpec, Epoch, Fork, Slot}; +/// A fixed amount of time after a slot to perform operations. This gives the node time to complete +/// per-slot processes. +const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(200); + /// The validator service. This is the main thread that executes and maintains validator /// duties. //TODO: Generalize the BeaconNode types to use testing @@ -230,6 +234,8 @@ impl Service { runtime.block_on( interval .for_each(move |_| { + // wait for node to process + std::thread::sleep(TIME_DELAY_FROM_SLOT); // if a non-fatal error occurs, proceed to the next slot. let _ignore_error = service.per_slot_execution(); // completed a slot process From bd860eb3e155177ca47714e6f9356d42c39eb960 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 15:30:09 +1100 Subject: [PATCH 087/106] Fixes bug in epoch processing. - Was using the wrong slot to determine relative epoch. - Added a non-related test I build during the search --- .../src/per_epoch_processing/validator_statuses.rs | 2 +- eth2/types/src/slot_epoch.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs b/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs index 50f3ec372..02149cc5a 100644 --- a/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs +++ b/eth2/state_processing/src/per_epoch_processing/validator_statuses.rs @@ -227,7 +227,7 @@ impl ValidatorStatuses { status.is_previous_epoch_attester = true; // The inclusion slot and distance are only required for previous epoch attesters. - let relative_epoch = RelativeEpoch::from_slot(state.slot, a.data.slot, spec)?; + let relative_epoch = RelativeEpoch::from_slot(state.slot, a.inclusion_slot, spec)?; status.inclusion_info = Some(InclusionInfo { slot: a.inclusion_slot, distance: inclusion_distance(a), diff --git a/eth2/types/src/slot_epoch.rs b/eth2/types/src/slot_epoch.rs index c40b6badf..a8c32ef85 100644 --- a/eth2/types/src/slot_epoch.rs +++ b/eth2/types/src/slot_epoch.rs @@ -113,6 +113,16 @@ mod epoch_tests { all_tests!(Epoch); + #[test] + fn epoch_start_end() { + let slots_per_epoch = 8; + + let epoch = Epoch::new(0); + + assert_eq!(epoch.start_slot(slots_per_epoch), Slot::new(0)); + assert_eq!(epoch.end_slot(slots_per_epoch), Slot::new(7)); + } + #[test] fn slot_iter() { let slots_per_epoch = 8; From c6fc4f0769ae423f38cc3a46d162d79bd4425908 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 15:35:27 +1100 Subject: [PATCH 088/106] Fix bug in attestation production --- beacon_node/beacon_chain/src/beacon_chain.rs | 37 ++++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 046f37a81..b272520c5 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -482,14 +482,37 @@ where trace!("BeaconChain::produce_attestation: shard: {}", shard); let state = self.state.read(); - let target_root = *self.state.read().get_block_root( - self.state + let current_epoch_start_slot = self + .state + .read() + .slot + .epoch(self.spec.slots_per_epoch) + .start_slot(self.spec.slots_per_epoch); + + let target_root = if state.slot == current_epoch_start_slot { + // If we're on the first slot of the state's epoch. + if self.head().beacon_block.slot == state.slot { + // If the current head block is from the current slot, use its block root. + self.head().beacon_block_root + } else { + // If the current head block is not from this slot, use the slot from the previous + // epoch. + let root = *self.state.read().get_block_root( + current_epoch_start_slot - self.spec.slots_per_epoch, + &self.spec, + )?; + + root + } + } else { + // If we're not on the first slot of the epoch. + let root = *self + .state .read() - .slot - .epoch(self.spec.slots_per_epoch) - .start_slot(self.spec.slots_per_epoch), - &self.spec, - )?; + .get_block_root(current_epoch_start_slot, &self.spec)?; + + root + }; Ok(AttestationData { slot: self.state.read().slot, From c85da612f64c16640cbcfab2c8fbc3a9d6de12f1 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 31 Mar 2019 15:35:54 +1100 Subject: [PATCH 089/106] Remove debugging statements --- beacon_node/beacon_chain/src/beacon_chain.rs | 2 +- beacon_node/rpc/src/attestation.rs | 3 --- validator_client/src/attestation_producer/grpc.rs | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 046f37a81..f600fb1ac 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -290,7 +290,7 @@ where /// fork-choice rule). /// /// It is important to note that the `beacon_state` returned may not match the present slot. It - /// is the state as it was when the head block was recieved, which could be some slots prior to + /// is the state as it was when the head block was received, which could be some slots prior to /// now. pub fn head(&self) -> RwLockReadGuard { self.canonical_head.read() diff --git a/beacon_node/rpc/src/attestation.rs b/beacon_node/rpc/src/attestation.rs index 494b24067..abef49df1 100644 --- a/beacon_node/rpc/src/attestation.rs +++ b/beacon_node/rpc/src/attestation.rs @@ -86,9 +86,6 @@ impl AttestationService for AttestationServiceInstance { } }; - dbg!("Produced attestation"); - dbg!(attestation_data.clone()); - let mut attestation_data_proto = AttestationDataProto::new(); attestation_data_proto.set_ssz(ssz_encode(&attestation_data)); diff --git a/validator_client/src/attestation_producer/grpc.rs b/validator_client/src/attestation_producer/grpc.rs index 49c577e24..900a92f32 100644 --- a/validator_client/src/attestation_producer/grpc.rs +++ b/validator_client/src/attestation_producer/grpc.rs @@ -22,8 +22,6 @@ impl BeaconNodeAttestation for AttestationServiceClient { .produce_attestation_data(&req) .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - dbg!("Produced Attestation Data"); - let (attestation_data, _index) = AttestationData::ssz_decode(reply.get_attestation_data().get_ssz(), 0) .map_err(|_| BeaconNodeError::DecodeFailure)?; From e0b5e74e7cb269b75db4ec2469bbf8fd29bfa45c Mon Sep 17 00:00:00 2001 From: Age Manning Date: Sun, 31 Mar 2019 15:45:52 +1100 Subject: [PATCH 090/106] Removes further unneccessary debug output --- beacon_node/client/src/notifier.rs | 4 ++-- beacon_node/network/src/service.rs | 2 +- .../src/per_block_processing/validate_attestation.rs | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 91a9f3a26..1a5ecbb53 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -22,13 +22,13 @@ pub fn run(client: &Client, executor: TaskExecutor, exit: Exi // build heartbeat logic here let heartbeat = move |_| { - debug!(log, "Temp heartbeat output"); + //debug!(log, "Temp heartbeat output"); //TODO: Remove this logic. Testing only let mut count = counter.lock().unwrap(); *count += 1; if *count % 5 == 0 { - debug!(log, "Sending Message"); + // debug!(log, "Sending Message"); network.send_message(); } diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index b2d2b5a24..aee7eb466 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -161,7 +161,7 @@ fn network_service( libp2p_service.swarm.send_rpc(peer_id, rpc_event); } OutgoingMessage::NotifierTest => { - debug!(log, "Received message from notifier"); + // debug!(log, "Received message from notifier"); } }; } diff --git a/eth2/state_processing/src/per_block_processing/validate_attestation.rs b/eth2/state_processing/src/per_block_processing/validate_attestation.rs index 76b415796..3b89bec99 100644 --- a/eth2/state_processing/src/per_block_processing/validate_attestation.rs +++ b/eth2/state_processing/src/per_block_processing/validate_attestation.rs @@ -99,9 +99,6 @@ fn validate_attestation_parametric( crosslink_data_root: attestation.data.crosslink_data_root, epoch: attestation.data.slot.epoch(spec.slots_per_epoch), }; - dbg!(attestation.clone()); - dbg!(state.latest_crosslinks[attestation.data.shard as usize].clone()); - dbg!(potential_crosslink.clone()); verify!( (attestation.data.previous_crosslink == state.latest_crosslinks[attestation.data.shard as usize]) From c596e3f7d77fb04b7881b012019f66e5bf55b213 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 17:26:28 +1100 Subject: [PATCH 091/106] Change log levels of gossipsub events --- beacon_node/eth2-libp2p/src/behaviour.rs | 4 ++-- beacon_node/eth2-libp2p/src/service.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/beacon_node/eth2-libp2p/src/behaviour.rs b/beacon_node/eth2-libp2p/src/behaviour.rs index fdf12f0bf..88bfd0042 100644 --- a/beacon_node/eth2-libp2p/src/behaviour.rs +++ b/beacon_node/eth2-libp2p/src/behaviour.rs @@ -12,7 +12,7 @@ use libp2p::{ tokio_io::{AsyncRead, AsyncWrite}, NetworkBehaviour, PeerId, }; -use slog::{debug, o, warn}; +use slog::{debug, o, trace, warn}; use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream}; use types::{Attestation, BeaconBlock}; use types::{Topic, TopicHash}; @@ -47,7 +47,7 @@ impl NetworkBehaviourEventProcess { - debug!(self.log, "Received GossipEvent"; "msg" => format!("{:?}", gs_msg)); + trace!(self.log, "Received GossipEvent"; "msg" => format!("{:?}", gs_msg)); let pubsub_message = match PubsubMessage::ssz_decode(&gs_msg.data, 0) { //TODO: Punish peer on error diff --git a/beacon_node/eth2-libp2p/src/service.rs b/beacon_node/eth2-libp2p/src/service.rs index 0dc30cf42..f52d11ef1 100644 --- a/beacon_node/eth2-libp2p/src/service.rs +++ b/beacon_node/eth2-libp2p/src/service.rs @@ -113,7 +113,7 @@ impl Stream for Service { topics, message, } => { - debug!(self.log, "Pubsub message received: {:?}", message); + trace!(self.log, "Pubsub message received: {:?}", message); return Ok(Async::Ready(Some(Libp2pEvent::PubsubMessage { source, topics, From a93f89894627a0b1276617965940abf91672b2db Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 31 Mar 2019 17:27:04 +1100 Subject: [PATCH 092/106] Improve gossipsub block processing --- beacon_node/network/src/beacon_chain.rs | 2 +- beacon_node/network/src/message_handler.rs | 5 +- beacon_node/network/src/sync/import_queue.rs | 38 ++++- beacon_node/network/src/sync/simple_sync.rs | 158 +++++++++++++----- .../testing_beacon_state_builder.rs | 2 +- 5 files changed, 160 insertions(+), 45 deletions(-) diff --git a/beacon_node/network/src/beacon_chain.rs b/beacon_node/network/src/beacon_chain.rs index 7a8efb254..827adeb3c 100644 --- a/beacon_node/network/src/beacon_chain.rs +++ b/beacon_node/network/src/beacon_chain.rs @@ -10,7 +10,7 @@ use beacon_chain::{ use eth2_libp2p::rpc::HelloMessage; use types::{Attestation, BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Epoch, Hash256, Slot}; -pub use beacon_chain::{BeaconChainError, BlockProcessingOutcome}; +pub use beacon_chain::{BeaconChainError, BlockProcessingOutcome, InvalidBlock}; /// The network's API to the beacon chain. pub trait BeaconChain: Send + Sync { diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 0efa6b96f..098a5b4bf 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -208,8 +208,9 @@ impl MessageHandler { fn handle_gossip(&mut self, peer_id: PeerId, gossip_message: PubsubMessage) { match gossip_message { PubsubMessage::Block(message) => { - self.sync - .on_block_gossip(peer_id, message, &mut self.network_context) + let _should_foward_on = + self.sync + .on_block_gossip(peer_id, message, &mut self.network_context); } PubsubMessage::Attestation(message) => { self.sync diff --git a/beacon_node/network/src/sync/import_queue.rs b/beacon_node/network/src/sync/import_queue.rs index b9280440b..0026347eb 100644 --- a/beacon_node/network/src/sync/import_queue.rs +++ b/beacon_node/network/src/sync/import_queue.rs @@ -104,7 +104,7 @@ impl ImportQueue { } /// Returns `true` if `self.chain` has not yet processed this block. - pub fn is_new_block(&self, block_root: &Hash256) -> bool { + pub fn chain_has_not_seen_block(&self, block_root: &Hash256) -> bool { self.chain .is_new_block_root(&block_root) .unwrap_or_else(|_| { @@ -125,7 +125,7 @@ impl ImportQueue { let new_roots: Vec = block_roots .iter() // Ignore any roots already processed by the chain. - .filter(|brs| self.is_new_block(&brs.block_root)) + .filter(|brs| self.chain_has_not_seen_block(&brs.block_root)) // Ignore any roots already stored in the queue. .filter(|brs| !self.partials.iter().any(|p| p.block_root == brs.block_root)) .cloned() @@ -168,7 +168,7 @@ impl ImportQueue { for header in headers { let block_root = Hash256::from_slice(&header.hash_tree_root()[..]); - if self.is_new_block(&block_root) { + if self.chain_has_not_seen_block(&block_root) { self.insert_header(block_root, header, sender.clone()); required_bodies.push(block_root) } @@ -186,6 +186,12 @@ impl ImportQueue { } } + pub fn enqueue_full_blocks(&mut self, blocks: Vec, sender: PeerId) { + for block in blocks { + self.insert_full_block(block, sender.clone()); + } + } + /// Inserts a header to the queue. /// /// If the header already exists, the `inserted` time is set to `now` and not other @@ -239,6 +245,32 @@ impl ImportQueue { } }); } + + /// Updates an existing `partial` with the completed block, or adds a new (complete) partial. + /// + /// If the partial already existed, the `inserted` time is set to `now`. + fn insert_full_block(&mut self, block: BeaconBlock, sender: PeerId) { + let block_root = Hash256::from_slice(&block.hash_tree_root()[..]); + + let partial = PartialBeaconBlock { + slot: block.slot, + block_root, + header: Some(block.block_header()), + body: Some(block.body), + inserted: Instant::now(), + sender, + }; + + if let Some(i) = self + .partials + .iter() + .position(|p| p.block_root == block_root) + { + self.partials[i] = partial; + } else { + self.partials.push(partial) + } + } } /// Individual components of a `BeaconBlock`, potentially all that are required to form a full diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index e8a3da656..6a78dc57d 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -1,10 +1,11 @@ use super::import_queue::ImportQueue; -use crate::beacon_chain::BeaconChain; +use crate::beacon_chain::{BeaconChain, BlockProcessingOutcome, InvalidBlock}; use crate::message_handler::NetworkContext; use eth2_libp2p::rpc::methods::*; use eth2_libp2p::rpc::{RPCRequest, RPCResponse, RequestId}; use eth2_libp2p::PeerId; use slog::{debug, error, info, o, warn}; +use ssz::TreeHash; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; @@ -16,6 +17,10 @@ const SLOT_IMPORT_TOLERANCE: u64 = 100; /// The amount of seconds a block (or partial block) may exist in the import queue. const QUEUE_STALE_SECS: u64 = 60; +/// If a block is more than `FUTURE_SLOT_TOLERANCE` slots ahead of our slot clock, we drop it. +/// Otherwise we queue it. +const FUTURE_SLOT_TOLERANCE: u64 = 1; + /// Keeps track of syncing information for known connected peers. #[derive(Clone, Copy, Debug)] pub struct PeerSyncInfo { @@ -536,65 +541,130 @@ impl SimpleSync { } /// Process a gossip message declaring a new block. + /// + /// Returns a `bool` which, if `true`, indicates we should forward the block to our peers. pub fn on_block_gossip( &mut self, peer_id: PeerId, block: BeaconBlock, network: &mut NetworkContext, - ) { + ) -> bool { info!( self.log, "NewGossipBlock"; "peer" => format!("{:?}", peer_id), ); - /* // Ignore any block from a finalized slot. - if self.slot_is_finalized(msg.slot) { + if self.slot_is_finalized(block.slot) { warn!( self.log, "NewGossipBlock"; "msg" => "new block slot is finalized.", - "slot" => msg.slot, + "block_slot" => block.slot, ); - return; + return false; } + let block_root = Hash256::from_slice(&block.hash_tree_root()); + // Ignore any block that the chain already knows about. - if self.chain_has_seen_block(&msg.block_root) { - return; + if self.chain_has_seen_block(&block_root) { + println!("this happened"); + // TODO: Age confirm that we shouldn't forward a block if we already know of it. + return false; } - // k - if msg.slot == self.chain.hello_message().best_slot + 1 { - self.request_block_headers( - peer_id, - BeaconBlockHeadersRequest { - start_root: msg.block_root, - start_slot: msg.slot, - max_headers: 1, - skip_slots: 0, - }, - network, - ) + debug!( + self.log, + "NewGossipBlock"; + "peer" => format!("{:?}", peer_id), + "msg" => "processing block", + ); + match self.chain.process_block(block.clone()) { + Ok(BlockProcessingOutcome::InvalidBlock(InvalidBlock::ParentUnknown)) => { + // get the parent. + true + } + Ok(BlockProcessingOutcome::InvalidBlock(InvalidBlock::FutureSlot { + present_slot, + block_slot, + })) => { + if block_slot - present_slot > FUTURE_SLOT_TOLERANCE { + // The block is too far in the future, drop it. + warn!( + self.log, "NewGossipBlock"; + "msg" => "future block rejected", + "present_slot" => present_slot, + "block_slot" => block_slot, + "FUTURE_SLOT_TOLERANCE" => FUTURE_SLOT_TOLERANCE, + "peer" => format!("{:?}", peer_id), + ); + // Do not forward the block around to peers. + false + } else { + // The block is in the future, but not too far. + warn!( + self.log, "NewGossipBlock"; + "msg" => "queuing future block", + "present_slot" => present_slot, + "block_slot" => block_slot, + "FUTURE_SLOT_TOLERANCE" => FUTURE_SLOT_TOLERANCE, + "peer" => format!("{:?}", peer_id), + ); + // Queue the block for later processing. + self.import_queue.enqueue_full_blocks(vec![block], peer_id); + // Forward the block around to peers. + true + } + } + Ok(outcome) => { + if outcome.is_invalid() { + // The peer has sent a block which is fundamentally invalid. + warn!( + self.log, "NewGossipBlock"; + "msg" => "invalid block from peer", + "outcome" => format!("{:?}", outcome), + "peer" => format!("{:?}", peer_id), + ); + // Disconnect the peer + network.disconnect(peer_id, GoodbyeReason::Fault); + // Do not forward the block to peers. + false + } else if outcome.sucessfully_processed() { + // The block was valid and we processed it successfully. + info!( + self.log, "NewGossipBlock"; + "msg" => "block import successful", + "peer" => format!("{:?}", peer_id), + ); + // Forward the block to peers + true + } else { + // The block wasn't necessarily invalid but we didn't process it successfully. + // This condition shouldn't be reached. + error!( + self.log, "NewGossipBlock"; + "msg" => "unexpected condition in processing block.", + "outcome" => format!("{:?}", outcome), + ); + // Do not forward the block on. + false + } + } + Err(e) => { + // We encountered an error whilst processing the block. + // + // Blocks should not be able to trigger errors, instead they should be flagged as + // invalid. + error!( + self.log, "NewGossipBlock"; + "msg" => "internal error in processing block.", + "error" => format!("{:?}", e), + ); + // Do not forward the block to peers. + false + } } - - // TODO: if the block is a few more slots ahead, try to get all block roots from then until - // now. - // - // Note: only requests the new block -- will fail if we don't have its parents. - if !self.chain_has_seen_block(&msg.block_root) { - self.request_block_headers( - peer_id, - BeaconBlockHeadersRequest { - start_root: msg.block_root, - start_slot: msg.slot, - max_headers: 1, - skip_slots: 0, - }, - network, - ) - } - */ } /// Process a gossip message declaring a new attestation. @@ -724,6 +794,18 @@ impl SimpleSync { network.send_rpc_request(peer_id.clone(), RPCRequest::BeaconBlockBodies(req)); } + /// Returns `true` if `self.chain` has not yet processed this block. + pub fn chain_has_seen_block(&self, block_root: &Hash256) -> bool { + !self + .chain + .is_new_block_root(&block_root) + .unwrap_or_else(|_| { + error!(self.log, "Unable to determine if block is new."); + false + }) + } + + /// Returns `true` if the given slot is finalized in our chain. fn slot_is_finalized(&self, slot: Slot) -> bool { slot <= self .chain diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index f437240dc..e25da37e7 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -120,7 +120,7 @@ impl TestingBeaconStateBuilder { }) .collect(); - let genesis_time = 1553977336; // arbitrary + let genesis_time = 1554013000; // arbitrary let mut state = BeaconState::genesis( genesis_time, From 170f993032002f0d50fdb8bed25564fbad678622 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 1 Apr 2019 12:14:23 +1100 Subject: [PATCH 093/106] Clean up warnings --- beacon_node/client/src/lib.rs | 2 -- beacon_node/eth2-libp2p/src/rpc/methods.rs | 2 +- beacon_node/rpc/src/validator.rs | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 807fd9301..6b4277c26 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -15,13 +15,11 @@ use futures::{future::Future, Stream}; use network::Service as NetworkService; use slog::{error, info, o}; use slot_clock::SlotClock; -use ssz::TreeHash; use std::marker::PhantomData; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::runtime::TaskExecutor; use tokio::timer::Interval; -use types::Hash256; /// Main beacon node client service. This provides the connection and initialisation of the clients /// sub-services in multiple threads. diff --git a/beacon_node/eth2-libp2p/src/rpc/methods.rs b/beacon_node/eth2-libp2p/src/rpc/methods.rs index f9adb93c1..dc0be19a9 100644 --- a/beacon_node/eth2-libp2p/src/rpc/methods.rs +++ b/beacon_node/eth2-libp2p/src/rpc/methods.rs @@ -1,7 +1,7 @@ use ssz::{Decodable, DecodeError, Encodable, SszStream}; /// Available RPC methods types and ids. use ssz_derive::{Decode, Encode}; -use types::{Attestation, BeaconBlockBody, BeaconBlockHeader, Epoch, Hash256, Slot}; +use types::{BeaconBlockBody, BeaconBlockHeader, Epoch, Hash256, Slot}; #[derive(Debug)] /// Available Serenity Libp2p RPC methods diff --git a/beacon_node/rpc/src/validator.rs b/beacon_node/rpc/src/validator.rs index 0a9d7015c..4511a8913 100644 --- a/beacon_node/rpc/src/validator.rs +++ b/beacon_node/rpc/src/validator.rs @@ -83,7 +83,7 @@ impl ValidatorService for ValidatorServiceInstance { RpcStatusCode::InvalidArgument, Some("Invalid public_key".to_string()), )) - .map_err(move |e| warn!(log_clone, "failed to reply {:?}", req)); + .map_err(move |_| warn!(log_clone, "failed to reply {:?}", req)); return ctx.spawn(f); } }; From 9f8850d0a18bbdefd9fc5d8eefadb42dc8bbb327 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 1 Apr 2019 12:14:44 +1100 Subject: [PATCH 094/106] Adds bootnode CLI parameter --- beacon_node/client/src/client_config.rs | 12 ++++++++++++ beacon_node/src/main.rs | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index cad287f2c..f7a257a3a 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -10,6 +10,7 @@ use std::path::PathBuf; use types::multiaddr::Protocol; use types::multiaddr::ToMultiaddr; use types::ChainSpec; +use types::Multiaddr; /// Stores the client configuration for this Lighthouse instance. #[derive(Debug, Clone)] @@ -88,6 +89,17 @@ impl ClientConfig { } } + // Custom bootnodes + // TODO: Handle list of addresses + if let Some(boot_addresses_str) = args.value_of("boot_nodes") { + if let Ok(boot_address) = boot_addresses_str.parse::() { + config.net_conf.boot_nodes.append(&mut vec![boot_address]); + } else { + error!(log, "Invalid Bootnode multiaddress"; "Multiaddr" => boot_addresses_str); + return Err("Invalid IP Address"); + } + } + /* Filesystem related arguments */ // Custom datadir diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index ea74c7376..a4e1ee130 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -16,6 +16,7 @@ fn main() { .version(version::version().as_str()) .author("Sigma Prime ") .about("Eth 2.0 Client") + // file system related arguments .arg( Arg::with_name("datadir") .long("datadir") @@ -23,6 +24,7 @@ fn main() { .help("Data directory for keys and databases.") .takes_value(true), ) + // network related arguments .arg( Arg::with_name("listen_address") .long("listen-address") @@ -37,6 +39,14 @@ fn main() { .help("Network listen port for p2p connections.") .takes_value(true), ) + .arg( + Arg::with_name("boot-nodes") + .long("boot-nodes") + .value_name("BOOTNODES") + .help("A list of comma separated multi addresses representing bootnodes to connect to.") + .takes_value(true), + ) + // rpc related arguments .arg( Arg::with_name("rpc") .long("rpc") From ddd9654f7001adb1ac254a9cefa76c297af91a45 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 1 Apr 2019 13:34:43 +1100 Subject: [PATCH 095/106] op-pool: fix bug in attestation_score The attestation scoring function was looking only at the previous epoch, but should really look at whichever epoch is appropriate for a given attestation. We also avoid including attestations that don't pay us any reward, as they simply bloat the chain. --- eth2/operation_pool/src/lib.rs | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index c42527b60..0c5d78fe4 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -74,15 +74,26 @@ impl AttestationId { /// the aggregate attestation introduces, and is proportional to the size of the reward we will /// receive for including it in a block. // TODO: this could be optimised with a map from validator index to whether that validator has -// attested in the *current* epoch. Alternatively, we could cache an index that allows us to -// quickly look up the attestations in the current epoch for a given shard. -fn attestation_score(attestation: &Attestation, state: &BeaconState) -> usize { +// attested in each of the current and previous epochs. Currently quadractic in number of validators. +fn attestation_score(attestation: &Attestation, state: &BeaconState, spec: &ChainSpec) -> usize { // Bitfield of validators whose attestations are new/fresh. let mut new_validators = attestation.aggregation_bitfield.clone(); - state - .current_epoch_attestations + let attestation_epoch = attestation.data.slot.epoch(spec.slots_per_epoch); + + let state_attestations = if attestation_epoch == state.current_epoch(spec) { + &state.current_epoch_attestations + } else if attestation_epoch == state.previous_epoch(spec) { + &state.previous_epoch_attestations + } else { + return 0; + }; + + state_attestations .iter() + // In a single epoch, an attester should only be attesting for one shard. + // TODO: we avoid including slashable attestations in the state here, + // but maybe we should do something else with them (like construct slashings). .filter(|current_attestation| current_attestation.data.shard == attestation.data.shard) .for_each(|current_attestation| { // Remove the validators who have signed the existing attestation (they are not new) @@ -176,7 +187,9 @@ impl OperationPool { .filter(|attestation| validate_attestation(state, attestation, spec).is_ok()) // Scored by the number of new attestations they introduce (descending) // TODO: need to consider attestations introduced in THIS block - .map(|att| (att, attestation_score(att, state))) + .map(|att| (att, attestation_score(att, state, spec))) + // Don't include any useless attestations (score 0) + .filter(|&(_, score)| score != 0) .sorted_by_key(|&(_, score)| std::cmp::Reverse(score)) // Limited to the maximum number of attestations per block .take(spec.max_attestations as usize) @@ -695,7 +708,7 @@ mod tests { num_committees * (spec.slots_per_epoch * spec.target_committee_size) as usize; let mut state_builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(num_validators, spec); - let slot_offset = 100000; + let slot_offset = 1000 * spec.slots_per_epoch + spec.slots_per_epoch / 2; let slot = spec.genesis_slot + slot_offset; state_builder.teleport_to_slot(slot, spec); state_builder.build_caches(spec).unwrap(); @@ -726,7 +739,7 @@ mod tests { assert_eq!( att1.aggregation_bitfield.num_set_bits(), - attestation_score(&att1, state) + attestation_score(&att1, state, spec) ); state @@ -735,7 +748,7 @@ mod tests { assert_eq!( committee.committee.len() - 2, - attestation_score(&att2, &state) + attestation_score(&att2, state, spec) ); } } From 111c81f42836f215a4e6190cd95f139c83328b8c Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 1 Apr 2019 15:23:38 +1100 Subject: [PATCH 096/106] Add ParentUnknown block processing to `SimpleSync` --- beacon_node/network/src/sync/simple_sync.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 6a78dc57d..e7ef301bb 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -582,7 +582,23 @@ impl SimpleSync { ); match self.chain.process_block(block.clone()) { Ok(BlockProcessingOutcome::InvalidBlock(InvalidBlock::ParentUnknown)) => { - // get the parent. + // The block was valid and we processed it successfully. + debug!( + self.log, "NewGossipBlock"; + "msg" => "parent block unknown", + "parent_root" => format!("{}", block.previous_block_root), + "peer" => format!("{:?}", peer_id), + ); + // Send a hello to learn of the clients best slot so we can then sync the require + // parent(s). + network.send_rpc_request( + peer_id.clone(), + RPCRequest::Hello(self.chain.hello_message()), + ); + // Forward the block onto our peers. + // + // Note: this may need to be changed if we decide to only forward blocks if we have + // all required info. true } Ok(BlockProcessingOutcome::InvalidBlock(InvalidBlock::FutureSlot { From a3ca3ec50d1058a45368918fe8313cabadf3bb72 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 1 Apr 2019 15:32:04 +1100 Subject: [PATCH 097/106] Break block proc. loop if we get a bad block --- beacon_node/network/src/sync/simple_sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index e7ef301bb..841ae37ac 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -726,6 +726,7 @@ impl SimpleSync { "reason" => format!("{:?}", outcome), ); network.disconnect(sender, GoodbyeReason::Fault); + break; } // If this results to true, the item will be removed from the queue. From a7df4f180081aa26a58bc3c4098f5365bce9f26c Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 1 Apr 2019 15:38:22 +1100 Subject: [PATCH 098/106] Add log when block not processed in queue --- beacon_node/network/src/sync/simple_sync.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 841ae37ac..038975f05 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -733,6 +733,14 @@ impl SimpleSync { if outcome.sucessfully_processed() { successful += 1; self.import_queue.remove(block_root); + } else { + debug!( + self.log, + "ProcessImportQueue"; + "msg" => "Block not imported", + "outcome" => format!("{:?}", outcome), + "peer" => format!("{:?}", sender), + ); } } Err(e) => { From 5e80b90301d1abab663180d7d13278987b6597e1 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 1 Apr 2019 15:51:48 +1100 Subject: [PATCH 099/106] Extend queue stale time, queue more blocks --- beacon_node/network/src/sync/simple_sync.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 038975f05..9a1e51bdd 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -15,7 +15,7 @@ use types::{Attestation, BeaconBlock, Epoch, Hash256, Slot}; const SLOT_IMPORT_TOLERANCE: u64 = 100; /// The amount of seconds a block (or partial block) may exist in the import queue. -const QUEUE_STALE_SECS: u64 = 60; +const QUEUE_STALE_SECS: u64 = 600; /// If a block is more than `FUTURE_SLOT_TOLERANCE` slots ahead of our slot clock, we drop it. /// Otherwise we queue it. @@ -589,6 +589,9 @@ impl SimpleSync { "parent_root" => format!("{}", block.previous_block_root), "peer" => format!("{:?}", peer_id), ); + // Queue the block for later processing. + self.import_queue + .enqueue_full_blocks(vec![block], peer_id.clone()); // Send a hello to learn of the clients best slot so we can then sync the require // parent(s). network.send_rpc_request( From 3f160d3b995f848c035f1ab7c5d46da3dcc208c2 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 1 Apr 2019 16:29:11 +1100 Subject: [PATCH 100/106] Correct bootnodes cli parameter --- beacon_node/client/src/client_config.rs | 4 ++-- beacon_node/src/main.rs | 2 +- .../src/test_utils/testing_beacon_state_builder.rs | 11 ++++++++--- validator_client/src/service.rs | 12 +++++++----- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index f7a257a3a..407171ff5 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -77,7 +77,7 @@ impl ClientConfig { } // Custom listening address ipv4/ipv6 // TODO: Handle list of addresses - if let Some(listen_address_str) = args.value_of("listen_address") { + if let Some(listen_address_str) = args.value_of("listen-address") { if let Ok(listen_address) = listen_address_str.parse::() { let multiaddr = SocketAddr::new(listen_address, config.net_conf.listen_port) .to_multiaddr() @@ -91,7 +91,7 @@ impl ClientConfig { // Custom bootnodes // TODO: Handle list of addresses - if let Some(boot_addresses_str) = args.value_of("boot_nodes") { + if let Some(boot_addresses_str) = args.value_of("boot-nodes") { if let Ok(boot_address) = boot_addresses_str.parse::() { config.net_conf.boot_nodes.append(&mut vec![boot_address]); } else { diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index a4e1ee130..45aafb3ce 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -26,7 +26,7 @@ fn main() { ) // network related arguments .arg( - Arg::with_name("listen_address") + Arg::with_name("listen-address") .long("listen-address") .value_name("Listen Address") .help("The Network address to listen for p2p connections.") diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index def58b0d7..445debae7 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -122,12 +122,17 @@ impl TestingBeaconStateBuilder { }) .collect(); + // TODO: Testing only. Burn with fire later. + // set genesis to the last 30 minute block. + // this is used for testing only. Allows multiple nodes to connect within a 30min window + // and agree on a genesis let now = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap() - .as_secs() - - 30; - let genesis_time = now; // arbitrary + .as_secs(); + let secs_after_last_period = now.checked_rem(30 * 60).unwrap_or(0); + // genesis is now the last 30 minute block. + let genesis_time = now - secs_after_last_period; let mut state = BeaconState::genesis( genesis_time, diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index 38883e68f..ce19c23e9 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -292,11 +292,13 @@ impl Service { let current_epoch = self.current_slot.epoch(self.spec.slots_per_epoch); // spawn a new thread separate to the runtime // TODO: Handle thread termination/timeout - std::thread::spawn(move || { - // the return value is a future which returns ready. - // built to be compatible with the tokio runtime. - let _empty = cloned_manager.run_update(current_epoch, cloned_log.clone()); - }); + // TODO: Add duties thread back in, with channel to process duties in duty change. + // leave sequential for now. + //std::thread::spawn(move || { + // the return value is a future which returns ready. + // built to be compatible with the tokio runtime. + let _empty = cloned_manager.run_update(current_epoch, cloned_log.clone()); + //}); } /// If there are any duties to process, spawn a separate thread and perform required actions. From 38f2cb955580d6ebee405e9086d2181d9058a9a1 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 2 Apr 2019 14:30:32 +1100 Subject: [PATCH 101/106] Run rustfmt --- eth2/state_processing/tests/tests.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/eth2/state_processing/tests/tests.rs b/eth2/state_processing/tests/tests.rs index 0363da810..12b78c08f 100644 --- a/eth2/state_processing/tests/tests.rs +++ b/eth2/state_processing/tests/tests.rs @@ -1,6 +1,9 @@ -use state_processing::{per_block_processing, per_block_processing_without_verifying_block_signature, per_slot_processing}; use serde_derive::Deserialize; use serde_yaml; +use state_processing::{ + per_block_processing, per_block_processing_without_verifying_block_signature, + per_slot_processing, +}; use std::{fs::File, io::prelude::*, path::PathBuf}; use types::*; #[allow(unused_imports)] @@ -79,17 +82,22 @@ fn run_state_transition_tests_small() { for block in test_case.blocks.iter() { while block.slot > state.slot { let latest_block_header = state.latest_block_header.clone(); - let res = per_slot_processing(&mut state, &latest_block_header, &test_case.config).unwrap(); + let res = per_slot_processing(&mut state, &latest_block_header, &test_case.config) + .unwrap(); } if test_case.verify_signatures { let res = per_block_processing(&mut state, &block, &test_case.config); - if res.is_err() { + if res.is_err() { println!("{:?}", i); println!("{:?}", res); }; } else { - let res = per_block_processing_without_verifying_block_signature(&mut state, &block, &test_case.config); - if res.is_err() { + let res = per_block_processing_without_verifying_block_signature( + &mut state, + &block, + &test_case.config, + ); + if res.is_err() { println!("{:?}", i); println!("{:?}", res); } From 3a42d7fa6ebbd5679c675b8edfdb663eccd18e6b Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 2 Apr 2019 15:33:18 +1100 Subject: [PATCH 102/106] Disable some blop pool tests during debug --- eth2/operation_pool/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 41c41c3ff..69a1ccc0b 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -695,6 +695,7 @@ mod tests { /// Create a signed attestation for use in tests. /// Signed by all validators in `committee[signing_range]` and `committee[extra_signer]`. + #[cfg(not(debug_assertions))] fn signed_attestation>( committee: &CrosslinkCommittee, keypairs: &[Keypair], @@ -727,6 +728,7 @@ mod tests { } /// Test state for attestation-related tests. + #[cfg(not(debug_assertions))] fn attestation_test_state( spec: &ChainSpec, num_committees: usize, @@ -743,6 +745,7 @@ mod tests { } /// Set the latest crosslink in the state to match the attestation. + #[cfg(not(debug_assertions))] fn fake_latest_crosslink(att: &Attestation, state: &mut BeaconState, spec: &ChainSpec) { state.latest_crosslinks[att.data.shard as usize] = Crosslink { crosslink_data_root: att.data.crosslink_data_root, @@ -751,6 +754,7 @@ mod tests { } #[test] + #[cfg(not(debug_assertions))] fn test_attestation_score() { let spec = &ChainSpec::foundation(); let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); @@ -782,6 +786,7 @@ mod tests { /// End-to-end test of basic attestation handling. #[test] + #[cfg(not(debug_assertions))] fn attestation_aggregation_insert_get_prune() { let spec = &ChainSpec::foundation(); let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); @@ -847,6 +852,7 @@ mod tests { /// Adding an attestation already in the pool should not increase the size of the pool. #[test] + #[cfg(not(debug_assertions))] fn attestation_duplicate() { let spec = &ChainSpec::foundation(); let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); @@ -873,6 +879,7 @@ mod tests { /// Adding lots of attestations that only intersect pairwise should lead to two aggregate /// attestations. #[test] + #[cfg(not(debug_assertions))] fn attestation_pairwise_overlapping() { let spec = &ChainSpec::foundation(); let (ref mut state, ref keypairs) = attestation_test_state(spec, 1); @@ -915,6 +922,7 @@ mod tests { /// high-quality attestations. To ensure that no aggregation occurs, ALL attestations /// are also signed by the 0th member of the committee. #[test] + #[cfg(not(debug_assertions))] fn attestation_get_max() { let spec = &ChainSpec::foundation(); let small_step_size = 2; From f61db9cac880194b55021c851808e4a8bf868463 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 2 Apr 2019 15:33:38 +1100 Subject: [PATCH 103/106] Fix merge conflict in `bls` Issue came about from Michael and Kirk doing simultaneous work. --- eth2/utils/bls/src/aggregate_signature.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth2/utils/bls/src/aggregate_signature.rs b/eth2/utils/bls/src/aggregate_signature.rs index f446ce71e..8c7ae5222 100644 --- a/eth2/utils/bls/src/aggregate_signature.rs +++ b/eth2/utils/bls/src/aggregate_signature.rs @@ -38,7 +38,8 @@ impl AggregateSignature { /// Add (aggregate) another `AggregateSignature`. pub fn add_aggregate(&mut self, agg_signature: &AggregateSignature) { - self.0.add_aggregate(&agg_signature.0) + self.aggregate_signature + .add_aggregate(&agg_signature.aggregate_signature) } /// Verify the `AggregateSignature` against an `AggregatePublicKey`. From 1d34e2b2a5bd245a7c4e96fc40b261deee91814f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 2 Apr 2019 15:34:18 +1100 Subject: [PATCH 104/106] Fix bug in bitfield. --- eth2/utils/boolean-bitfield/src/lib.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/eth2/utils/boolean-bitfield/src/lib.rs b/eth2/utils/boolean-bitfield/src/lib.rs index 0634490a5..d04516dba 100644 --- a/eth2/utils/boolean-bitfield/src/lib.rs +++ b/eth2/utils/boolean-bitfield/src/lib.rs @@ -33,12 +33,21 @@ impl BooleanBitfield { } /// Create a new bitfield with the given length `initial_len` and all values set to `bit`. + /// + /// Note: if `initial_len` is not a multiple of 8, the remaining bits will be set to `false` + /// regardless of `bit`. pub fn from_elem(initial_len: usize, bit: bool) -> Self { // BitVec can panic if we don't set the len to be a multiple of 8. - let len = ((initial_len + 7) / 8) * 8; - Self { - 0: BitVec::from_elem(len, bit), + let full_len = ((initial_len + 7) / 8) * 8; + let mut bitfield = BitVec::from_elem(full_len, false); + + if bit { + for i in 0..initial_len { + bitfield.set(i, true); + } } + + Self { 0: bitfield } } /// Create a new bitfield using the supplied `bytes` as input From 1913be0c6fc923378a14f41ad968a0433f5e2635 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 3 Apr 2019 16:23:09 +1100 Subject: [PATCH 105/106] Fix clippy lints --- beacon_node/beacon_chain/src/beacon_chain.rs | 12 +++------ .../test_harness/src/beacon_chain_harness.rs | 5 ++-- .../test_harness/src/test_case/state_check.rs | 1 + .../validator_harness/direct_beacon_node.rs | 8 ------ .../test_harness/src/validator_harness/mod.rs | 26 ++----------------- beacon_node/client/src/lib.rs | 19 +++++++------- beacon_node/client/src/notifier.rs | 2 +- beacon_node/eth2-libp2p/src/behaviour.rs | 19 +++++--------- beacon_node/eth2-libp2p/src/rpc/mod.rs | 6 ++--- beacon_node/eth2-libp2p/src/rpc/protocol.rs | 16 +++++++----- beacon_node/eth2-libp2p/src/service.rs | 13 ++++++---- beacon_node/network/src/message_handler.rs | 4 +-- beacon_node/network/src/service.rs | 12 ++++----- beacon_node/network/src/sync/simple_sync.rs | 2 +- beacon_node/rpc/src/attestation.rs | 10 +++---- beacon_node/rpc/src/beacon_block.rs | 4 +-- beacon_node/rpc/src/beacon_node.rs | 4 +-- eth2/state_processing/tests/tests.rs | 3 +-- .../testing_beacon_state_builder.rs | 3 +-- eth2/utils/bls/src/keypair.rs | 8 +++++- validator_client/src/config.rs | 2 ++ validator_client/src/service.rs | 2 +- 22 files changed, 76 insertions(+), 105 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 600c453fd..a22f4179e 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -497,21 +497,17 @@ where } else { // If the current head block is not from this slot, use the slot from the previous // epoch. - let root = *self.state.read().get_block_root( + *self.state.read().get_block_root( current_epoch_start_slot - self.spec.slots_per_epoch, &self.spec, - )?; - - root + )? } } else { // If we're not on the first slot of the epoch. - let root = *self + *self .state .read() - .get_block_root(current_epoch_start_slot, &self.spec)?; - - root + .get_block_root(current_epoch_start_slot, &self.spec)? }; Ok(AttestationData { diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index 33c12d7c7..aeb734a4e 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -211,9 +211,8 @@ impl BeaconChainHarness { // Ensure the validators slot clock is accurate. self.validators[proposer].set_slot(present_slot); - let block = self.validators[proposer].produce_block().unwrap(); - block + self.validators[proposer].produce_block().unwrap() } /// Advances the chain with a BeaconBlock and attestations from all validators. @@ -245,7 +244,7 @@ impl BeaconChainHarness { .for_each(|(i, attestation)| { self.beacon_chain .process_attestation(attestation.clone()) - .expect(&format!("Attestation {} invalid: {:?}", i, attestation)); + .unwrap_or_else(|_| panic!("Attestation {} invalid: {:?}", i, attestation)); }); debug!("Attestations processed."); diff --git a/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs b/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs index 7ac33c86c..c6bdf8978 100644 --- a/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs +++ b/beacon_node/beacon_chain/test_harness/src/test_case/state_check.rs @@ -52,6 +52,7 @@ impl StateCheck { /// # Panics /// /// Panics with an error message if any test fails. + #[allow(clippy::cyclomatic_complexity)] pub fn assert_valid(&self, state: &BeaconState, spec: &ChainSpec) { let state_epoch = state.slot.epoch(spec.slots_per_epoch); diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs index 2d2b9e84d..d47fd44b9 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator_harness/direct_beacon_node.rs @@ -14,9 +14,6 @@ use slot_clock::SlotClock; use std::sync::Arc; use types::{AttestationData, BeaconBlock, FreeAttestation, Signature, Slot}; -// mod attester; -// mod producer; - /// Connect directly to a borrowed `BeaconChain` instance so an attester/producer can request/submit /// blocks/attestations. /// @@ -42,11 +39,6 @@ impl DirectBeaconNode { pub fn last_published_block(&self) -> Option { Some(self.published_blocks.read().last()?.clone()) } - - /// Get the last published attestation (if any). - pub fn last_published_free_attestation(&self) -> Option { - Some(self.published_attestations.read().last()?.clone()) - } } impl AttesterBeaconNode for DirectBeaconNode { diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs index 91a679463..815d4b23b 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs @@ -2,8 +2,7 @@ mod direct_beacon_node; mod direct_duties; mod local_signer; -use attester::PollOutcome as AttestationPollOutcome; -use attester::{Attester, Error as AttestationPollError}; +use attester::Attester; use beacon_chain::BeaconChain; use block_proposer::PollOutcome as BlockPollOutcome; use block_proposer::{BlockProducer, Error as BlockPollError}; @@ -14,7 +13,7 @@ use fork_choice::BitwiseLMDGhost; use local_signer::LocalSigner; use slot_clock::TestingSlotClock; use std::sync::Arc; -use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair, Slot}; +use types::{BeaconBlock, ChainSpec, Keypair, Slot}; #[derive(Debug, PartialEq)] pub enum BlockProduceError { @@ -22,12 +21,6 @@ pub enum BlockProduceError { PollError(BlockPollError), } -#[derive(Debug, PartialEq)] -pub enum AttestationProduceError { - DidNotProduce(AttestationPollOutcome), - PollError(AttestationPollError), -} - type TestingBlockProducer = BlockProducer< TestingSlotClock, DirectBeaconNode>, @@ -117,21 +110,6 @@ impl ValidatorHarness { .expect("Unable to obtain produced block.")) } - /// Run the `poll` function on the `Attester` and produce a `FreeAttestation`. - /// - /// An error is returned if the attester refuses to attest. - pub fn produce_free_attestation(&mut self) -> Result { - match self.attester.poll() { - Ok(AttestationPollOutcome::AttestationProduced(_)) => {} - Ok(outcome) => return Err(AttestationProduceError::DidNotProduce(outcome)), - Err(error) => return Err(AttestationProduceError::PollError(error)), - }; - Ok(self - .beacon_node - .last_published_free_attestation() - .expect("Unable to obtain produced attestation.")) - } - /// Set the validators slot clock to the specified slot. /// /// The validators slot clock will always read this value until it is set to something else. diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 6b4277c26..6a21493b1 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -25,9 +25,9 @@ use tokio::timer::Interval; /// sub-services in multiple threads. pub struct Client { /// Configuration for the lighthouse client. - config: ClientConfig, + _config: ClientConfig, /// The beacon chain for the running client. - beacon_chain: Arc>, + _beacon_chain: Arc>, /// Reference to the network service. pub network: Arc, /// Signal to terminate the RPC server. @@ -90,17 +90,18 @@ impl Client { network_logger, )?; - let mut rpc_exit_signal = None; // spawn the RPC server - if config.rpc_conf.enabled { - rpc_exit_signal = Some(rpc::start_server( + let rpc_exit_signal = if config.rpc_conf.enabled { + Some(rpc::start_server( &config.rpc_conf, executor, network_send, beacon_chain.clone(), &log, - )); - } + )) + } else { + None + }; let (slot_timer_exit_signal, exit) = exit_future::signal(); if let Ok(Some(duration_to_next_slot)) = beacon_chain.slot_clock.duration_to_next_slot() { @@ -129,8 +130,8 @@ impl Client { } Ok(Client { - config, - beacon_chain, + _config: config, + _beacon_chain: beacon_chain, rpc_exit_signal, slot_timer_exit_signal: Some(slot_timer_exit_signal), log, diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 1a5ecbb53..aa1e43c3c 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -14,7 +14,7 @@ pub fn run(client: &Client, executor: TaskExecutor, exit: Exi // notification heartbeat let interval = Interval::new(Instant::now(), Duration::from_secs(5)); - let log = client.log.new(o!("Service" => "Notifier")); + let _log = client.log.new(o!("Service" => "Notifier")); // TODO: Debugging only let counter = Arc::new(Mutex::new(0)); diff --git a/beacon_node/eth2-libp2p/src/behaviour.rs b/beacon_node/eth2-libp2p/src/behaviour.rs index 88bfd0042..e1112e6ff 100644 --- a/beacon_node/eth2-libp2p/src/behaviour.rs +++ b/beacon_node/eth2-libp2p/src/behaviour.rs @@ -65,17 +65,11 @@ impl NetworkBehaviourEventProcess {} + GossipsubEvent::Subscribed { .. } => {} + GossipsubEvent::Unsubscribed { .. } => {} } } } @@ -110,7 +104,8 @@ impl NetworkBehaviourEventProcess {} IdentifyEvent::SendBack { .. } => {} @@ -183,12 +178,12 @@ impl Behaviour { pub enum BehaviourEvent { RPC(PeerId, RPCEvent), PeerDialed(PeerId), - Identified(PeerId, IdentifyInfo), + Identified(PeerId, Box), // TODO: This is a stub at the moment GossipMessage { source: PeerId, topics: Vec, - message: PubsubMessage, + message: Box, }, } diff --git a/beacon_node/eth2-libp2p/src/rpc/mod.rs b/beacon_node/eth2-libp2p/src/rpc/mod.rs index 08573aa52..57d7dadbe 100644 --- a/beacon_node/eth2-libp2p/src/rpc/mod.rs +++ b/beacon_node/eth2-libp2p/src/rpc/mod.rs @@ -26,7 +26,7 @@ pub struct Rpc { /// Pins the generic substream. marker: PhantomData, /// Slog logger for RPC behaviour. - log: slog::Logger, + _log: slog::Logger, } impl Rpc { @@ -35,7 +35,7 @@ impl Rpc { Rpc { events: Vec::new(), marker: PhantomData, - log, + _log: log, } } @@ -65,7 +65,7 @@ where fn inject_connected(&mut self, peer_id: PeerId, connected_point: ConnectedPoint) { // if initialised the connection, report this upwards to send the HELLO request - if let ConnectedPoint::Dialer { address: _ } = connected_point { + if let ConnectedPoint::Dialer { .. } = connected_point { self.events.push(NetworkBehaviourAction::GenerateEvent( RPCMessage::PeerDialed(peer_id), )); diff --git a/beacon_node/eth2-libp2p/src/rpc/protocol.rs b/beacon_node/eth2-libp2p/src/rpc/protocol.rs index 314be1037..5c1c47fbf 100644 --- a/beacon_node/eth2-libp2p/src/rpc/protocol.rs +++ b/beacon_node/eth2-libp2p/src/rpc/protocol.rs @@ -31,7 +31,7 @@ impl Default for RPCProtocol { } /// A monotonic counter for ordering `RPCRequest`s. -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, Default)] pub struct RequestId(u64); impl RequestId { @@ -48,6 +48,12 @@ impl RequestId { impl Eq for RequestId {} +impl PartialEq for RequestId { + fn eq(&self, other: &RequestId) -> bool { + self.0 == other.0 + } +} + impl Hash for RequestId { fn hash(&self, state: &mut H) { self.0.hash(state); @@ -104,17 +110,15 @@ impl UpgradeInfo for RPCEvent { } } +type FnDecodeRPCEvent = fn(Vec, ()) -> Result; + impl InboundUpgrade for RPCProtocol where TSocket: AsyncRead + AsyncWrite, { type Output = RPCEvent; type Error = DecodeError; - type Future = upgrade::ReadOneThen< - upgrade::Negotiated, - (), - fn(Vec, ()) -> Result, - >; + type Future = upgrade::ReadOneThen, (), FnDecodeRPCEvent>; fn upgrade_inbound(self, socket: upgrade::Negotiated, _: Self::Info) -> Self::Future { upgrade::read_one_then(socket, MAX_READ_SIZE, (), |packet, ()| Ok(decode(packet)?)) diff --git a/beacon_node/eth2-libp2p/src/service.rs b/beacon_node/eth2-libp2p/src/service.rs index f52d11ef1..07a36e408 100644 --- a/beacon_node/eth2-libp2p/src/service.rs +++ b/beacon_node/eth2-libp2p/src/service.rs @@ -19,13 +19,16 @@ use std::io::{Error, ErrorKind}; use std::time::Duration; use types::{TopicBuilder, TopicHash}; +type Libp2pStream = Boxed<(PeerId, StreamMuxerBox), Error>; +type Libp2pBehaviour = Behaviour>; + /// The configuration and state of the libp2p components for the beacon node. pub struct Service { /// The libp2p Swarm handler. //TODO: Make this private - pub swarm: Swarm, Behaviour>>, + pub swarm: Swarm, /// This node's PeerId. - local_peer_id: PeerId, + _local_peer_id: PeerId, /// The libp2p logger handle. pub log: slog::Logger, } @@ -89,7 +92,7 @@ impl Service { info!(log, "Subscribed to topics: {:?}", subscribed_topics); Ok(Service { - local_peer_id, + _local_peer_id: local_peer_id, swarm, log, }) @@ -179,11 +182,11 @@ pub enum Libp2pEvent { /// Initiated the connection to a new peer. PeerDialed(PeerId), /// Received information about a peer on the network. - Identified(PeerId, IdentifyInfo), + Identified(PeerId, Box), /// Received pubsub message. PubsubMessage { source: PeerId, topics: Vec, - message: PubsubMessage, + message: Box, }, } diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs index 098a5b4bf..c5ba25f82 100644 --- a/beacon_node/network/src/message_handler.rs +++ b/beacon_node/network/src/message_handler.rs @@ -41,7 +41,7 @@ pub enum HandlerMessage { /// An RPC response/request has been received. RPC(PeerId, RPCEvent), /// A gossip message has been received. - PubsubMessage(PeerId, PubsubMessage), + PubsubMessage(PeerId, Box), } impl MessageHandler { @@ -93,7 +93,7 @@ impl MessageHandler { } // we have received an RPC message request/response HandlerMessage::PubsubMessage(peer_id, gossip) => { - self.handle_gossip(peer_id, gossip); + self.handle_gossip(peer_id, *gossip); } //TODO: Handle all messages _ => {} diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index aee7eb466..06e3f7af9 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -17,7 +17,7 @@ use types::Topic; /// Service that handles communication between internal services and the eth2_libp2p network service. pub struct Service { //libp2p_service: Arc>, - libp2p_exit: oneshot::Sender<()>, + _libp2p_exit: oneshot::Sender<()>, network_send: crossbeam_channel::Sender, //message_handler: MessageHandler, //message_handler_send: Sender, @@ -54,7 +54,7 @@ impl Service { log, )?; let network_service = Service { - libp2p_exit, + _libp2p_exit: libp2p_exit, network_send: network_send.clone(), }; @@ -131,9 +131,7 @@ fn network_service( ); } Libp2pEvent::PubsubMessage { - source, - topics: _, - message, + source, message, .. } => { //TODO: Decide if we need to propagate the topic upwards. (Potentially for //attestations) @@ -167,7 +165,7 @@ fn network_service( } Ok(NetworkMessage::Publish { topics, message }) => { debug!(log, "Sending pubsub message on topics {:?}", topics); - libp2p_service.swarm.publish(topics, message); + libp2p_service.swarm.publish(topics, *message); } Err(TryRecvError::Empty) => break, Err(TryRecvError::Disconnected) => { @@ -190,7 +188,7 @@ pub enum NetworkMessage { /// Publish a message to pubsub mechanism. Publish { topics: Vec, - message: PubsubMessage, + message: Box, }, } diff --git a/beacon_node/network/src/sync/simple_sync.rs b/beacon_node/network/src/sync/simple_sync.rs index 9a1e51bdd..824458b89 100644 --- a/beacon_node/network/src/sync/simple_sync.rs +++ b/beacon_node/network/src/sync/simple_sync.rs @@ -65,7 +65,7 @@ pub enum PeerStatus { } impl PeerStatus { - pub fn should_handshake(&self) -> bool { + pub fn should_handshake(self) -> bool { match self { PeerStatus::DifferentNetworkId => false, PeerStatus::FinalizedEpochNotInChain => false, diff --git a/beacon_node/rpc/src/attestation.rs b/beacon_node/rpc/src/attestation.rs index abef49df1..3abfdac59 100644 --- a/beacon_node/rpc/src/attestation.rs +++ b/beacon_node/rpc/src/attestation.rs @@ -43,9 +43,9 @@ impl AttestationService for AttestationServiceInstance { let f = sink .fail(RpcStatus::new( RpcStatusCode::OutOfRange, - Some(format!( - "AttestationData request for a slot that is in the future." - )), + Some( + "AttestationData request for a slot that is in the future.".to_string(), + ), )) .map_err(move |e| { error!(log_clone, "Failed to reply with failure {:?}: {:?}", req, e) @@ -58,9 +58,7 @@ impl AttestationService for AttestationServiceInstance { let f = sink .fail(RpcStatus::new( RpcStatusCode::InvalidArgument, - Some(format!( - "AttestationData request for a slot that is in the past." - )), + Some("AttestationData request for a slot that is in the past.".to_string()), )) .map_err(move |e| { error!(log_clone, "Failed to reply with failure {:?}: {:?}", req, e) diff --git a/beacon_node/rpc/src/beacon_block.rs b/beacon_node/rpc/src/beacon_block.rs index 0b90f774a..450bcbca1 100644 --- a/beacon_node/rpc/src/beacon_block.rs +++ b/beacon_node/rpc/src/beacon_block.rs @@ -43,7 +43,7 @@ impl BeaconBlockService for BeaconBlockServiceInstance { let f = sink .fail(RpcStatus::new( RpcStatusCode::InvalidArgument, - Some(format!("Invalid randao reveal signature")), + Some("Invalid randao reveal signature".to_string()), )) .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); return ctx.spawn(f); @@ -114,7 +114,7 @@ impl BeaconBlockService for BeaconBlockServiceInstance { self.network_chan .send(NetworkMessage::Publish { topics: vec![topic], - message, + message: Box::new(message), }) .unwrap_or_else(|e| { error!( diff --git a/beacon_node/rpc/src/beacon_node.rs b/beacon_node/rpc/src/beacon_node.rs index c92ab6616..a9b8df343 100644 --- a/beacon_node/rpc/src/beacon_node.rs +++ b/beacon_node/rpc/src/beacon_node.rs @@ -24,7 +24,7 @@ impl BeaconNodeService for BeaconNodeServiceInstance { // get the chain state let state = self.chain.get_state(); let state_fork = state.fork.clone(); - let genesis_time = state.genesis_time.clone(); + let genesis_time = state.genesis_time; // build the rpc fork struct let mut fork = Fork::new(); @@ -35,7 +35,7 @@ impl BeaconNodeService for BeaconNodeServiceInstance { node_info.set_fork(fork); node_info.set_genesis_time(genesis_time); node_info.set_genesis_slot(self.chain.get_spec().genesis_slot.as_u64()); - node_info.set_chain_id(self.chain.get_spec().chain_id as u32); + node_info.set_chain_id(u32::from(self.chain.get_spec().chain_id)); // send the node_info the requester let error_log = self.log.clone(); diff --git a/eth2/state_processing/tests/tests.rs b/eth2/state_processing/tests/tests.rs index 12b78c08f..1394eeba0 100644 --- a/eth2/state_processing/tests/tests.rs +++ b/eth2/state_processing/tests/tests.rs @@ -82,8 +82,7 @@ fn run_state_transition_tests_small() { for block in test_case.blocks.iter() { while block.slot > state.slot { let latest_block_header = state.latest_block_header.clone(); - let res = per_slot_processing(&mut state, &latest_block_header, &test_case.config) - .unwrap(); + per_slot_processing(&mut state, &latest_block_header, &test_case.config).unwrap(); } if test_case.verify_signatures { let res = per_block_processing(&mut state, &block, &test_case.config); diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index 445debae7..9bdd9e149 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -6,8 +6,7 @@ use dirs; use log::debug; use rayon::prelude::*; use std::path::{Path, PathBuf}; -//TODO: testing only -use std::time::{Duration, SystemTime}; +use std::time::SystemTime; pub const KEYPAIRS_FILE: &str = "keypairs.raw_keypairs"; diff --git a/eth2/utils/bls/src/keypair.rs b/eth2/utils/bls/src/keypair.rs index 2f0e794a6..75960a47d 100644 --- a/eth2/utils/bls/src/keypair.rs +++ b/eth2/utils/bls/src/keypair.rs @@ -3,7 +3,7 @@ use serde_derive::{Deserialize, Serialize}; use std::fmt; use std::hash::{Hash, Hasher}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, Serialize, Deserialize)] pub struct Keypair { pub sk: SecretKey, pub pk: PublicKey, @@ -22,6 +22,12 @@ impl Keypair { } } +impl PartialEq for Keypair { + fn eq(&self, other: &Keypair) -> bool { + self == other + } +} + impl Hash for Keypair { /// Note: this is distinct from consensus serialization, it will produce a different hash. /// diff --git a/validator_client/src/config.rs b/validator_client/src/config.rs index 3d426e8c7..903da047e 100644 --- a/validator_client/src/config.rs +++ b/validator_client/src/config.rs @@ -81,6 +81,7 @@ impl Config { } /// Try to load keys from validator_dir, returning None if none are found or an error. + #[allow(dead_code)] pub fn fetch_keys(&self, log: &slog::Logger) -> Option> { let key_pairs: Vec = fs::read_dir(&self.data_dir) .unwrap() @@ -144,6 +145,7 @@ impl Config { } /// Saves a keypair to a file inside the appropriate validator directory. Returns the saved path filename. + #[allow(dead_code)] pub fn save_key(&self, key: &Keypair) -> Result { let validator_config_path = self.data_dir.join(key.identifier()); let key_path = validator_config_path.join(DEFAULT_PRIVATE_KEY_FILENAME); diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs index ce19c23e9..a8a8325dd 100644 --- a/validator_client/src/service.rs +++ b/validator_client/src/service.rs @@ -29,7 +29,7 @@ use std::sync::RwLock; use std::time::{Duration, Instant, SystemTime}; use tokio::prelude::*; use tokio::runtime::Builder; -use tokio::timer::{Delay, Interval}; +use tokio::timer::Interval; use tokio_timer::clock::Clock; use types::test_utils::generate_deterministic_keypairs; use types::{ChainSpec, Epoch, Fork, Slot}; From 914e0cf1fc523dfcdfdb30f10d3452d0a8bde040 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 3 Apr 2019 17:27:32 +1100 Subject: [PATCH 106/106] Skip long-running tests in debug --- eth2/state_processing/tests/tests.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth2/state_processing/tests/tests.rs b/eth2/state_processing/tests/tests.rs index 1394eeba0..1359508dc 100644 --- a/eth2/state_processing/tests/tests.rs +++ b/eth2/state_processing/tests/tests.rs @@ -1,5 +1,6 @@ use serde_derive::Deserialize; use serde_yaml; +#[cfg(not(debug_assertions))] use state_processing::{ per_block_processing, per_block_processing_without_verifying_block_signature, per_slot_processing, @@ -62,6 +63,7 @@ fn test_read_yaml() { } #[test] +#[cfg(not(debug_assertions))] fn run_state_transition_tests_small() { // Test sanity-check_small-config_32-vals.yaml let mut file = {