Skip to content

Commit 430c33c

Browse files
authored
Merge pull request casper-network#5217 from zajko/documenting_cited_signatures_assumptions
Added tests which document how RewardedSignatures are assembled.
2 parents 4bfac16 + ebc3aa6 commit 430c33c

1 file changed

Lines changed: 159 additions & 0 deletions

File tree

node/src/components/consensus/era_supervisor.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,32 @@ async fn join_2<T: Future, U: Future>(
15391539
futures::join!(t, u)
15401540
}
15411541

1542+
// The created RewardedSignatures should contain bit vectors for each of the block for which
1543+
// signatures are being cited. If we are eligible to cite 3 blocks, RewardsSignature will contain an
1544+
// at-most 3 vectors of bit vectors (Vec<Vec<u8>>). With `signature_rewards_max_delay = 3` The logic
1545+
// is - "we can cite signatures for the blocks parent, parents parent and parents parent parent".
1546+
// If we are close to genesis, the outer vector will obviously not have 3 entries.
1547+
// (At height 0 there is no parent, at height 1 there is no grandparent etc.)
1548+
// The `rewarded_signatures` vector will look something like:
1549+
// [[255, 64],[128, 0],[0, 0]]
1550+
// Entries in the outer vec are interpreted as:
1551+
// - on index 0 - the last finalized block
1552+
// - on index 1 - the penultimate finalized block
1553+
// - on index 2 - the penpenultimate finalized block
1554+
// There are at most `signature_rewards_max_delay` entries in this vector. if we are "close" to
1555+
// genesis there can be less (at height 0 there is no history, so there will be no cited blocks, at
1556+
// height 1 we can only cite signatures from one block etc.) Each entry in this vector is also a
1557+
// vector of u8 numbers. To interpret them we need to realize that if we concatenate all the bytes
1558+
// of the numbers, the nth bit will say that the nth validators signature was either cited (if the
1559+
// bit is 1) or not (if the bit is 0). To figure out which validator is on position n, we need to
1560+
// take all the validators relevant to the era of the particular block, fetch their public keys and
1561+
// sort them ascending. In the quoted example we see that: For the parent on the proposed block we
1562+
// cite signatures of validators on position 0, 1, 2, 3, 4, 5, 6, 7 and 9 For the grandparent on
1563+
// the proposed block we cite signatures of validators on position 0 For the grandgrandparent on
1564+
// the proposed block we cite no signatures Please note that due to using u8 as the "packing"
1565+
// mechanism it is possible that the byte vector will have more bits than there are validators - we
1566+
// round it up to 8 (ceiling(number_of_valuidators/8)), the remaining bits are only used as padding
1567+
// to full bytes.
15421568
fn create_rewarded_signatures(
15431569
maybe_past_blocks_with_metadata: &[Option<BlockWithMetadata>],
15441570
validator_matrix: ValidatorMatrix,
@@ -1595,3 +1621,136 @@ fn create_rewarded_signatures(
15951621

15961622
rewarded_signatures
15971623
}
1624+
1625+
#[cfg(test)]
1626+
mod tests {
1627+
use std::collections::{BTreeMap, BTreeSet};
1628+
1629+
use crate::{
1630+
consensus::{
1631+
era_supervisor::create_rewarded_signatures,
1632+
tests::utils::{ALICE_PUBLIC_KEY, ALICE_SECRET_KEY, BOB_PUBLIC_KEY, CAROL_PUBLIC_KEY},
1633+
BlockContext, ClContext,
1634+
},
1635+
types::{BlockWithMetadata, ValidatorMatrix},
1636+
};
1637+
use casper_types::{
1638+
bytesrepr::{Bytes, ToBytes},
1639+
testing::TestRng,
1640+
Block, BlockHash, BlockSignatures, BlockSignaturesV2, BlockV2, Digest, EraId,
1641+
ProtocolVersion, PublicKey, RewardedSignatures, Signature, SingleBlockRewardedSignatures,
1642+
Timestamp, U512,
1643+
};
1644+
1645+
#[test]
1646+
fn should_set_first_bit_if_earliest_key_cited() {
1647+
// The first bit in the bit list should be set to 1 if the "lowest" (in the sense of public
1648+
// key comaparison) public key signature was cited.
1649+
let mut rng = TestRng::new();
1650+
1651+
let mut bs_v2 = BlockSignaturesV2::random(&mut rng);
1652+
bs_v2.insert_signature(
1653+
ALICE_PUBLIC_KEY.clone(),
1654+
Signature::ed25519([44; Signature::ED25519_LENGTH]).unwrap(),
1655+
);
1656+
let signatures = build_rewarded_signatures_without_historical_blocks(&mut rng, bs_v2);
1657+
assert_eq!(
1658+
signatures.to_bytes().unwrap(),
1659+
vec![Bytes::from(vec![128_u8])].to_bytes().unwrap()
1660+
);
1661+
}
1662+
1663+
#[test]
1664+
fn should_set_third_bit_if_the_first_validator_signature_cited() {
1665+
// Given there are three validators, if the first (by public key copmparison) validator
1666+
// signature was cited - the third bit should be set to 1
1667+
let mut rng = TestRng::new();
1668+
1669+
let mut bs_v2 = BlockSignaturesV2::random(&mut rng);
1670+
bs_v2.insert_signature(
1671+
BOB_PUBLIC_KEY.clone(),
1672+
Signature::ed25519([44; Signature::ED25519_LENGTH]).unwrap(),
1673+
);
1674+
let signatures = build_rewarded_signatures_without_historical_blocks(&mut rng, bs_v2);
1675+
assert_eq!(
1676+
signatures.to_bytes().unwrap(),
1677+
vec![Bytes::from(vec![32_u8])].to_bytes().unwrap()
1678+
);
1679+
}
1680+
1681+
#[test]
1682+
fn should_set_second_bit_if_the_second_validator_signature_cited() {
1683+
// Given there are three validators, if the second (by public key copmparison) validator
1684+
// signature was cited - the second bit should be set to 1
1685+
let mut rng = TestRng::new();
1686+
1687+
let mut bs_v2 = BlockSignaturesV2::random(&mut rng);
1688+
bs_v2.insert_signature(
1689+
CAROL_PUBLIC_KEY.clone(),
1690+
Signature::ed25519([44; Signature::ED25519_LENGTH]).unwrap(),
1691+
);
1692+
let signatures = build_rewarded_signatures_without_historical_blocks(&mut rng, bs_v2);
1693+
assert_eq!(
1694+
signatures.to_bytes().unwrap(),
1695+
vec![Bytes::from(vec![64_u8])].to_bytes().unwrap()
1696+
);
1697+
}
1698+
1699+
fn build_rewarded_signatures_without_historical_blocks(
1700+
rng: &mut TestRng,
1701+
bs_v2: BlockSignaturesV2,
1702+
) -> RewardedSignatures {
1703+
assert!(*BOB_PUBLIC_KEY > *CAROL_PUBLIC_KEY && *CAROL_PUBLIC_KEY > *ALICE_PUBLIC_KEY);
1704+
let signatures_1 = BTreeSet::new();
1705+
let mut validator_public_keys: BTreeMap<PublicKey, U512> = BTreeMap::new();
1706+
// Making sure that Alice, Bob and Carols keys by stake have different ordering than
1707+
// by PublicKey
1708+
validator_public_keys.insert(
1709+
ALICE_PUBLIC_KEY.clone(),
1710+
U512::MAX.saturating_sub(100.into()),
1711+
);
1712+
validator_public_keys.insert(BOB_PUBLIC_KEY.clone(), 1_u64.into());
1713+
validator_public_keys.insert(CAROL_PUBLIC_KEY.clone(), U512::MAX);
1714+
1715+
let past_rewarded_signatures =
1716+
RewardedSignatures::new(vec![SingleBlockRewardedSignatures::from_validator_set(
1717+
&signatures_1,
1718+
validator_public_keys.keys(),
1719+
)]);
1720+
1721+
let block_v2 = BlockV2::new(
1722+
BlockHash::random(rng),
1723+
Digest::random(rng),
1724+
Digest::random(rng),
1725+
false,
1726+
None,
1727+
Timestamp::now(),
1728+
EraId::new(1),
1729+
1010,
1730+
ProtocolVersion::V2_0_0,
1731+
PublicKey::random(rng),
1732+
BTreeMap::new(),
1733+
past_rewarded_signatures,
1734+
1,
1735+
None,
1736+
);
1737+
let block = Block::V2(block_v2);
1738+
1739+
let block_1 = BlockWithMetadata {
1740+
block,
1741+
block_signatures: BlockSignatures::V2(bs_v2),
1742+
};
1743+
let maybe_past_blocks_with_metadata = vec![Some(block_1)];
1744+
let mut validator_matrix = ValidatorMatrix::new_with_validator(ALICE_SECRET_KEY.clone());
1745+
validator_matrix.register_validator_weights(EraId::new(1), validator_public_keys);
1746+
let timestamp = Timestamp::now();
1747+
let ancestor_values = vec![];
1748+
let block_context = BlockContext::<ClContext>::new(timestamp, ancestor_values);
1749+
create_rewarded_signatures(
1750+
&maybe_past_blocks_with_metadata,
1751+
validator_matrix,
1752+
&block_context,
1753+
1,
1754+
)
1755+
}
1756+
}

0 commit comments

Comments
 (0)