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

Provide an API for deterministic contract generation #111

Closed
oneforalone opened this issue Nov 22, 2023 · 15 comments · Fixed by #118 or #117
Closed

Provide an API for deterministic contract generation #111

oneforalone opened this issue Nov 22, 2023 · 15 comments · Fixed by #118 or #117
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@oneforalone
Copy link

I tried to make every arguments to const value, however, each time i compiled it, the contract id changes. And after take tracing the code, found the contract id is generate from lib commit_verify's function commitment_id. The function shows that the id is generate from a sha256 of a 32 bytes variable TAG, while i found that TAGs variables are defined as const, so, why the contract id would become different with the same arguments and the same codes? Or is there an way to generate a deterministic contract id with the same codes/arguments?

@dr-orlovsky
Copy link
Member

No, it is not possible. Each contract is unique - at least as long as it contains a timestamp (which includes milliseconds).

@oneforalone
Copy link
Author

I figure it out that RGB20 contract id is based on fungible field which is a Confined<BTreeMap<u16, Confined<HashMap<BuilderSeal<Seal>, RevealedValue, RandomState>, 1, U8>, Global>, ZERO, U8> type, and there's RandomState in it, thus, there's no way to make generate a deterministic contract id. And if the RandomState is removed or deterministic, then the blind seal would be meaningless, am I right?

@dr-orlovsky
Copy link
Member

No, RandomState is the Rust thing, which has nothing to do with RGB or indeterminism. It is used by the BTreeMap as an allocator.

However, inside RevealedValue there is an automatically generated blinding factor, and you are right, that makes the contract id different each time. And there is no way to remove it. However, this is not the only reason: even if it is removed, you will have different contract ids due to different timestamps.

Why do you need a deterministic contract generation?

@oneforalone
Copy link
Author

Why do you need a deterministic contract generation?

Cause in my point of view, contract id should be the same if and only if the contract contents is the same. I mean, it's just a hash of the contract content.

Actually, i tried to set Timestamp to a constant, and for the RevealedValue, yeah, there's a blind factor which is a secp256k1_zkp::SecretKey, and i do set this argument to a constant with a fixed timestamp. The contract id still changes. Am i missing something?

@dr-orlovsky
Copy link
Member

If you are using current master/beta v0.11 there is also a thing called AssetTag which is there for Liquid compatibility.

Anyway, can you share your code so I can check how exactly you are doing that?

@oneforalone
Copy link
Author

If you are using current master/beta v0.11 there is also a thing called AssetTag which is there for Liquid compatibility.

I'm still on version 0.10.2, not using AssetTag attribute.

Anyway, can you share your code so I can check how exactly you are doing that?
Okay, just want to get a fixed contract id with constant arguments. Here is my codes:

    let name = "USDT";
    let decimal = Precision::CentiMicro; // Decimal: 8
    let desc = "USD Tether Token";
    let spec = DivisibleAssetSpec::with("RGB20", name, decimal, Some(desc)).unwrap();
    let terms = RicardianContract::default();
    let contract_data = ContractData { terms, media: None };
    // let created = Timestamp::now();
    let ts = 1700755200;
    let strict_value = StrictVal::from(ts);
    let created = Timestamp::from_strict_val_unchecked(&strict_value);
    let txid = "0018dc9fff99382ac228a6cbcbdddb0989329d85d95c1e354b74a488da324516";
    let vout_index = 1;
    let beneficiary = Outpoint::new(Txid::from_hex(txid).unwrap(), vout_index);

    const ISSUE: u64 = 1_000_000_000;

    let contract = ContractBuilder::with(rgb20(), nia_schema(), nia_rgb20())
        .expect("schema fails to implement RGB20 interface")
        .set_chain(Chain::Testnet3)
        .add_global_state("spec", spec)
        .expect("invalid nominal")
        .add_global_state("created", created)
        .expect("invalid creation date")
        .add_global_state("issuedSupply", Amount::from(ISSUE))
        .expect("invalid issued supply")
        .add_global_state("data", contract_data)
        .expect("invalid contract text")
        .add_fungible_state("assetOwner", beneficiary, ISSUE)
        .expect("invalid asset amount")

        .issue_contract()
        .expect("contract doesn't fit schema requirements");

    let contract_id = contract.contract_id();
    println!("{contract_id}");

