Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Random Number Generation #2053

Merged
merged 21 commits into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
556adfd
feat(rad): add RNG in retrieval RADType
lrubiorod Sep 2, 2021
d3a7af7
feat(rad): skipping aggregation when rng
lrubiorod Sep 3, 2021
bf45289
feat(rad): implement HashConcatenate reducer
lrubiorod Sep 3, 2021
61c052f
feat(rad): include tapi activation for includeing RNG functionality
lrubiorod Sep 6, 2021
e769da5
feat(data_request): modify sorting in get_all_reveals
lrubiorod Sep 6, 2021
5b92d2b
feat(rad): during RNG, ensure reveal bytes has the same lenght
lrubiorod Sep 6, 2021
ff41187
feat: add random_bytes.json data request example
tmpolaczyk Sep 6, 2021
5115fbc
fix(tapi): include wip19 in tapi initialize test
lrubiorod Sep 6, 2021
5e0cdd9
test: tally rng request
tmpolaczyk Sep 6, 2021
799fb3f
refactor: improve and test hash concatenate
tmpolaczyk Sep 7, 2021
9fd5df6
refactor(rad): modify HashConcatenate reducer code
lrubiorod Sep 7, 2021
f317060
feat(rad): add unwrap reducer
lrubiorod Sep 8, 2021
d6639ac
fix(rad): fix rng tally tests
lrubiorod Sep 8, 2021
044c670
feat(validation): remove extra validations for rng
lrubiorod Sep 8, 2021
619ae2a
feat(rad): include tapi in RadType validation
lrubiorod Sep 13, 2021
beeac1f
refactor(rad): remove option for active_wips
lrubiorod Sep 14, 2021
a29a77a
fix(tapi): fix tests after include RadType changes
lrubiorod Sep 14, 2021
a744726
refactor(rad): remove RadonReducers::Unwrap, using RadonReducers::Mod…
lrubiorod Sep 15, 2021
f8e1540
feat(rad): convert RadType from HttpGet to Unknown before WIP-0019 ac…
lrubiorod Sep 16, 2021
5e35b2c
refactor: move current_active_wips and all_wips_active to mainnet_val…
lrubiorod Sep 17, 2021
1b3176c
feat: apply suggestions
lrubiorod Sep 17, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion bridges/centralized-ethereum/src/actors/dr_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use serde_json::json;
use std::{fmt, time::Duration};
use witnet_data_structures::{
chain::{DataRequestOutput, Hash},
mainnet_validations::current_active_wips,
proto::ProtobufConvert,
radon_error::RadonErrors,
};
Expand Down Expand Up @@ -263,7 +264,7 @@ fn deserialize_and_validate_dr_bytes(
});
}

validate_rad_request(&dr_output.data_request, None)
validate_rad_request(&dr_output.data_request, &current_active_wips())
.map_err(|e| DrSenderError::RadonValidation { msg: e.to_string() })?;

// Check if we want to claim this data request:
Expand Down
53 changes: 21 additions & 32 deletions bridges/centralized-ethereum/src/actors/dr_sender/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,33 @@ fn deserialize_dr_not_protobuf() {
assert_eq!(err.encode_cbor(), vec![216, 39, 129, 24, 224]);
}

fn example_request() -> RADRequest {
RADRequest {
retrieve: vec![RADRetrieve {
url: "http://127.0.0.1:8000".to_string(),
script: vec![128],
..Default::default()
}],
aggregate: RADAggregate {
filters: vec![],
reducer: 3,
},
tally: RADTally {
filters: vec![],
reducer: 3,
},
time_lock: 0,
}
}

