OpenPay (1 crate, 1801 LOC, 57 tests)
op-bin BIN/IIN database + range matching + card-network
classification. 8-digit normalized prefix Bin +
BinRange. Sorted-vec interval tree with O(log N) point
lookup + overlap rejection. CardNetwork classify()
with structural rules (Visa 4, MC 51-55/2221-2720,
Amex 34/37, Discover, JCB, Diners, UnionPay, RuPay,
Mir, Troy, Maestro, Elo). Static prefix tables +
build_default_tree(). ISO/IEC 7812-1 Annex B Luhn
(validate / is_valid / check_digit). Card-type +
issuer-country + Durbin regulated-debit. PCI-safe:
8-digit cap, no full-PAN APIs.
Smart Byte (1 crate, ~1500 LOC, 20 tests)
smart-byte-tendermint BFT consensus. Step enum + Round + propose/prevote/
precommit/commit FSM with voting-power tallies.
ValidatorSet with 2/3+1 quorum, 1/3+1 trust
threshold, round-robin proposer. Block / Header /
Commit / CommitSig with Blake3 hashing. Light client
(sequential + skipping). ABCI Application trait +
EchoApp. DuplicateVoteEvidence + LightClientAttackEvidence.
IBC ClientState + ConsensusState + light-client
update.
EOC (1 crate, 2084 LOC, 23 tests)
eoc-safety AI safety primitives. RegexSet over 16 prompt-injection
signatures. 13-family jailbreak detector (DAN/DUDE/
Grandma/STAN/AIM/dev-mode/etc.). Presidio-style PII
redactor with Luhn-validated CC. Toxicity / bias /
NSFW classifier traits + heuristic baselines (5-axis
bias, 4-category NSFW with hard-reject for minors).
Constitutional AI critique→revise loop. Composable
InputGuard / OutputGuard pipelines. JSON-Schema-subset
output validator. Token-bucket rate limiter +
abuse-window detection. Red-team replay harness.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
70 lines
2.1 KiB
Rust
70 lines
2.1 KiB
Rust
use smart_byte_tendermint::validator::{Validator, ValidatorId, ValidatorSet};
|
|
|
|
fn vid(b: u8) -> ValidatorId {
|
|
ValidatorId::from_bytes([b; 32])
|
|
}
|
|
|
|
#[test]
|
|
fn quorum_is_two_thirds_plus_one_for_equal_power() {
|
|
// 4 validators with power 1 each, total = 4
|
|
let vs = ValidatorSet::new((0..4).map(|i| Validator::new(vid(i as u8), 1))).unwrap();
|
|
assert_eq!(vs.total_voting_power(), 4);
|
|
// floor(2*4/3)+1 = floor(2.66)+1 = 2+1 = 3
|
|
assert_eq!(vs.quorum(), 3);
|
|
}
|
|
|
|
#[test]
|
|
fn quorum_handles_weighted_validators() {
|
|
// total = 100 → quorum = 66+1 = 67
|
|
let vs = ValidatorSet::new(vec![
|
|
Validator::new(vid(1), 40),
|
|
Validator::new(vid(2), 30),
|
|
Validator::new(vid(3), 20),
|
|
Validator::new(vid(4), 10),
|
|
])
|
|
.unwrap();
|
|
assert_eq!(vs.total_voting_power(), 100);
|
|
assert_eq!(vs.quorum(), 67);
|
|
assert_eq!(vs.trust_threshold(), 34);
|
|
}
|
|
|
|
#[test]
|
|
fn has_quorum_aggregates_signers_by_power() {
|
|
let vs = ValidatorSet::new(vec![
|
|
Validator::new(vid(1), 40),
|
|
Validator::new(vid(2), 30),
|
|
Validator::new(vid(3), 20),
|
|
Validator::new(vid(4), 10),
|
|
])
|
|
.unwrap();
|
|
// 40 + 30 = 70 ≥ 67 → quorum
|
|
assert!(vs.has_quorum([&vid(1), &vid(2)].into_iter()));
|
|
// 40 + 20 = 60 < 67 → no quorum
|
|
assert!(!vs.has_quorum([&vid(1), &vid(3)].into_iter()));
|
|
// unknown validator → no quorum
|
|
assert!(!vs.has_quorum([&vid(99)].into_iter()));
|
|
}
|
|
|
|
#[test]
|
|
fn overflow_returns_error() {
|
|
let err = ValidatorSet::new(vec![
|
|
Validator::new(vid(1), u64::MAX),
|
|
Validator::new(vid(2), 1),
|
|
]);
|
|
assert!(err.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn proposer_rotates_by_round() {
|
|
let vs = ValidatorSet::new((0..4).map(|i| Validator::new(vid(i as u8), 1))).unwrap();
|
|
let p0 = vs.proposer(1, 0).unwrap().id;
|
|
let p1 = vs.proposer(1, 1).unwrap().id;
|
|
let p2 = vs.proposer(1, 2).unwrap().id;
|
|
let p3 = vs.proposer(1, 3).unwrap().id;
|
|
let p4 = vs.proposer(1, 4).unwrap().id;
|
|
// round-robin: 1,2,3,0,1
|
|
assert_ne!(p0, p1);
|
|
assert_ne!(p1, p2);
|
|
assert_ne!(p2, p3);
|
|
assert_eq!(p0, p4);
|
|
}
|