Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ logs
*.so
*.a

# Proptest regression files for when proptest's fail
**/proptest-regressions

# fog-test directory from fog-local-network instructions
/fog-test/

Expand Down
4 changes: 3 additions & 1 deletion Cargo.lock

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

23 changes: 16 additions & 7 deletions android-bindings/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ use mc_transaction_core::{
create_shared_secret, recover_onetime_private_key, recover_public_subaddress_spend_key,
},
ring_signature::KeyImage,
tokens::Mob,
tx::{Tx, TxOut, TxOutConfirmationNumber, TxOutMembershipProof},
Amount, BlockVersion, CompressedCommitment,
Amount, BlockVersion, CompressedCommitment, Token,
};
use mc_transaction_std::{InputCredentials, RTHMemoBuilder, TransactionBuilder};
use mc_util_from_random::FromRandom;
Expand Down Expand Up @@ -310,9 +311,12 @@ pub unsafe extern "C" fn Java_com_mobilecoin_lib_Amount_init_1jni(
jni_ffi_call(&env, |env| {
let commitment_bytes = env.convert_byte_array(commitment)?;

// FIXME #1595: We should get a masked token id also, here we default to
// 0 bytes, which is backwards compatible
let amount = Amount {
commitment: CompressedCommitment::try_from(&commitment_bytes[..])?,
masked_value: masked_value as u64,
masked_token_id: Default::default(),
};
Ok(env.set_rust_field(obj, RUST_OBJ_FIELD, amount)?)
})
Expand All @@ -328,9 +332,9 @@ pub unsafe extern "C" fn Java_com_mobilecoin_lib_Amount_init_1jni_1with_1secret(
jni_ffi_call(&env, |env| {
let tx_out_shared_secret: MutexGuard<RistrettoPublic> =
env.get_rust_field(tx_out_shared_secret, RUST_OBJ_FIELD)?;
let value =
(masked_value as u64) ^ mc_transaction_core::get_value_mask(&tx_out_shared_secret);
let amount: Amount = Amount::new(value, &tx_out_shared_secret)?;
// FIXME #1595: the masked token id should be 0 or 4 bytes.
// To avoid breaking changes, it is hard coded to 0 bytes here
let amount = Amount::reconstruct(masked_value as u64, &[], &tx_out_shared_secret)?;

Ok(env.set_rust_field(obj, RUST_OBJ_FIELD, amount)?)
})
Expand Down Expand Up @@ -377,14 +381,15 @@ pub unsafe extern "C" fn Java_com_mobilecoin_lib_Amount_unmask_1value(
let tx_pub_key: MutexGuard<RistrettoPublic> =
env.get_rust_field(tx_pub_key, RUST_OBJ_FIELD)?;
let shared_secret = create_shared_secret(&tx_pub_key, &view_key);
let value = amount.get_value(&shared_secret)?.0;
let (amount_data, _) = amount.get_value(&shared_secret)?;
Ok(env
.new_object(
"java/math/BigInteger",
"(I[B)V", // public BigInteger(int signum, byte[] magnitude)
&[
1.into(),
env.byte_array_from_slice(&value.to_be_bytes())?.into(),
env.byte_array_from_slice(&amount_data.value.to_be_bytes())?
.into(),
],
)?
.into_inner())
Expand Down Expand Up @@ -1177,7 +1182,11 @@ pub unsafe extern "C" fn Java_com_mobilecoin_lib_TransactionBuilder_init_1jni(
// credentials memo_builder.set_sender_credential(SenderMemoCredential::
// from(source_account_key));
memo_builder.enable_destination_memo();
let tx_builder = TransactionBuilder::new(block_version, fog_resolver.clone(), memo_builder);
// FIXME #1595: The token id should be a parameter and not hard coded to Mob
// here
let token_id = Mob::ID;
let tx_builder =
TransactionBuilder::new(block_version, token_id, fog_resolver.clone(), memo_builder);
Ok(env.set_rust_field(obj, RUST_OBJ_FIELD, tx_builder)?)
})
}
Expand Down
17 changes: 17 additions & 0 deletions api/proto/external.proto
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,17 @@ message ViewKey {
// `trasaction/core` crate
///////////////////////////////////////////////////////////////////////////////

/// A list of "known" token id's and their names.
///
/// Note that this is not an exhaustive list and clients should gracefully handle
/// the scenario that they receive a tx out with a token id they don't know about yet.
///
/// If changing this, please keep it in sync with the list defined in
/// mc-transaction-core in the tokens module.
enum KnownTokenId {
MOB = 0;
}

/// A 32-byte scalar associated to the ristretto group.
/// This is the same as RistrettoPrivate, but they are used in different places.
/// TODO: MC-1605 Consider to factor out this type, or just this proto message.
Expand Down Expand Up @@ -175,6 +186,9 @@ message Amount {

// `masked_value = value XOR_8 Blake2B("value_mask" || shared_secret)`
fixed64 masked_value = 2;

// `masked_token_id = token_id XOR_8 Blake2B("token_id_mask" || shared_secret)`
bytes masked_token_id = 3;
}

// The bytes of encrypted fog hint
Expand Down Expand Up @@ -228,6 +242,9 @@ message TxPrefix {

// The block index at which this transaction is no longer valid.
uint64 tombstone_block = 4;

// Token id for this transaction
fixed32 token_id = 5;
}

message RingMLSAG {
Expand Down
3 changes: 3 additions & 0 deletions api/src/convert/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl From<&Amount> for external::Amount {
let mut amount = external::Amount::new();
amount.mut_commitment().set_data(commitment_bytes);
amount.set_masked_value(source.masked_value);
amount.set_masked_token_id(source.masked_token_id.clone());
amount
}
}
Expand All @@ -21,9 +22,11 @@ impl TryFrom<&external::Amount> for Amount {
fn try_from(source: &external::Amount) -> Result<Self, Self::Error> {
let commitment = CompressedCommitment::try_from(source.get_commitment())?;
let masked_value = source.get_masked_value();
let masked_token_id = source.get_masked_token_id();
let amount = Amount {
commitment,
masked_value,
masked_token_id: masked_token_id.to_vec(),
};
Ok(amount)
}
Expand Down
10 changes: 8 additions & 2 deletions api/src/convert/archive_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,10 @@ mod tests {
encrypted_fog_hint::ENCRYPTED_FOG_HINT_LEN,
membership_proofs::Range,
ring_signature::KeyImage,
tokens::Mob,
tx::{TxOut, TxOutMembershipElement, TxOutMembershipHash},
Amount, Block, BlockContents, BlockData, BlockID, BlockSignature, BlockVersion,
Amount, AmountData, Block, BlockContents, BlockData, BlockID, BlockSignature, BlockVersion,
Token,
};
use mc_util_from_random::FromRandom;
use rand::{rngs::StdRng, SeedableRng};
Expand All @@ -133,8 +135,12 @@ mod tests {
let mut last_block: Option<Block> = None;

for block_idx in 0..num_blocks {
let amount_data = AmountData {
value: 1u64 << 13,
token_id: Mob::ID,
};
let tx_out = TxOut {
amount: Amount::new(1u64 << 13, &RistrettoPublic::from_random(&mut rng)).unwrap(),
amount: Amount::new(amount_data, &RistrettoPublic::from_random(&mut rng)).unwrap(),
target_key: RistrettoPublic::from_random(&mut rng).into(),
public_key: RistrettoPublic::from_random(&mut rng).into(),
e_fog_hint: (&[0u8; ENCRYPTED_FOG_HINT_LEN]).into(),
Expand Down
4 changes: 3 additions & 1 deletion api/src/convert/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ mod tests {
use mc_crypto_keys::RistrettoPublic;
use mc_transaction_core::{
onetime_keys::recover_onetime_private_key,
tokens::Mob,
tx::{Tx, TxOut, TxOutMembershipProof},
BlockVersion,
BlockVersion, Token,
};
use mc_transaction_core_test_utils::MockFogResolver;
use mc_transaction_std::{EmptyMemoBuilder, InputCredentials, TransactionBuilder};
Expand Down Expand Up @@ -70,6 +71,7 @@ mod tests {

let mut transaction_builder = TransactionBuilder::new(
block_version,
Mob::ID,
MockFogResolver::default(),
EmptyMemoBuilder::default(),
);
Expand Down
16 changes: 13 additions & 3 deletions api/src/convert/tx_out.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ mod tests {
use super::*;
use generic_array::GenericArray;
use mc_crypto_keys::RistrettoPublic;
use mc_transaction_core::{encrypted_fog_hint::ENCRYPTED_FOG_HINT_LEN, Amount};
use mc_transaction_core::{
encrypted_fog_hint::ENCRYPTED_FOG_HINT_LEN, tokens::Mob, Amount, AmountData, Token,
};
use mc_util_from_random::FromRandom;
use rand::{rngs::StdRng, SeedableRng};

Expand All @@ -87,8 +89,12 @@ mod tests {
fn test_tx_out_from_tx_out_stored() {
let mut rng: StdRng = SeedableRng::from_seed([1u8; 32]);

let amount_data = AmountData {
value: 1u64 << 13,
token_id: Mob::ID,
};
let source = tx::TxOut {
amount: Amount::new(1u64 << 13, &RistrettoPublic::from_random(&mut rng)).unwrap(),
amount: Amount::new(amount_data, &RistrettoPublic::from_random(&mut rng)).unwrap(),
target_key: RistrettoPublic::from_random(&mut rng).into(),
public_key: RistrettoPublic::from_random(&mut rng).into(),
e_fog_hint: (&[0u8; ENCRYPTED_FOG_HINT_LEN]).into(),
Expand All @@ -106,8 +112,12 @@ mod tests {
fn test_tx_out_from_tx_out_stored_with_memo() {
let mut rng: StdRng = SeedableRng::from_seed([1u8; 32]);

let amount_data = AmountData {
value: 1u64 << 13,
token_id: Mob::ID,
};
let source = tx::TxOut {
amount: Amount::new(1u64 << 13, &RistrettoPublic::from_random(&mut rng)).unwrap(),
amount: Amount::new(amount_data, &RistrettoPublic::from_random(&mut rng)).unwrap(),
target_key: RistrettoPublic::from_random(&mut rng).into(),
public_key: RistrettoPublic::from_random(&mut rng).into(),
e_fog_hint: (&[0u8; ENCRYPTED_FOG_HINT_LEN]).into(),
Expand Down
3 changes: 3 additions & 0 deletions api/src/convert/tx_prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ impl From<&tx::TxPrefix> for external::TxPrefix {

tx_prefix.set_fee(source.fee);

tx_prefix.set_token_id(source.token_id);

tx_prefix.set_tombstone_block(source.tombstone_block);

tx_prefix
Expand Down Expand Up @@ -45,6 +47,7 @@ impl TryFrom<&external::TxPrefix> for tx::TxPrefix {
inputs,
outputs,
fee: source.get_fee(),
token_id: source.get_token_id(),
tombstone_block: source.get_tombstone_block(),
};
Ok(tx_prefix)
Expand Down
22 changes: 22 additions & 0 deletions api/tests/tokens.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use mc_api::external::KnownTokenId;
use mc_transaction_core::{tokens, Token};
use protobuf::ProtobufEnum;
use std::collections::HashMap;

// Test that protobuf KnownTokens enum matches the tokens in mc-transaction-core
#[test]
fn test_known_tokens_enum_vs_mc_transaction_core_tokens() {
// Collect known tokens from proto
let mut known_tokens = HashMap::<String, i32>::default();

let descriptor = KnownTokenId::enum_descriptor_static();
for value in KnownTokenId::values() {
known_tokens.insert(
descriptor.value_by_number(value.value()).name().to_string(),
value.value(),
);
}

assert_eq!(known_tokens.len(), 1);
assert_eq!(*known_tokens.get("MOB").unwrap() as u32, *tokens::Mob::ID);
}
3 changes: 3 additions & 0 deletions consensus/api/proto/consensus_common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ enum ProposeTxResult {
UnsortedInputs = 39;
MissingMemo = 40;
MemosNotAllowed = 41;
TokenNotYetConfigured = 42;
MissingMaskedTokenId = 43;
MaskedTokenIdNotAllowed = 44;
}

/// Response from TxPropose RPC call.
Expand Down
6 changes: 6 additions & 0 deletions consensus/api/src/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ impl From<Error> for ProposeTxResult {
Error::UnsortedInputs => Self::UnsortedInputs,
Error::MissingMemo => Self::MissingMemo,
Error::MemosNotAllowed => Self::MemosNotAllowed,
Error::TokenNotYetConfigured => Self::TokenNotYetConfigured,
Error::MissingMaskedTokenId => Self::MissingMaskedTokenId,
Error::MaskedTokenIdNotAllowed => Self::MaskedTokenIdNotAllowed,
}
}
}
Expand Down Expand Up @@ -93,6 +96,9 @@ impl TryInto<Error> for ProposeTxResult {
Self::UnsortedInputs => Ok(Error::UnsortedInputs),
Self::MissingMemo => Ok(Error::MissingMemo),
Self::MemosNotAllowed => Ok(Error::MemosNotAllowed),
Self::TokenNotYetConfigured => Ok(Error::TokenNotYetConfigured),
Self::MissingMaskedTokenId => Ok(Error::MissingMaskedTokenId),
Self::MaskedTokenIdNotAllowed => Ok(Error::MaskedTokenIdNotAllowed),
}
}
}
Expand Down
Loading