Also, i've replaced let state = Reveledalue::new(value, &mut thread_rng()); in rgb-std-0.10.9/src/interface/builder.rs line 445 to:

                let sk_str = "01010101010101010001020304050607ffff0000ffff00006363636363636363";
                let sk = secp256k1_zkp::SecretKey::from_str(sk_str).unwrap();
                let state = RevealedValue::with(value, sk);

However, got an error with "use of undeclared crate or module secp256k1_zkp", but in the cargo.toml file, i do declare secp256k1_zkp with secp256k1-zkp = { version = "0.9.2", features = ["rand", "rand-std", "global-context",] }, that's very wired.

@dr-orlovsky
Copy link
Member

You need to use it in the code as secp256k1zkp::SecretKey...

@dr-orlovsky dr-orlovsky changed the title Is possible to generate a deterministic contract id with the same arguments? Provide an API for deterministic contract generation Nov 30, 2023
@dr-orlovsky dr-orlovsky self-assigned this Nov 30, 2023
@dr-orlovsky dr-orlovsky added this to the v0.11.0 milestone Nov 30, 2023
@dr-orlovsky dr-orlovsky added the enhancement New feature or request label Nov 30, 2023
@dr-orlovsky
Copy link
Member

@oneforalone I agree with your arguments and have added a convenient API for deterministic contract generation into the v0.11 roadmap

@fedsten
Copy link
Member

fedsten commented Dec 1, 2023

Not sure I understood, what would be exactly the use case of having deterministic contract generation?

@oneforalone
Copy link
Author

The simplest case is that we can verify a contract if we know construction arguments of the contract.

@dr-orlovsky
Copy link
Member

With v0.11 I tried to address ability to deterministically generate contract and state transitions (important for Lightning, coinjoins, atomic swap protocols etc). Let's use this issue as a tracking for the matter.

To generate contract or a state transition in a deterministic way, one has to do the following:

  1. Provide custom asset tags - this is needed only during contract issuing and not for state transitions/transfers. Use ContractBuilder::set_asset_tag API to provide this information.
  2. Provide explicit blinding information for single-use seal definitions when using OperationBuilder::add_*_state. This can be done by creating a beneficiary using BlindSeal::with_blinding (for genesis and blind-utxos) or BlindSeal::with_blinded_vout (for address-based payments).
  3. Provide explicit blinding information for fungible state (used in Pedersen commitments). This can be done by calling ContractBuilder::add_owned_state_raw (or the same-named method for TransitionBuilder)
  4. Instead of using Runtime::pay or Runtime::construct_psbt methods from rgb-runtime crate use Runtime::pay_deterministic/construct_psbt_deterministic, providing closures generating blinding factors for both pedersen commitments and seal definitions in a deterministic way (this part is WIP, right now we have a low-level APIs from Inventory::compose_deterministic which still has to be exposed at Runtime level)
  5. Provide entropy value for multi-protocol commitments during the anchor creation. It should be also done using the same APIs from pt.4, but this is pending (we have low-level Psbt::dbc_set_entropy, but it is not yet exposed via PSBT construction API at the runtime level)

@zoedberg
Copy link
Contributor

@dr-orlovsky what's missing to complete this? I see this isn't listed in the rgb 0.11 board (https://github.com/orgs/RGB-WG/projects/17), do you still plan to do it in a 0.11 release? I think this is useful to have, to do some tests

@dr-orlovsky
Copy link
Member

I think tests are missing: I am not 100% sure we have all required APIs in place, but hard to point at specific one which can be missed

@zoedberg
Copy link
Contributor

I can give a look at this and let you know if something's missing or if everything's in place

@zoedberg
Copy link
Contributor

I've checked this using v0.11.0-beta5 and it seems the possibility to add global state in a deterministic way is missing, therefore I've opened a PR for this #190.

I think we can close this as soon that PR gets merged.

I've added a test (RGB-WG/rgb-schemata#41) so that with beta 6 we can be sure this still works.

@dr-orlovsky dr-orlovsky linked a pull request Apr 16, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
4 participants