#[test]
fn deserialize_dr_high_value() {
// A minimal valid data request
let dro = DataRequestOutput {
witness_reward: 1_000_000,
witnesses: 20,
min_consensus_percentage: 51,
data_request: RADRequest {
retrieve: vec![RADRetrieve {
url: "http://127.0.0.1:8000".to_string(),
script: vec![128],
..Default::default()
}],
aggregate: RADAggregate {
filters: vec![],
reducer: 3,
},
tally: RADTally {
filters: vec![],
reducer: 3,
},
time_lock: 0,
},
data_request: example_request(),
..Default::default()
};
// The cost of creating this data request is the reward (1_000_000) times the number of
Expand All @@ -60,22 +64,7 @@ fn deserialize_dr_value_overflow() {
witness_reward: u64::MAX,
witnesses: 20,
min_consensus_percentage: 51,
data_request: RADRequest {
retrieve: vec![RADRetrieve {
url: "http://127.0.0.1:8000".to_string(),
script: vec![128],
..Default::default()
}],
aggregate: RADAggregate {
filters: vec![],
reducer: 3,
},
tally: RADTally {
filters: vec![],
reducer: 3,
},
time_lock: 0,
},
data_request: example_request(),
..Default::default()
};

Expand Down
3 changes: 2 additions & 1 deletion bridges/ethereum/src/actors/claim_and_post.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use web3::{contract, futures::Future, types::U256};
use witnet_crypto::hash::{calculate_sha256, Sha256};
use witnet_data_structures::{
chain::{DataRequestOutput, Hashable, KeyedSignature},
mainnet_validations::current_active_wips,
proto::ProtobufConvert,
};
use witnet_util::timestamp::get_local_timestamp;
Expand Down Expand Up @@ -97,7 +98,7 @@ fn try_to_claim_local_query(

let dr_output: DataRequestOutput =
match ProtobufConvert::from_pb_bytes(&dr_bytes).and_then(|dr: DataRequestOutput| {
validate_rad_request(&dr.data_request, None)?;
validate_rad_request(&dr.data_request, &current_active_wips())?;
Ok(dr)
}) {
Ok(x) => {
Expand Down
9 changes: 8 additions & 1 deletion data_structures/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1584,14 +1584,21 @@ impl Hashable for Bn256Signature {
/// Retrieval type
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize, Hash)]
pub enum RADType {
/// Unknown
#[serde(rename = "Unknown")]
Unknown,
/// HTTP GET request
#[serde(rename = "HTTP-GET")]
HttpGet,
/// Random number generation
#[serde(rename = "RNG")]
Rng,
}

impl Default for RADType {
fn default() -> Self {
RADType::HttpGet
// TODO: Use RadType::HttpGet after WIP-0019 activation
RADType::Unknown
Comment on lines +1600 to +1601
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think RADType::Unknown is a good default value, the problem is that this is used in tests so any tests that want to create a "default HttpGet request" can use a helper function.

Suggested change
// TODO: Use RadType::HttpGet after WIP-0019 activation
RADType::Unknown
RADType::Unknown

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could do a refactor in tests after WIP19 activation

}
}

Expand Down
46 changes: 40 additions & 6 deletions data_structures/src/data_request.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use std::convert::TryFrom;
use std::{
collections::{BTreeMap, HashMap, HashSet},
convert::TryFrom,
};

use serde::{Deserialize, Serialize};

Expand All @@ -13,6 +15,7 @@ use crate::{
radon_report::{RadonReport, Stage, TypeLike},
transaction::{CommitTransaction, DRTransaction, RevealTransaction, TallyTransaction},
};
use witnet_crypto::hash::calculate_sha256;

/// Pool of active data requests
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -56,10 +59,21 @@ impl DataRequestPool {
}

/// Get all reveals related to a `DataRequestOuput`
pub fn get_reveals(&self, dr_pointer: &Hash) -> Option<Vec<&RevealTransaction>> {
pub fn get_reveals(
&self,
dr_pointer: &Hash,
active_wips: &ActiveWips,
) -> Option<Vec<&RevealTransaction>> {
self.data_request_pool.get(dr_pointer).map(|dr_state| {
let mut reveals: Vec<&RevealTransaction> = dr_state.info.reveals.values().collect();
reveals.sort_unstable_by_key(|reveal| reveal.body.pkh);
if active_wips.wip0019() {
// As specified in (7) in WIP-0019
reveals.sort_unstable_by_key(|reveal| {
lrubiorod marked this conversation as resolved.
Show resolved Hide resolved
concatenate_and_hash(&reveal.body.pkh.hash, dr_pointer.as_ref())
});
} else {
reveals.sort_unstable_by_key(|reveal| reveal.body.pkh);
}

reveals
})
Expand All @@ -71,14 +85,25 @@ impl DataRequestPool {
}

/// Get all the reveals
pub fn get_all_reveals(&self) -> HashMap<Hash, Vec<RevealTransaction>> {
pub fn get_all_reveals(
lrubiorod marked this conversation as resolved.
Show resolved Hide resolved
&self,
active_wips: &ActiveWips,
) -> HashMap<Hash, Vec<RevealTransaction>> {
self.data_request_pool
.iter()
.filter_map(|(dr_pointer, dr_state)| {
if let DataRequestStage::TALLY = dr_state.stage {
let mut reveals: Vec<RevealTransaction> =
dr_state.info.reveals.values().cloned().collect();
reveals.sort_unstable_by_key(|reveal| reveal.body.pkh);

if active_wips.wip0019() {
// As specified in (7) in WIP-0019
reveals.sort_unstable_by_key(|reveal| {
concatenate_and_hash(&reveal.body.pkh.hash, dr_pointer.as_ref())
});
} else {
reveals.sort_unstable_by_key(|reveal| reveal.body.pkh);
}

Some((*dr_pointer, reveals))
} else {
Expand Down Expand Up @@ -393,6 +418,15 @@ impl DataRequestPool {
}
}

/// Concatenate 2 bytes sequences and hash
fn concatenate_and_hash(a: &[u8], b: &[u8]) -> [u8; 32] {
let mut bytes_to_hash = vec![];
bytes_to_hash.extend(a);
bytes_to_hash.extend(b);

calculate_sha256(bytes_to_hash.as_ref()).0
}

/// Return the change that should be returned to the creator of the data request if
/// some witness fails to commit, fails to reveal, or reports a value out of consensus.
/// If the change is 0, the change `ValueTransferOutput` should not be created
Expand Down
2 changes: 2 additions & 0 deletions data_structures/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,8 @@ pub enum DataRequestError {
UnfinishedDataRequest,
#[fail(display = "The data request is not valid since it has no retrieval sources")]
NoRetrievalSources,
#[fail(display = "The data request has not a valid RadType")]
InvalidRadType,
}

/// Possible errors when converting between epoch and timestamp
Expand Down
22 changes: 21 additions & 1 deletion data_structures/src/mainnet_validations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,26 @@ fn test_wip_info() -> HashMap<String, Epoch> {
active_wips
}

/// Auxiliary function that returns the current active wips for using in RADON
/// It is only used for testing or for external libraries, so we set epoch to MAX
pub fn current_active_wips() -> ActiveWips {
ActiveWips {
active_wips: wip_info(),
block_epoch: u32::MAX,
}
}

/// Auxiliary function that returns the current active wips and the WIPs in voting process as actived
/// It is only used for testing
pub fn all_wips_active() -> ActiveWips {
let mut active_wips = current_active_wips();
active_wips
.active_wips
.insert("WIP0017-0018-0019".to_string(), 0);

active_wips
}

impl TapiEngine {
pub fn update_bit_counter(
&mut self,
Expand Down Expand Up @@ -681,7 +701,7 @@ mod tests {

// Test initialize_wip_information with a non-empty TapiEngine
let (epoch, old_wips) = t.initialize_wip_information(Environment::Mainnet);
// WIP0017 is already included and it won't be updated
// WIP0017-18-19 is already included and it won't be updated
let name_wip0017_18_19 = "WIP0017-0018-0019".to_string();
let mut hs = HashSet::new();
hs.insert(name_wip0017_18_19);
Expand Down
4 changes: 4 additions & 0 deletions data_structures/src/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,17 @@ impl ProtobufConvert for chain::RADType {

fn to_pb(&self) -> Self::ProtoStruct {
match self {
chain::RADType::Unknown => witnet::DataRequestOutput_RADRequest_RADType::Unknown,
chain::RADType::HttpGet => witnet::DataRequestOutput_RADRequest_RADType::HttpGet,
chain::RADType::Rng => witnet::DataRequestOutput_RADRequest_RADType::Rng,
}
}

fn from_pb(pb: Self::ProtoStruct) -> Result<Self, Error> {
Ok(match pb {
witnet::DataRequestOutput_RADRequest_RADType::Unknown => chain::RADType::Unknown,
witnet::DataRequestOutput_RADRequest_RADType::HttpGet => chain::RADType::HttpGet,
witnet::DataRequestOutput_RADRequest_RADType::Rng => chain::RADType::Rng,
})
}
}
Expand Down
1 change: 1 addition & 0 deletions examples/random_bytes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"jsonrpc":"2.0","method":"sendRequest","id":"1","params":{"dro":{"data_request":{"time_lock":0,"retrieve":[{"kind":"RNG","url":"","script":[128]}],"aggregate":{"filters":[],"reducer":2},"tally":{"filters":[],"reducer":11}},"witness_reward":1000,"witnesses":5,"commit_and_reveal_fee":10,"min_consensus_percentage":51,"collateral":1000000000},"fee":0}}
19 changes: 16 additions & 3 deletions node/src/actors/chain_manager/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{
use witnet_data_structures::{
chain::{
Block, ChainState, CheckpointBeacon, DataRequestInfo, Epoch, Hash, Hashable, NodeStats,
SuperBlockVote, SupplyInfo,
RADType, SuperBlockVote, SupplyInfo,
},
error::{ChainInfoError, TransactionError::DataRequestNotFound},
mainnet_validations::ActiveWips,
Expand Down Expand Up @@ -1277,13 +1277,26 @@ impl Handler<BuildDrt> for ChainManager {
block_epoch: self.current_epoch.unwrap(),
};

if let Err(e) = validate_rad_request(&msg.dro.data_request, Some(&active_wips)) {
let mut dr_output = msg.dro;
// TODO: Remove after WIP-0019 activation
// Before wip-0019 activation, RadType::HttpGet enum is serialized with a 0.
// With the new update, position 0 is RadType::Unknown, so to keep backward compatibility,
// we need to convert HttpGet retrievals to Unknown.
if !active_wips.wip0019() {
for retrieval in &mut dr_output.data_request.retrieve {
if retrieval.kind == RADType::HttpGet {
retrieval.kind = RADType::Unknown;
}
}
}

if let Err(e) = validate_rad_request(&dr_output.data_request, &active_wips) {
return Box::pin(actix::fut::err(e));
}
let timestamp = u64::try_from(get_timestamp()).unwrap();
let max_dr_weight = self.consensus_constants().max_dr_weight;
match transaction_factory::build_drt(
msg.dro,
dr_output,
msg.fee,
&mut self.chain_state.own_utxos,
self.own_pkh.unwrap(),
Expand Down
Loading