1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Toy off-chain process to create an amoeba and perform mitosis on it

use crate::rpc::fetch_storage;

use std::{thread::sleep, time::Duration};

use jsonrpsee::{core::client::ClientT, http_client::HttpClient, rpc_params};
use parity_scale_codec::Encode;
use runtime::{
    amoeba::{AmoebaCreation, AmoebaDetails, AmoebaMitosis},
    OuterConstraintChecker, OuterVerifier,
};
use sp_runtime::traits::{BlakeTwo256, Hash};
use tuxedo_core::{
    types::{Input, Output, OutputRef, Transaction},
    verifier::UpForGrabs,
    ConstraintChecker,
};

pub async fn amoeba_demo(parachain: bool, client: &HttpClient) -> anyhow::Result<()> {
    if parachain {
        amoeba_demo_helper::<crate::ParachainConstraintChecker>(client).await
    } else {
        amoeba_demo_helper::<crate::OuterConstraintChecker>(client).await
    }
}

pub async fn amoeba_demo_helper<Checker: ConstraintChecker + From<OuterConstraintChecker>>(
    client: &HttpClient,
) -> anyhow::Result<()> {
    // Construct a simple amoeba spawning transaction (no signature required)
    let eve = AmoebaDetails {
        generation: 0,
        four_bytes: *b"eve_",
    };
    let spawn_tx: Transaction<OuterVerifier, Checker> = Transaction {
        inputs: Vec::new(),
        peeks: Vec::new(),
        outputs: vec![Output {
            payload: eve.into(),
            verifier: UpForGrabs.into(),
        }],
        checker: OuterConstraintChecker::AmoebaCreation(AmoebaCreation).into(),
    };

    // Calculate the OutputRef which also serves as the storage location
    let eve_ref = OutputRef {
        tx_hash: <BlakeTwo256 as Hash>::hash_of(&spawn_tx.encode()),
        index: 0,
    };

    // Send the transaction
    let spawn_hex = hex::encode(spawn_tx.encode());
    let params = rpc_params![spawn_hex];
    let spawn_response: Result<String, _> = client.request("author_submitExtrinsic", params).await;
    println!("Node's response to spawn transaction: {:?}", spawn_response);

    // Wait a few seconds to make sure a block has been authored.
    sleep(Duration::from_secs(3));

    // Check that the amoeba is in storage and print its details
    let eve_from_storage: AmoebaDetails = fetch_storage::<OuterVerifier>(&eve_ref, client)
        .await?
        .payload
        .extract()?;
    println!("Eve Amoeba retrieved from storage: {:?}", eve_from_storage);

    // Create a mitosis transaction on the Eve amoeba
    let cain = AmoebaDetails {
        generation: 1,
        four_bytes: *b"cain",
    };
    let able = AmoebaDetails {
        generation: 1,
        four_bytes: *b"able",
    };
    let mitosis_tx: Transaction<OuterVerifier, Checker> = Transaction {
        inputs: vec![Input {
            output_ref: eve_ref,
            redeemer: Default::default(),
        }],
        peeks: Vec::new(),
        outputs: vec![
            Output {
                payload: cain.into(),
                verifier: UpForGrabs.into(),
            },
            Output {
                payload: able.into(),
                verifier: UpForGrabs.into(),
            },
        ],
        checker: OuterConstraintChecker::AmoebaMitosis(AmoebaMitosis).into(),
    };

    // Calculate the two OutputRefs for the daughters
    let cain_ref = OutputRef {
        tx_hash: <BlakeTwo256 as Hash>::hash_of(&mitosis_tx.encode()),
        index: 0,
    };
    let able_ref = OutputRef {
        tx_hash: <BlakeTwo256 as Hash>::hash_of(&mitosis_tx.encode()),
        index: 1,
    };

    // Send the mitosis transaction
    let mitosis_hex = hex::encode(mitosis_tx.encode());
    let params = rpc_params![mitosis_hex];
    let mitosis_response: Result<String, _> =
        client.request("author_submitExtrinsic", params).await;
    println!(
        "Node's response to mitosis transaction: {:?}",
        mitosis_response
    );

    // Wait a few seconds to make sure a block has been authored.
    sleep(Duration::from_secs(3));

    // Check that the daughters are in storage and print their details
    let cain_from_storage: AmoebaDetails = fetch_storage::<OuterVerifier>(&cain_ref, client)
        .await?
        .payload
        .extract()?;
    println!(
        "Cain Amoeba retrieved from storage: {:?}",
        cain_from_storage
    );
    let able_from_storage: AmoebaDetails = fetch_storage::<OuterVerifier>(&able_ref, client)
        .await?
        .payload
        .extract()?;
    println!(
        "Able Amoeba retrieved from storage: {:?}",
        able_from_storage
    );

    Ok(())
}