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

Issue 1884 - contract ID generation mechanism #2003

Merged
merged 2 commits into from
Jul 26, 2024
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
6 changes: 6 additions & 0 deletions execution-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
next_epoch,
}`

### Added

- Add `nonce` contract deploy transaction [#1884]


[#1963]: https://github.com/dusk-network/rusk/issues/1963
[#1963]: https://github.com/dusk-network/rusk/issues/1856
[#1884]: https://github.com/dusk-network/rusk/issues/1884
[#1882]: https://github.com/dusk-network/rusk/issues/1882
[#1723]: https://github.com/dusk-network/rusk/issues/1723

Expand Down
7 changes: 7 additions & 0 deletions execution-core/src/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@ pub struct ContractDeploy {
pub owner: Vec<u8>,
/// Constructor arguments of the deployed contract.
pub constructor_args: Option<Vec<u8>>,
/// Nonce for contract id uniqueness and vanity
pub nonce: u64,
}

/// All the data the transfer-contract needs to perform a contract-call.
Expand Down Expand Up @@ -365,6 +367,8 @@ impl ContractDeploy {
None => bytes.push(0),
}

bytes.extend(self.nonce.to_bytes());

bytes
}

Expand All @@ -385,10 +389,13 @@ impl ContractDeploy {
_ => return Err(BytesError::InvalidData),
};

let nonce = u64::from_reader(&mut buf)?;

Ok(Self {
bytecode,
owner,
constructor_args,
nonce,
})
}
}
Expand Down
1 change: 1 addition & 0 deletions execution-core/src/transfer/transaction/moonlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl Transaction {
hash: deploy.bytecode.hash,
bytes: Vec::new(),
},
nonce: deploy.nonce,
})),
},
*self.signature(),
Expand Down
1 change: 1 addition & 0 deletions execution-core/src/transfer/transaction/phoenix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ impl Transaction {
hash: deploy.bytecode.hash,
bytes: Vec::new(),
},
nonce: deploy.nonce,
})),
},
self.proof(),
Expand Down
6 changes: 6 additions & 0 deletions execution-core/tests/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,13 @@ fn phoenix_with_deploy() -> Result<(), Error> {
let mut constructor_args = vec![0; 20];
rng.fill_bytes(&mut constructor_args);

let nonce = rng.next_u64();

let deploy = ContractDeploy {
bytecode,
owner,
constructor_args: Some(constructor_args),
nonce,
};

let transaction =
Expand Down Expand Up @@ -240,10 +243,13 @@ fn moonlight_with_deploy() -> Result<(), Error> {
let mut constructor_args = vec![0; 20];
rng.fill_bytes(&mut constructor_args);

let nonce = rng.next_u64();

let deploy = ContractDeploy {
bytecode,
owner,
constructor_args: Some(constructor_args),
nonce,
};

let transaction =
Expand Down
2 changes: 2 additions & 0 deletions rusk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add `gen_contract_id` and 32-byte hash for contract deployment [#1884]
- Add execution of contract deployment [#1882]
- Add first version of RUES, allowing websocket clients to subscribe for events
emitted by block transitions [#931]
Expand Down Expand Up @@ -210,6 +211,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add linking between Rusk and Protobuff structs
- Add build system that generates keys for circuits and caches them.

[#1884]: https://github.com/dusk-network/rusk/issues/1884
[#1882]: https://github.com/dusk-network/rusk/issues/1882
[#1675]: https://github.com/dusk-network/rusk/issues/1675
[#1640]: https://github.com/dusk-network/rusk/issues/1640
Expand Down
1 change: 1 addition & 0 deletions rusk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ rkyv = { version = "0.7", default-features = false, features = ["size_32"] }
bytecheck = { version = "0.6", default-features = false }
dirs = "4"
blake3 = "1"
blake2b_simd = { version = "1", default-features = false }

poseidon-merkle = { version = "0.6", features = ["rkyv-impl", "size_32"] }
sha3 = "0.10"
Expand Down
7 changes: 6 additions & 1 deletion rusk/src/lib/chain/rusk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use rusk_profile::to_rusk_state_id_path;
use tokio::sync::broadcast;

use super::{coinbase_value, Rusk, RuskTip};
use crate::gen_id::gen_contract_id;
use crate::http::RuesEvent;
use crate::Error::InvalidCreditsCount;
use crate::{Error, Result};
Expand Down Expand Up @@ -540,7 +541,11 @@ fn contract_deploy(
receipt.data = Err(Panic("failed bytecode hash check".into()))
} else {
let result = session.deploy_raw(
None,
Some(gen_contract_id(
miloszm marked this conversation as resolved.
Show resolved Hide resolved
&deploy.bytecode.bytes,
deploy.nonce,
&deploy.owner,
)),
deploy.bytecode.bytes.as_slice(),
deploy.constructor_args.clone(),
deploy.owner.clone(),
Expand Down
53 changes: 53 additions & 0 deletions rusk/src/lib/gen_id.rs
miloszm marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use crate::hash::Hasher;
use rusk_abi::ContractId;

/// Generate a [`ContractId`] address from:
/// - slice of bytes,
/// - nonce
/// - owner
pub fn gen_contract_id(
bytes: impl AsRef<[u8]>,
nonce: u64,
owner: impl AsRef<[u8]>,
) -> ContractId {
let mut hasher = Hasher::new();
hasher.update(bytes.as_ref());
hasher.update(nonce.to_le_bytes());
hasher.update(owner.as_ref());
let hash_bytes = hasher.finalize();
ContractId::from_bytes(hash_bytes)
}

#[cfg(test)]
mod tests {
use super::*;
use rand::rngs::StdRng;
use rand::{RngCore, SeedableRng};

#[test]
fn test_gen_contract_id() {
let mut rng = StdRng::seed_from_u64(42);

let mut bytes = vec![0; 1000];
rng.fill_bytes(&mut bytes);

let nonce = rng.next_u64();

let mut owner = vec![0, 100];
rng.fill_bytes(&mut owner);

let contract_id =
gen_contract_id(bytes.as_slice(), nonce, owner.as_slice());

assert_eq!(
hex::encode(contract_id.as_bytes()),
"a138d3b9c87235dac6f62d1d30b75cffbb94601d9cbe5bd540b3e1e5842c8a7d"
);
}
}
44 changes: 44 additions & 0 deletions rusk/src/lib/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use blake2b_simd::{Params, State};

/// Hashes scalars and arbitrary slices of bytes using Blake2b, returning an
/// array of 32 bytes.
///
/// This hash cannot be proven inside a circuit, if that is desired, use
/// `poseidon_hash` instead.
pub struct Hasher {
state: State,
}

impl Default for Hasher {
fn default() -> Self {
Hasher {
state: Params::new().hash_length(64).to_state(),
}
}
}

impl Hasher {
/// Create new hasher instance.
pub fn new() -> Self {
Self::default()
}

/// Process data, updating the internal state.
pub fn update(&mut self, data: impl AsRef<[u8]>) {
self.state.update(data.as_ref());
}

/// Retrieve result and consume hasher instance.
pub fn finalize(self) -> [u8; 32] {
let hash = self.state.finalize();
let mut a = [0u8; 32];
a.clone_from_slice(&hash.as_array()[..32]);
a
}
}
2 changes: 2 additions & 0 deletions rusk/src/lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#[cfg(feature = "node")]
pub mod chain;
mod error;
pub mod gen_id;
mod hash;
pub mod http;
pub mod verifier;
mod version;
Expand Down
11 changes: 9 additions & 2 deletions rusk/tests/services/contract_deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use execution_core::bytecode::Bytecode;
use execution_core::transfer::{ContractDeploy, ContractExec};
use rand::prelude::*;
use rand::rngs::StdRng;
use rusk::gen_id::gen_contract_id;
use rusk::{Result, Rusk};
use rusk_abi::{ContractData, ContractId, PiecrustError};
use rusk_recovery_tools::state;
Expand Down Expand Up @@ -77,7 +78,12 @@ fn initial_state<P: AsRef<Path>>(dir: P, deploy_bob: bool) -> Result<Rusk> {
bob_bytecode,
ContractData::builder()
.owner(OWNER)
.constructor_arg(&BOB_INIT_VALUE),
.constructor_arg(&BOB_INIT_VALUE)
.contract_id(gen_contract_id(
&bob_bytecode,
0u64,
&OWNER,
)),
POINT_LIMIT,
)
.expect("Deploying the alice contract should succeed");
Expand Down Expand Up @@ -121,6 +127,7 @@ fn make_and_execute_transaction_deploy(
},
owner: OWNER.to_vec(),
constructor_args,
nonce: 0,
}),
SENDER_INDEX,
gas_limit,
Expand Down Expand Up @@ -191,7 +198,7 @@ impl Fixture {
"../../../target/dusk/wasm32-unknown-unknown/release/bob.wasm"
)
.to_vec();
let contract_id = bytecode_hash(bob_bytecode.as_slice());
let contract_id = gen_contract_id(&bob_bytecode, 0u64, &OWNER);

let path = tmp.into_path();
Self {
Expand Down
Loading