diff --git a/Cargo.lock b/Cargo.lock index ae7542d8..021fcdef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4865,6 +4865,7 @@ dependencies = [ "gadget-sdk", "indexmap 2.6.0", "itertools 0.13.0", + "parking_lot 0.12.3", "proc-macro2", "quote", "serde_json", @@ -12276,8 +12277,7 @@ dependencies = [ [[package]] name = "tangle-subxt" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cad370e154d2297ed658b566b3ed5320362dfebdcc0f1f38f5194d85bf85f02" +source = "git+https://github.com/tangle-network/tangle#83f587fb4a720ac3936200abb568a346e5045277" dependencies = [ "parity-scale-codec", "scale-info", diff --git a/Cargo.toml b/Cargo.toml index 1fbef32e..8e5fe23a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ cargo-tangle = { path = "./cli", version = "0.3.2" } cargo_metadata = { version = "0.18.1" } # Tangle-related dependencies -tangle-subxt = { version = "0.7.0", default-features = false } +tangle-subxt = { git = "https://github.com/tangle-network/tangle", default-features = false } subxt-signer = { version = "0.37.0", default-features = false } subxt = { version = "0.37.0", default-features = false } subxt-core = { version = "0.37.0", default-features = false } diff --git a/README.md b/README.md index bc7b08a7..ccc05a50 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ passing `--clean` as an argument to reset the chain and any keys. Then, you can run: ```bash -cargo test --package blueprint-test-utils tests_standard::test_externalities_gadget_starts -- --nocapture +cargo test --package blueprint-test-utils test_incredible_squaring -- --nocapture ``` Since testing is in beta stage, each time the blueprint is run, you diff --git a/blueprint-manager/src/executor/event_handler.rs b/blueprint-manager/src/executor/event_handler.rs index a12e582d..77d9c163 100644 --- a/blueprint-manager/src/executor/event_handler.rs +++ b/blueprint-manager/src/executor/event_handler.rs @@ -266,11 +266,10 @@ pub(crate) async fn handle_tangle_event( // Ensure that we have a test fetcher if we are in test mode if gadget_manager_opts.test_mode && test_fetcher_idx.is_none() { - warn!( + return Err(color_eyre::Report::msg(format!( "No testing fetcher found for blueprint `{}` despite operating in TEST MODE", blueprint.name, - ); - continue; + ))); } // Ensure that we have only one fetcher if we are in test mode diff --git a/blueprint-metadata/src/lib.rs b/blueprint-metadata/src/lib.rs index 60efe587..f9d9fd5b 100644 --- a/blueprint-metadata/src/lib.rs +++ b/blueprint-metadata/src/lib.rs @@ -316,22 +316,44 @@ fn generate_gadget(package: &Package) -> Gadget<'static> { let root = Path::new(&root) .canonicalize() .expect("Failed to canonicalize root dir"); - let Some(gadget) = package.metadata.get("gadget") else { + let mut sources = vec![]; + if let Some(gadget) = package.metadata.get("gadget") { + let gadget: Gadget<'static> = + serde_json::from_value(gadget.clone()).expect("Failed to deserialize gadget."); + if let Gadget::Native(NativeGadget { sources: fetchers }) = gadget { + sources.extend(fetchers); + } else { + panic!("Currently unsupported gadget type has been parsed") + } + } else { eprintln!("No gadget metadata found in the Cargo.toml."); eprintln!("For more information, see:"); eprintln!(""); - // For now, we just return an empty gadget - return Gadget::Native(NativeGadget { - sources: vec![GadgetSource { - fetcher: GadgetSourceFetcher::Testing(TestFetcher { - cargo_package: package.name.clone().into(), - cargo_bin: "main".into(), - base_path: format!("{}", root.display()).into(), - }), - }], - }); }; - serde_json::from_value(gadget.clone()).expect("Failed to deserialize gadget.") + + let has_test_fetcher = sources.iter().any(|fetcher| { + matches!( + fetcher, + GadgetSource { + fetcher: GadgetSourceFetcher::Testing(..) + } + ) + }); + + if !has_test_fetcher { + println!("Adding test fetcher since none exists"); + sources.push(GadgetSource { + fetcher: GadgetSourceFetcher::Testing(TestFetcher { + cargo_package: package.name.clone().into(), + cargo_bin: "main".into(), + base_path: format!("{}", root.display()).into(), + }), + }) + } + + assert_ne!(sources.len(), 0, "No sources found for the gadget"); + + Gadget::Native(NativeGadget { sources }) } fn generate_rustdoc() -> Crate { diff --git a/blueprint-test-utils/src/tangle/mod.rs b/blueprint-test-utils/src/tangle/mod.rs index 81c715de..8a1edc03 100644 --- a/blueprint-test-utils/src/tangle/mod.rs +++ b/blueprint-test-utils/src/tangle/mod.rs @@ -117,7 +117,8 @@ macro_rules! test_tangle_blueprint { $T:tt, $job_id:tt, [$($inputs:expr),*], - [$($expected_output:expr),*] + [$($expected_output:expr),*], + $call_id:expr, ) => { ::blueprint_test_utils::tangle_blueprint_test_template!( $N, @@ -138,6 +139,7 @@ macro_rules! test_tangle_blueprint { service_id, $job_id as ::blueprint_test_utils::Job, job_args, + $call_id, ) .await .expect("Failed to submit job"); @@ -174,7 +176,8 @@ macro_rules! test_tangle_blueprint { $job_id:tt, [$($input:expr),*], [$($expected_output:expr),*] + $call_id:expr, ) => { - ::blueprint_test_utils::test_tangle_blueprint!($N, $N, $job_id, [$($input),+], [$($expected_output),+]); + ::blueprint_test_utils::test_tangle_blueprint!($N, $N, $job_id, [$($input),+], [$($expected_output),+], $call_id); }; } diff --git a/blueprint-test-utils/src/tangle/transactions.rs b/blueprint-test-utils/src/tangle/transactions.rs index 41ae5786..76a710c1 100644 --- a/blueprint-test-utils/src/tangle/transactions.rs +++ b/blueprint-test-utils/src/tangle/transactions.rs @@ -19,6 +19,8 @@ use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::{Jo use subxt::tx::TxProgress; use gadget_sdk::clients::tangle::runtime::TangleConfig; use gadget_sdk::subxt_core::tx::signer::Signer; +use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::Asset; +use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::calls::types::request::{Assets, PaymentAsset}; use crate::TestClient; /// Deploy a new MBSM revision and returns the result. @@ -138,6 +140,7 @@ pub async fn submit_job( service_id: u64, job_id: Job, job_params: Args, + call_id: u64, ) -> Result> { let call = api::tx().services().call(service_id, job_id, job_params); let events = client @@ -153,6 +156,7 @@ pub async fn submit_job( if job_called.service_id == service_id && job_called.job == job_id && user.account_id() == job_called.caller + && job_called.call_id == call_id { return Ok(job_called); } @@ -175,8 +179,9 @@ pub async fn request_service( test_nodes.clone(), test_nodes, Default::default(), - vec![0], + Assets::from([0]), 1000, + PaymentAsset::from(Asset::Custom(0)), value, ); let res = client diff --git a/blueprint-test-utils/tnt-core/MasterBlueprintServiceManager.hex b/blueprint-test-utils/tnt-core/MasterBlueprintServiceManager.hex index 2e3d5d3e..5af0510e 100644 --- a/blueprint-test-utils/tnt-core/MasterBlueprintServiceManager.hex +++ b/blueprint-test-utils/tnt-core/MasterBlueprintServiceManager.hex @@ -1 +1 @@ -0x608060405234801561001057600080fd5b506002805460ff191690556124b18061002a6000396000f3fe60806040526004361061019c5760003560e01c8063727391f2116100ec578063a4d91fe91161008a578063b89af90411610064578063b89af9041461047c578063b9315d3a1461048f578063c97008e0146104a2578063d547741f146104c257600080fd5b8063a4d91fe914610438578063a6a7853814610456578063a8f7c5ed1461046957600080fd5b80638e6f8c60116100c65780638e6f8c60146103c257806391d14854146103e2578063987ab9db14610402578063a217fddf1461042357600080fd5b8063727391f21461036d57806382a1ece414610380578063884673ac146103a057600080fd5b80632f2ff15d11610159578063410fdec811610133578063410fdec81461030f5780634984ee6b1461032f5780634efb4b8b146103425780635c975abb1461035557600080fd5b80632f2ff15d146102af57806333db3920146102cf57806336568abe146102ef57600080fd5b806301ffc9a7146101a15780630633da77146101d65780630d0dd399146101f85780631fb27b3414610230578063248a9ca314610250578063274ef0151461028f575b600080fd5b3480156101ad57600080fd5b506101c16101bc3660046116e7565b6104e2565b60405190151581526020015b60405180910390f35b3480156101e257600080fd5b506101f66101f136600461174d565b610519565b005b34801561020457600080fd5b50600054610218906001600160a01b031681565b6040516001600160a01b0390911681526020016101cd565b34801561023c57600080fd5b506101f661024b3660046117ac565b610640565b34801561025c57600080fd5b5061028161026b3660046117f9565b6000908152600160208190526040909120015490565b6040519081526020016101cd565b34801561029b57600080fd5b506102186102aa366004611812565b610745565b3480156102bb57600080fd5b506101f66102ca366004611845565b6107d9565b3480156102db57600080fd5b506101f66102ea3660046118ce565b610805565b3480156102fb57600080fd5b506101f661030a366004611845565b610926565b34801561031b57600080fd5b506101f661032a36600461194b565b61095e565b6101f661033d3660046119a8565b610a62565b6101f6610350366004611a71565b610b72565b34801561036157600080fd5b5060025460ff166101c1565b6101f661037b366004611b4e565b610c9d565b34801561038c57600080fd5b506101f661039b366004611bc4565b610da8565b3480156103ac57600080fd5b5061021860008051602061248583398151915281565b3480156103ce57600080fd5b506102186103dd366004611812565b610ed1565b3480156103ee57600080fd5b506101c16103fd366004611845565b610f20565b34801561040e57600080fd5b50600080516020612485833981519152610218565b34801561042f57600080fd5b50610281600081565b34801561044457600080fd5b506000546001600160a01b0316610218565b6101f66104643660046117ac565b610f4b565b6101f6610477366004611c5c565b611043565b6101f661048a366004611d34565b61116b565b6101f661049d366004611d8f565b611240565b3480156104ae57600080fd5b506101f66104bd3660046118ce565b611357565b3480156104ce57600080fd5b506101f66104dd366004611845565b611467565b60006001600160e01b03198216637965db0b60e01b148061051357506301ffc9a760e01b6001600160e01b03198316145b92915050565b336000805160206124858339815191521461056257336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b60405180910390fd5b61056a61148d565b600061058060036001600160401b0386166114b3565b604051630a24e8a960e41b81526001600160401b03851660048201526001600160a01b0384811660248301529192509082169063a24e8a9090604401600060405180830381600087803b1580156105d657600080fd5b505af11580156105ea573d6000803e3d6000fd5b50506040516001600160a01b03851681526001600160401b038087169350871691507f5267932e6c1b678e74efba1e4d6c8b3fd7504cf0fa8eea462efac2c590a21d56906020015b60405180910390a350505050565b336000805160206124858339815191521461068057336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61068861148d565b600061069e60036001600160401b0385166114b3565b60405163434698bb60e01b81529091506001600160a01b0382169063434698bb906106cd908590600401611f18565b600060405180830381600087803b1580156106e757600080fd5b505af11580156106fb573d6000803e3d6000fd5b50505050826001600160401b03167fde25c2b146db36cbc91715fdf29cb0eb556eed7678e0bf13563bf7050e8f0bbd836040516107389190611f18565b60405180910390a2505050565b60008061075c60036001600160401b0386166114b3565b6040516374ceeb5560e01b81526001600160401b03851660048201529091506001600160a01b038216906374ceeb55906024015b602060405180830381865afa1580156107ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d19190611f2b565b949350505050565b600082815260016020819052604090912001546107f5816114c6565b6107ff83836114d3565b50505050565b336000805160206124858339815191521461084557336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61084d61148d565b600061086360036001600160401b0389166114b3565b604051630af7d74360e01b81529091506001600160a01b03821690630af7d7439061089a9089908990899089908990600401611f48565b600060405180830381600087803b1580156108b457600080fd5b505af11580156108c8573d6000803e3d6000fd5b50505050856001600160401b0316876001600160401b03167f7d2ac4c1544e07516def74ce3ada12ff791868ed07d6da82694ae2c0342c8371878787876040516109159493929190611f82565b60405180910390a350505050505050565b6001600160a01b038116331461094f5760405163334bd91960e11b815260040160405180910390fd5b610959828261154c565b505050565b336000805160206124858339815191521461099e57336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b6109a661148d565b60006109bc60036001600160401b0386166114b3565b60405163410e3df160e11b81529091506001600160a01b0382169063821c7be2906109ed9086908690600401611fac565b600060405180830381600087803b158015610a0757600080fd5b505af1158015610a1b573d6000803e3d6000fd5b50505050816001600160401b0316846001600160401b03167f4ca48d7cb411035a931da7a686ea77bc413069de12d844c47daf9242b765cba4856040516106329190611f18565b3360008051602061248583398151915214610aa257336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610aaa61148d565b6000610ac060036001600160401b0389166114b3565b604051639838caa360e01b81529091506001600160a01b03821690639838caa390610af79089908990899089908990600401611fd7565b600060405180830381600087803b158015610b1157600080fd5b505af1158015610b25573d6000803e3d6000fd5b50506040805160ff891681526001600160401b038881166020830152808b1694508b1692507fa9aaaef624d196d961d053fc29d4331e5cb45d62195d99814d29a94f46fa9d4b9101610915565b3360008051602061248583398151915214610bb257336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610bba61148d565b6000610bd060036001600160401b038d166114b3565b6040516332e72cfd60e11b81529091506001600160a01b038216906365ce59fa90610c0f908d908d908d908d908d908d908d908d908d90600401612061565b600060405180830381600087803b158015610c2957600080fd5b505af1158015610c3d573d6000803e3d6000fd5b50506040516001600160401b0385811682526001600160a01b038d169350808e1692508e16907f43200f1363ce7ac3780a4c2c5835bf74800937ca5cbc69c4f4d666cf92b0c54c9060200160405180910390a45050505050505050505050565b3360008051602061248583398151915214610cdd57336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610ce561148d565b6000610cfb60036001600160401b0387166114b3565b604051634e82087760e11b81529091506001600160a01b03821690639d0410ee90610d2e90879087908790600401612136565b600060405180830381600087803b158015610d4857600080fd5b505af1158015610d5c573d6000803e3d6000fd5b50505050846001600160401b03167f7814301100cb38a35027dd63a29aa14c3f73188f15cf9f027655257c45016e8785604051610d999190611f18565b60405180910390a25050505050565b3360008051602061248583398151915214610de857336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610df061148d565b6000610e0660036001600160401b038a166114b3565b604051636bef5a4160e11b81529091506001600160a01b0382169063d7deb48290610e3f908a908a908a908a908a908a90600401612166565b600060405180830381600087803b158015610e5957600080fd5b505af1158015610e6d573d6000803e3d6000fd5b5050604080516001600160a01b03891681526001600160401b038681166020830152808b1694508b811693508c16917f93927390d124732c66289c6e22370514ddd612a9cc6bff5671cbf2cbc15ddfe3910160405180910390a45050505050505050565b600080610ee860036001600160401b0386166114b3565b60405163052d37d360e21b81526001600160401b03851660048201529091506001600160a01b038216906314b4df4c90602401610790565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3360008051602061248583398151915214610f8b57336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610f9361148d565b6000610fa960036001600160401b0385166114b3565b60405163fe0dd37160e01b81529091506001600160a01b0382169063fe0dd37190610fd8908590600401611f18565b600060405180830381600087803b158015610ff257600080fd5b505af1158015611006573d6000803e3d6000fd5b50505050826001600160401b03167febc442018e78570634a88dbac83d4677ae1a5cf8491fb0fc166a7306ba1ff051836040516107389190611f18565b336000805160206124858339815191521461108357336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61108b61148d565b60006110a160036001600160401b038c166114b3565b604051631be14b3160e11b81529091506001600160a01b038216906337c29662906110de908c908c908c908c908c908c908c908c906004016121b6565b600060405180830381600087803b1580156110f857600080fd5b505af115801561110c573d6000803e3d6000fd5b50505050886001600160401b03168a6001600160401b03167f08e18861659838cad8b04f4687aca1dfb93336e750acf5c3699637ed8ca4c27a8a8a8a60405161115793929190612222565b60405180910390a350505050505050505050565b33600080516020612485833981519152146111ab57336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b6111b361148d565b6111d96001600160401b0384166111d06040840160208501612256565b600391906115b9565b506111ef60066001600160401b038516846115b9565b50826001600160401b0316826001600160a01b03167f278018182b7c51e2da72c1f465c26c12d9606099af0f08db420378344b352223836040516112339190612287565b60405180910390a3505050565b336000805160206124858339815191521461128057336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61128861148d565b600061129e60036001600160401b0387166114b3565b60405163bb43abd960e01b81529091506001600160a01b0382169063bb43abd9906112d19087908790879060040161242a565b600060405180830381600087803b1580156112eb57600080fd5b505af11580156112ff573d6000803e3d6000fd5b50505050826001600160401b0316856001600160401b03167f219c2fdfbe4f111dda584eefbcb4eb2370cec850e2a79e4fed3a8f708006e7a9868560405161134892919061245f565b60405180910390a35050505050565b336000805160206124858339815191521461139757336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61139f61148d565b60006113b560036001600160401b0389166114b3565b60405163e926cbd160e01b81529091506001600160a01b0382169063e926cbd1906113ec9089908990899089908990600401611f48565b600060405180830381600087803b15801561140657600080fd5b505af115801561141a573d6000803e3d6000fd5b50505050856001600160401b0316876001600160401b03167f0145a8acdb5e19e431ea924e2c8997b01f0869cad2a2c6927c8645a5938cf0c3878787876040516109159493929190611f82565b60008281526001602081905260409091200154611483816114c6565b6107ff838361154c565b60025460ff16156114b15760405163d93c066560e01b815260040160405180910390fd5b565b60006114bf83836115cf565b9392505050565b6114d08133611616565b50565b60006114df8383610f20565b6115445760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a4506001610513565b506000610513565b60006115588383610f20565b156115445760008381526001602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610513565b60006107d184846001600160a01b038516611653565b6000818152600283016020526040812054801580156115f557506115f38484611670565b155b156114bf5760405163015ab34360e11b815260048101849052602401610559565b6116208282610f20565b61164f5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610559565b5050565b600082815260028401602052604081208290556107d1848461167c565b60006114bf8383611688565b60006114bf83836116a0565b600081815260018301602052604081205415156114bf565b600081815260018301602052604081205461154457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610513565b6000602082840312156116f957600080fd5b81356001600160e01b0319811681146114bf57600080fd5b80356001600160401b038116811461172857600080fd5b919050565b6001600160a01b03811681146114d057600080fd5b80356117288161172d565b60008060006060848603121561176257600080fd5b61176b84611711565b925061177960208501611711565b915060408401356117898161172d565b809150509250925092565b600060c082840312156117a657600080fd5b50919050565b600080604083850312156117bf57600080fd5b6117c883611711565b915060208301356001600160401b038111156117e357600080fd5b6117ef85828601611794565b9150509250929050565b60006020828403121561180b57600080fd5b5035919050565b6000806040838503121561182557600080fd5b61182e83611711565b915061183c60208401611711565b90509250929050565b6000806040838503121561185857600080fd5b82359150602083013561186a8161172d565b809150509250929050565b60008083601f84011261188757600080fd5b5081356001600160401b0381111561189e57600080fd5b6020830191508360208285010111156118b657600080fd5b9250929050565b803560ff8116811461172857600080fd5b60008060008060008060a087890312156118e757600080fd5b6118f087611711565b95506118fe60208801611711565b945060408701356001600160401b0381111561191957600080fd5b61192589828a01611875565b90955093506119389050606088016118bd565b9150608087013590509295509295509295565b60008060006060848603121561196057600080fd5b61196984611711565b925060208401356001600160401b0381111561198457600080fd5b61199086828701611794565b92505061199f60408501611711565b90509250925092565b60008060008060008060a087890312156119c157600080fd5b6119ca87611711565b95506119d860208801611711565b94506119e6604088016118bd565b93506119f460608801611711565b925060808701356001600160401b03811115611a0f57600080fd5b611a1b89828a01611875565b979a9699509497509295939492505050565b60008083601f840112611a3f57600080fd5b5081356001600160401b03811115611a5657600080fd5b6020830191508360208260051b85010111156118b657600080fd5b60008060008060008060008060008060e08b8d031215611a9057600080fd5b611a998b611711565b9950611aa760208c01611711565b985060408b0135611ab78161172d565b975060608b01356001600160401b0380821115611ad357600080fd5b611adf8e838f01611a2d565b909950975060808d0135915080821115611af857600080fd5b611b048e838f01611875565b909750955060a08d0135915080821115611b1d57600080fd5b50611b2a8d828e01611a2d565b9094509250611b3d905060c08c01611711565b90509295989b9194979a5092959850565b60008060008060608587031215611b6457600080fd5b611b6d85611711565b935060208501356001600160401b0380821115611b8957600080fd5b611b9588838901611794565b94506040870135915080821115611bab57600080fd5b50611bb887828801611875565b95989497509550505050565b600080600080600080600060c0888a031215611bdf57600080fd5b611be888611711565b9650611bf660208901611711565b9550611c0460408901611711565b94506060880135611c148161172d565b935060808801356001600160401b03811115611c2f57600080fd5b611c3b8a828b01611a2d565b9094509250611c4e905060a08901611711565b905092959891949750929550565b600080600080600080600080600060e08a8c031215611c7a57600080fd5b611c838a611711565b9850611c9160208b01611711565b9750611c9f60408b016118bd565b9650611cad60608b01611711565b955060808a01356001600160401b0380821115611cc957600080fd5b611cd58d838e01611794565b965060a08c0135915080821115611ceb57600080fd5b611cf78d838e01611875565b909650945060c08c0135915080821115611d1057600080fd5b50611d1d8c828d01611875565b915080935050809150509295985092959850929598565b600080600060608486031215611d4957600080fd5b611d5284611711565b92506020840135611d628161172d565b915060408401356001600160401b03811115611d7d57600080fd5b84016060818703121561178957600080fd5b60008060008060808587031215611da557600080fd5b611dae85611711565b935060208501356001600160401b03811115611dc957600080fd5b611dd587828801611794565b935050611de460408601611711565b9150611df2606086016118bd565b905092959194509250565b6001600160a01b0392831681529116602082015260400190565b6000808335601e19843603018112611e2e57600080fd5b83016020810192503590506001600160401b03811115611e4d57600080fd5b8036038213156118b657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000611e918283611e17565b60c08552611ea360c086018284611e5c565b9150506001600160401b0380611ebb60208601611711565b16602086015280611ece60408601611711565b16604086015280611ee160608601611711565b16606086015280611ef460808601611711565b16608086015280611f0760a08601611711565b1660a0860152508091505092915050565b6020815260006114bf6020830184611e85565b600060208284031215611f3d57600080fd5b81516114bf8161172d565b6001600160401b0386168152608060208201526000611f6b608083018688611e5c565b60ff94909416604083015250606001529392505050565b606081526000611f96606083018688611e5c565b60ff949094166020830152506040015292915050565b604081526000611fbf6040830185611e85565b90506001600160401b03831660208301529392505050565b60006001600160401b03808816835260ff871660208401528086166040840152506080606083015261200d608083018486611e5c565b979650505050505050565b8183526000602080850194508260005b8581101561205657813561203b8161172d565b6001600160a01b031687529582019590820190600101612028565b509495945050505050565b6001600160401b038a1681526001600160a01b038916602082015260c0604082018190528101879052600060e0600589901b830181019083018a835b8b8110156120e55785840360df190183528135368e900360be190181126120c357600080fd5b6120cf858f8301611e85565b945050602092830192919091019060010161209d565b50505082810360608401526120fb81888a611e5c565b90508281036080840152612110818688612018565b91505061212860a08301846001600160401b03169052565b9a9950505050505050505050565b6040815260006121496040830186611e85565b828103602084015261215c818587611e5c565b9695505050505050565b60006001600160401b038089168352808816602084015260018060a01b038716604084015260a060608401526121a060a084018688612018565b9150808416608084015250979650505050505050565b60006001600160401b03808b16835260ff8a16602084015280891660408401525060c060608301526121eb60c0830188611e85565b82810360808401526121fe818789611e5c565b905082810360a0840152612213818587611e5c565b9b9a5050505050505050505050565b60ff841681526001600160401b038316602082015260606040820152600061224d6060830184611e85565b95945050505050565b60006020828403121561226857600080fd5b81356114bf8161172d565b803563ffffffff8116811461172857600080fd5b602081526000823560fe198436030181126122a157600080fd5b6060602084015283016122b48180611e17565b6101008060808701526122cc61018087018385611e5c565b92506122db6020850185611e17565b9250607f19808886030160a08901526122f5858584611e5c565b94506123046040870187611e17565b94509150808886030160c089015261231d858584611e5c565b945061232c6060870187611e17565b94509150808886030160e0890152612345858584611e5c565b94506123546080870187611e17565b9450915080888603018389015261236c858584611e5c565b945061237b60a0870187611e17565b945092508088860301610120890152612395858585611e5c565b94506123a460c0870187611e17565b9450925080888603016101408901526123be858585611e5c565b94506123cd60e0870187611e17565b9650935080888603016101608901525050506123ea828483611e5c565b925050506123fa60208501611742565b6001600160a01b03811660408501525061241660408501612273565b63ffffffff81166060850152509392505050565b60608152600061243d6060830186611e85565b90506001600160401b038416602083015260ff83166040830152949350505050565b6040815260006124726040830185611e85565b905060ff83166020830152939250505056fe0000000000000000000000001111111111111111111111111111111111111111a164736f6c6343000814000a +0x608060405234801561001057600080fd5b506002805460ff191690556125968061002a6000396000f3fe60806040526004361061019c5760003560e01c806382a1ece4116100ec578063a6a785381161008a578063b9315d3a11610064578063b9315d3a1461047c578063c97008e01461048f578063d547741f146104af578063f9e13845146104cf57600080fd5b8063a6a7853814610443578063a8f7c5ed14610456578063b89af9041461046957600080fd5b806391d14854116100c657806391d14854146103cf578063987ab9db146103ef578063a217fddf14610410578063a4d91fe91461042557600080fd5b806382a1ece41461036d578063884673ac1461038d5780638e6f8c60146103af57600080fd5b80632f2ff15d11610159578063410fdec811610133578063410fdec81461030f5780634984ee6b1461032f5780635c975abb14610342578063727391f21461035a57600080fd5b80632f2ff15d146102af57806333db3920146102cf57806336568abe146102ef57600080fd5b806301ffc9a7146101a15780630633da77146101d65780630d0dd399146101f85780631fb27b3414610230578063248a9ca314610250578063274ef0151461028f575b600080fd5b3480156101ad57600080fd5b506101c16101bc366004611707565b6104e2565b60405190151581526020015b60405180910390f35b3480156101e257600080fd5b506101f66101f136600461176d565b610519565b005b34801561020457600080fd5b50600054610218906001600160a01b031681565b6040516001600160a01b0390911681526020016101cd565b34801561023c57600080fd5b506101f661024b3660046117cc565b610640565b34801561025c57600080fd5b5061028161026b366004611819565b6000908152600160208190526040909120015490565b6040519081526020016101cd565b34801561029b57600080fd5b506102186102aa366004611832565b610745565b3480156102bb57600080fd5b506101f66102ca366004611865565b6107d9565b3480156102db57600080fd5b506101f66102ea3660046118ee565b610805565b3480156102fb57600080fd5b506101f661030a366004611865565b610926565b34801561031b57600080fd5b506101f661032a36600461196b565b61095e565b6101f661033d3660046119c8565b610a62565b34801561034e57600080fd5b5060025460ff166101c1565b6101f6610368366004611a4d565b610b72565b34801561037957600080fd5b506101f6610388366004611ac3565b610c7d565b34801561039957600080fd5b5061021860008051602061256a83398151915281565b3480156103bb57600080fd5b506102186103ca366004611832565b610da6565b3480156103db57600080fd5b506101c16103ea366004611865565b610df5565b3480156103fb57600080fd5b5060008051602061256a833981519152610218565b34801561041c57600080fd5b50610281600081565b34801561043157600080fd5b506000546001600160a01b0316610218565b6101f66104513660046117cc565b610e20565b6101f6610464366004611b8d565b610f18565b6101f6610477366004611c65565b611040565b6101f661048a366004611cc0565b611115565b34801561049b57600080fd5b506101f66104aa3660046118ee565b61122c565b3480156104bb57600080fd5b506101f66104ca366004611865565b61133c565b6101f66104dd366004611d2e565b611362565b60006001600160e01b03198216637965db0b60e01b148061051357506301ffc9a760e01b6001600160e01b03198316145b92915050565b3360008051602061256a83398151915214610562573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b60405180910390fd5b61056a6114ad565b600061058060036001600160401b0386166114d3565b604051630a24e8a960e41b81526001600160401b03851660048201526001600160a01b0384811660248301529192509082169063a24e8a9090604401600060405180830381600087803b1580156105d657600080fd5b505af11580156105ea573d6000803e3d6000fd5b50506040516001600160a01b03851681526001600160401b038087169350871691507f5267932e6c1b678e74efba1e4d6c8b3fd7504cf0fa8eea462efac2c590a21d56906020015b60405180910390a350505050565b3360008051602061256a83398151915214610680573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6106886114ad565b600061069e60036001600160401b0385166114d3565b60405163434698bb60e01b81529091506001600160a01b0382169063434698bb906106cd908590600401611e93565b600060405180830381600087803b1580156106e757600080fd5b505af11580156106fb573d6000803e3d6000fd5b50505050826001600160401b03167fde25c2b146db36cbc91715fdf29cb0eb556eed7678e0bf13563bf7050e8f0bbd836040516107389190611e93565b60405180910390a2505050565b60008061075c60036001600160401b0386166114d3565b6040516374ceeb5560e01b81526001600160401b03851660048201529091506001600160a01b038216906374ceeb55906024015b602060405180830381865afa1580156107ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d19190611ea6565b949350505050565b600082815260016020819052604090912001546107f5816114e6565b6107ff83836114f3565b50505050565b3360008051602061256a83398151915214610845573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b61084d6114ad565b600061086360036001600160401b0389166114d3565b604051630af7d74360e01b81529091506001600160a01b03821690630af7d7439061089a9089908990899089908990600401611ec3565b600060405180830381600087803b1580156108b457600080fd5b505af11580156108c8573d6000803e3d6000fd5b50505050856001600160401b0316876001600160401b03167f7d2ac4c1544e07516def74ce3ada12ff791868ed07d6da82694ae2c0342c8371878787876040516109159493929190611efd565b60405180910390a350505050505050565b6001600160a01b038116331461094f5760405163334bd91960e11b815260040160405180910390fd5b610959828261156c565b505050565b3360008051602061256a8339815191521461099e573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6109a66114ad565b60006109bc60036001600160401b0386166114d3565b60405163410e3df160e11b81529091506001600160a01b0382169063821c7be2906109ed9086908690600401611f27565b600060405180830381600087803b158015610a0757600080fd5b505af1158015610a1b573d6000803e3d6000fd5b50505050816001600160401b0316846001600160401b03167f4ca48d7cb411035a931da7a686ea77bc413069de12d844c47daf9242b765cba4856040516106329190611e93565b3360008051602061256a83398151915214610aa2573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610aaa6114ad565b6000610ac060036001600160401b0389166114d3565b604051639838caa360e01b81529091506001600160a01b03821690639838caa390610af79089908990899089908990600401611f52565b600060405180830381600087803b158015610b1157600080fd5b505af1158015610b25573d6000803e3d6000fd5b50506040805160ff891681526001600160401b038881166020830152808b1694508b1692507fa9aaaef624d196d961d053fc29d4331e5cb45d62195d99814d29a94f46fa9d4b9101610915565b3360008051602061256a83398151915214610bb2573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610bba6114ad565b6000610bd060036001600160401b0387166114d3565b604051634e82087760e11b81529091506001600160a01b03821690639d0410ee90610c0390879087908790600401611f93565b600060405180830381600087803b158015610c1d57600080fd5b505af1158015610c31573d6000803e3d6000fd5b50505050846001600160401b03167f7814301100cb38a35027dd63a29aa14c3f73188f15cf9f027655257c45016e8785604051610c6e9190611e93565b60405180910390a25050505050565b3360008051602061256a83398151915214610cbd573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610cc56114ad565b6000610cdb60036001600160401b038a166114d3565b604051636bef5a4160e11b81529091506001600160a01b0382169063d7deb48290610d14908a908a908a908a908a908a90600401611fc3565b600060405180830381600087803b158015610d2e57600080fd5b505af1158015610d42573d6000803e3d6000fd5b5050604080516001600160a01b03891681526001600160401b038681166020830152808b1694508b811693508c16917f93927390d124732c66289c6e22370514ddd612a9cc6bff5671cbf2cbc15ddfe3910160405180910390a45050505050505050565b600080610dbd60036001600160401b0386166114d3565b60405163052d37d360e21b81526001600160401b03851660048201529091506001600160a01b038216906314b4df4c90602401610790565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3360008051602061256a83398151915214610e60573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610e686114ad565b6000610e7e60036001600160401b0385166114d3565b60405163fe0dd37160e01b81529091506001600160a01b0382169063fe0dd37190610ead908590600401611e93565b600060405180830381600087803b158015610ec757600080fd5b505af1158015610edb573d6000803e3d6000fd5b50505050826001600160401b03167febc442018e78570634a88dbac83d4677ae1a5cf8491fb0fc166a7306ba1ff051836040516107389190611e93565b3360008051602061256a83398151915214610f58573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610f606114ad565b6000610f7660036001600160401b038c166114d3565b604051631be14b3160e11b81529091506001600160a01b038216906337c2966290610fb3908c908c908c908c908c908c908c908c9060040161204a565b600060405180830381600087803b158015610fcd57600080fd5b505af1158015610fe1573d6000803e3d6000fd5b50505050886001600160401b03168a6001600160401b03167f08e18861659838cad8b04f4687aca1dfb93336e750acf5c3699637ed8ca4c27a8a8a8a60405161102c939291906120b6565b60405180910390a350505050505050505050565b3360008051602061256a83398151915214611080573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6110886114ad565b6110ae6001600160401b0384166110a560408401602085016120ea565b600391906115d9565b506110c460066001600160401b038516846115d9565b50826001600160401b0316826001600160a01b03167f278018182b7c51e2da72c1f465c26c12d9606099af0f08db420378344b35222383604051611108919061211b565b60405180910390a3505050565b3360008051602061256a83398151915214611155573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b61115d6114ad565b600061117360036001600160401b0387166114d3565b60405163bb43abd960e01b81529091506001600160a01b0382169063bb43abd9906111a6908790879087906004016122be565b600060405180830381600087803b1580156111c057600080fd5b505af11580156111d4573d6000803e3d6000fd5b50505050826001600160401b0316856001600160401b03167f219c2fdfbe4f111dda584eefbcb4eb2370cec850e2a79e4fed3a8f708006e7a9868560405161121d9291906122f3565b60405180910390a35050505050565b3360008051602061256a8339815191521461126c573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6112746114ad565b600061128a60036001600160401b0389166114d3565b60405163e926cbd160e01b81529091506001600160a01b0382169063e926cbd1906112c19089908990899089908990600401611ec3565b600060405180830381600087803b1580156112db57600080fd5b505af11580156112ef573d6000803e3d6000fd5b50505050856001600160401b0316876001600160401b03167f0145a8acdb5e19e431ea924e2c8997b01f0869cad2a2c6927c8645a5938cf0c3878787876040516109159493929190611efd565b60008281526001602081905260409091200154611358816114e6565b6107ff838361156c565b3360008051602061256a833981519152146113a2573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6113aa6114ad565b60006113c060036001600160401b0385166114d3565b604051638b24806560e01b81529091506001600160a01b03821690638b248065906113ef90859060040161242d565b600060405180830381600087803b15801561140957600080fd5b505af115801561141d573d6000803e3d6000fd5b506114329250505060408301602084016120ea565b6001600160a01b03166114486020840184612523565b6001600160401b039081169085167f4def5362750954077cbc9dad1ab88058dd6d0ed894ba05f8f147a7a2fe204b2261148760c0870160a08801612523565b8660c0018761010001356040516114a09392919061253e565b60405180910390a4505050565b60025460ff16156114d15760405163d93c066560e01b815260040160405180910390fd5b565b60006114df83836115ef565b9392505050565b6114f08133611636565b50565b60006114ff8383610df5565b6115645760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a4506001610513565b506000610513565b60006115788383610df5565b156115645760008381526001602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610513565b60006107d184846001600160a01b038516611673565b60008181526002830160205260408120548015801561161557506116138484611690565b155b156114df5760405163015ab34360e11b815260048101849052602401610559565b6116408282610df5565b61166f5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610559565b5050565b600082815260028401602052604081208290556107d1848461169c565b60006114df83836116a8565b60006114df83836116c0565b600081815260018301602052604081205415156114df565b600081815260018301602052604081205461156457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610513565b60006020828403121561171957600080fd5b81356001600160e01b0319811681146114df57600080fd5b80356001600160401b038116811461174857600080fd5b919050565b6001600160a01b03811681146114f057600080fd5b80356117488161174d565b60008060006060848603121561178257600080fd5b61178b84611731565b925061179960208501611731565b915060408401356117a98161174d565b809150509250925092565b600060c082840312156117c657600080fd5b50919050565b600080604083850312156117df57600080fd5b6117e883611731565b915060208301356001600160401b0381111561180357600080fd5b61180f858286016117b4565b9150509250929050565b60006020828403121561182b57600080fd5b5035919050565b6000806040838503121561184557600080fd5b61184e83611731565b915061185c60208401611731565b90509250929050565b6000806040838503121561187857600080fd5b82359150602083013561188a8161174d565b809150509250929050565b60008083601f8401126118a757600080fd5b5081356001600160401b038111156118be57600080fd5b6020830191508360208285010111156118d657600080fd5b9250929050565b803560ff8116811461174857600080fd5b60008060008060008060a0878903121561190757600080fd5b61191087611731565b955061191e60208801611731565b945060408701356001600160401b0381111561193957600080fd5b61194589828a01611895565b90955093506119589050606088016118dd565b9150608087013590509295509295509295565b60008060006060848603121561198057600080fd5b61198984611731565b925060208401356001600160401b038111156119a457600080fd5b6119b0868287016117b4565b9250506119bf60408501611731565b90509250925092565b60008060008060008060a087890312156119e157600080fd5b6119ea87611731565b95506119f860208801611731565b9450611a06604088016118dd565b9350611a1460608801611731565b925060808701356001600160401b03811115611a2f57600080fd5b611a3b89828a01611895565b979a9699509497509295939492505050565b60008060008060608587031215611a6357600080fd5b611a6c85611731565b935060208501356001600160401b0380821115611a8857600080fd5b611a94888389016117b4565b94506040870135915080821115611aaa57600080fd5b50611ab787828801611895565b95989497509550505050565b600080600080600080600060c0888a031215611ade57600080fd5b611ae788611731565b9650611af560208901611731565b9550611b0360408901611731565b94506060880135611b138161174d565b935060808801356001600160401b0380821115611b2f57600080fd5b818a0191508a601f830112611b4357600080fd5b813581811115611b5257600080fd5b8b60208260051b8501011115611b6757600080fd5b602083019550809450505050611b7f60a08901611731565b905092959891949750929550565b600080600080600080600080600060e08a8c031215611bab57600080fd5b611bb48a611731565b9850611bc260208b01611731565b9750611bd060408b016118dd565b9650611bde60608b01611731565b955060808a01356001600160401b0380821115611bfa57600080fd5b611c068d838e016117b4565b965060a08c0135915080821115611c1c57600080fd5b611c288d838e01611895565b909650945060c08c0135915080821115611c4157600080fd5b50611c4e8c828d01611895565b915080935050809150509295985092959850929598565b600080600060608486031215611c7a57600080fd5b611c8384611731565b92506020840135611c938161174d565b915060408401356001600160401b03811115611cae57600080fd5b8401606081870312156117a957600080fd5b60008060008060808587031215611cd657600080fd5b611cdf85611731565b935060208501356001600160401b03811115611cfa57600080fd5b611d06878288016117b4565b935050611d1560408601611731565b9150611d23606086016118dd565b905092959194509250565b60008060408385031215611d4157600080fd5b611d4a83611731565b915060208301356001600160401b03811115611d6557600080fd5b8301610120818603121561188a57600080fd5b6001600160a01b0392831681529116602082015260400190565b6000808335601e19843603018112611da957600080fd5b83016020810192503590506001600160401b03811115611dc857600080fd5b8036038213156118d657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000611e0c8283611d92565b60c08552611e1e60c086018284611dd7565b9150506001600160401b0380611e3660208601611731565b16602086015280611e4960408601611731565b16604086015280611e5c60608601611731565b16606086015280611e6f60808601611731565b16608086015280611e8260a08601611731565b1660a0860152508091505092915050565b6020815260006114df6020830184611e00565b600060208284031215611eb857600080fd5b81516114df8161174d565b6001600160401b0386168152608060208201526000611ee6608083018688611dd7565b60ff94909416604083015250606001529392505050565b606081526000611f11606083018688611dd7565b60ff949094166020830152506040015292915050565b604081526000611f3a6040830185611e00565b90506001600160401b03831660208301529392505050565b60006001600160401b03808816835260ff8716602084015280861660408401525060806060830152611f88608083018486611dd7565b979650505050505050565b604081526000611fa66040830186611e00565b8281036020840152611fb9818587611dd7565b9695505050505050565b6001600160401b0387811682528681166020808401919091526001600160a01b03878116604085015260a06060850181905284018690526000928792909160c08601855b8981101561202e57853561201a8161174d565b831682529483019490830190600101612007565b5080955050505080851660808501525050979650505050505050565b60006001600160401b03808b16835260ff8a16602084015280891660408401525060c0606083015261207f60c0830188611e00565b8281036080840152612092818789611dd7565b905082810360a08401526120a7818587611dd7565b9b9a5050505050505050505050565b60ff841681526001600160401b03831660208201526060604082015260006120e16060830184611e00565b95945050505050565b6000602082840312156120fc57600080fd5b81356114df8161174d565b803563ffffffff8116811461174857600080fd5b602081526000823560fe1984360301811261213557600080fd5b6060602084015283016121488180611d92565b61010080608087015261216061018087018385611dd7565b925061216f6020850185611d92565b9250607f19808886030160a0890152612189858584611dd7565b94506121986040870187611d92565b94509150808886030160c08901526121b1858584611dd7565b94506121c06060870187611d92565b94509150808886030160e08901526121d9858584611dd7565b94506121e86080870187611d92565b94509150808886030183890152612200858584611dd7565b945061220f60a0870187611d92565b945092508088860301610120890152612229858585611dd7565b945061223860c0870187611d92565b945092508088860301610140890152612252858585611dd7565b945061226160e0870187611d92565b96509350808886030161016089015250505061227e828483611dd7565b9250505061228e60208501611762565b6001600160a01b0381166040850152506122aa60408501612107565b63ffffffff81166060850152509392505050565b6060815260006122d16060830186611e00565b90506001600160401b038416602083015260ff83166040830152949350505050565b6040815260006123066040830185611e00565b905060ff831660208301529392505050565b6000808335601e1984360301811261232f57600080fd5b83016020810192503590506001600160401b0381111561234e57600080fd5b8060051b36038213156118d657600080fd5b81835260006020808501808196508560051b81019150846000805b888110156123ba578385038a52823560be1989360301811261239b578283fd5b6123a7868a8301611e00565b9a87019a9550509185019160010161237b565b509298975050505050505050565b8183526000602080850194508260005b858110156124065781356123eb8161174d565b6001600160a01b0316875295820195908201906001016123d8565b509495945050505050565b80356002811061242057600080fd5b8252602090810135910152565b602081526001600160401b0361244283611731565b166020820152600061245660208401611762565b6001600160a01b0381166040840152506124736040840184612318565b61012080606086015261248b61014086018385612360565b925061249a6060870187611d92565b9250601f19808786030160808801526124b4858584611dd7565b94506124c36080890189612318565b94509150808786030160a0880152506124dd8484836123c8565b9350506124ec60a08701611731565b6001600160401b03811660c0870152915061250d60e0860160c08801612411565b6101008601358186015250508091505092915050565b60006020828403121561253557600080fd5b6114df82611731565b6001600160401b03841681526080810161255b6020830185612411565b82606083015294935050505056fe0000000000000000000000001111111111111111111111111111111111111111a164736f6c6343000814000a \ No newline at end of file diff --git a/blueprints/examples/src/raw_tangle_events.rs b/blueprints/examples/src/raw_tangle_events.rs index 1a004c9d..ec16a11a 100644 --- a/blueprints/examples/src/raw_tangle_events.rs +++ b/blueprints/examples/src/raw_tangle_events.rs @@ -1,11 +1,17 @@ use gadget_sdk::config::StdGadgetConfiguration; +use gadget_sdk::contexts::TangleClientContext; use gadget_sdk::event_listener::tangle::{TangleEvent, TangleEventListener}; use gadget_sdk::event_utils::InitializableEventHandler; use gadget_sdk::job; use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api; -#[derive(Clone)] -pub struct MyContext; +#[derive(Clone, TangleClientContext)] +pub struct MyContext { + #[config] + sdk_config: StdGadgetConfiguration, + #[call_id] + call_id: Option, +} pub async fn constructor( env: StdGadgetConfiguration, @@ -17,9 +23,15 @@ pub async fn constructor( .map_err(|e| color_eyre::eyre::eyre!(e))?; gadget_sdk::info!("Starting the event watcher for {} ...", signer.account_id()); - RawEventHandler::new(&env, MyContext) - .await - .map_err(|e| color_eyre::eyre::eyre!(e)) + RawEventHandler::new( + &env, + MyContext { + sdk_config: env.clone(), + call_id: None, + }, + ) + .await + .map_err(|e| color_eyre::eyre::eyre!(e)) } #[job( diff --git a/blueprints/examples/src/services_context.rs b/blueprints/examples/src/services_context.rs index 6ff4255e..38383027 100644 --- a/blueprints/examples/src/services_context.rs +++ b/blueprints/examples/src/services_context.rs @@ -11,6 +11,8 @@ use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::Job pub struct ExampleServiceContext { #[config] sdk_config: StdGadgetConfiguration, + #[call_id] + call_id: Option, } pub async fn constructor( @@ -24,9 +26,15 @@ pub async fn constructor( .map_err(|e| color_eyre::eyre::eyre!(e))?; gadget_sdk::info!("Starting the event watcher for {} ...", signer.account_id()); - HandleJobEventHandler::new(&env.clone(), ExampleServiceContext { sdk_config: env }) - .await - .map_err(|e| color_eyre::eyre::eyre!(e)) + HandleJobEventHandler::new( + &env.clone(), + ExampleServiceContext { + sdk_config: env, + call_id: None, + }, + ) + .await + .map_err(|e| color_eyre::eyre::eyre!(e)) } #[job( @@ -39,8 +47,8 @@ pub async fn constructor( ), )] pub async fn handle_job( - job_details: Vec, context: ExampleServiceContext, + job_details: Vec, ) -> Result { let client = context.tangle_client().await.unwrap(); let blueprint_owner = context.current_blueprint_owner(&client).await.unwrap(); diff --git a/blueprints/incredible-squaring/contracts/foundry.toml b/blueprints/incredible-squaring/contracts/foundry.toml index 21570e20..41f3dfb1 100644 --- a/blueprints/incredible-squaring/contracts/foundry.toml +++ b/blueprints/incredible-squaring/contracts/foundry.toml @@ -2,4 +2,4 @@ src = "src" out = "out" libs = ["lib"] -solc_version = "0.8.20" \ No newline at end of file +solc_version = "0.8.20" diff --git a/blueprints/incredible-squaring/contracts/remappings.txt b/blueprints/incredible-squaring/contracts/remappings.txt index e159d006..8b9a7a0a 100644 --- a/blueprints/incredible-squaring/contracts/remappings.txt +++ b/blueprints/incredible-squaring/contracts/remappings.txt @@ -1,4 +1,4 @@ ds-test/=lib/ds-test/src/ forge-std/=lib/forge-std/src/ +incredible-squaring/=src/ tnt-core/=lib/tnt-core/src/ -incredible-squaring/=src/ \ No newline at end of file diff --git a/blueprints/incredible-squaring/contracts/src/IncredibleSquaringBlueprint.sol b/blueprints/incredible-squaring/contracts/src/IncredibleSquaringBlueprint.sol index 687a7d7a..59ee7c1c 100644 --- a/blueprints/incredible-squaring/contracts/src/IncredibleSquaringBlueprint.sol +++ b/blueprints/incredible-squaring/contracts/src/IncredibleSquaringBlueprint.sol @@ -23,46 +23,62 @@ contract IncredibleSquaringBlueprint is BlueprintServiceManagerBase { mapping(uint64 => address) public serviceInstances; /** - * @dev Hook for service instance requests. Called when a user requests a service - * instance from the blueprint. - * @param serviceId The ID of the requested service. - * @param operatorsOfService The operators involved in the service in bytes array format. - * @param requestInputs Inputs required for the service request in bytes format. + * @dev Hook for service initialization. Called when a service is initialized. + * This hook is called after the service is approved from all of the operators. + * + * @param requestId The ID of the request. + * @param serviceId The ID of the service. + * @param owner The owner of the service. + * @param permittedCallers The list of permitted callers for the service. + * @param ttl The time-to-live for the service. */ - function onRequest(uint64 serviceId, bytes[] calldata operatorsOfService, bytes calldata requestInputs) - public - payable - virtual - override - onlyFromRootChain + function onServiceInitialized( + uint64 requestId, + uint64 serviceId, + address owner, + address[] calldata permittedCallers, + uint64 ttl + ) + external + virtual + override + onlyFromMaster { IncredibleSquaringInstance deployed = new IncredibleSquaringInstance(serviceId); serviceInstances[serviceId] = address(deployed); } /** - * @dev Verifies the result of a job call. This function is used to validate the - * outputs of a job execution against the expected results. + * @dev Hook for handling job result. Called when operators send the result + * of a job execution. * @param serviceId The ID of the service related to the job. * @param job The job identifier. * @param jobCallId The unique ID for the job call. - * @param participant The participant (operator) whose result is being verified. - * @param inputs Inputs used for the job execution. - * @param outputs Outputs resulting from the job execution. + * @param operator The operator sending the result in bytes format. + * @param inputs Inputs used for the job execution in bytes format. + * @param outputs Outputs resulting from the job execution in bytes format. */ function onJobResult( uint64 serviceId, uint8 job, uint64 jobCallId, - bytes calldata participant, + ServiceOperators.OperatorPreferences calldata operator, bytes calldata inputs, bytes calldata outputs - ) public payable override { - // Decode the inputs and outputs - uint256 input = abi.decode(inputs, (uint256)); - uint256 output = abi.decode(outputs, (uint256)); - // Check if the output is the square of the input - bool isValid = output == input * input; - require(isValid, "Invalid result"); + ) + external + payable + virtual + override + onlyFromMaster + { + if (jobCallId == 0) { + // Decode the inputs and outputs + uint256 input = abi.decode(inputs, (uint256)); + uint256 output = abi.decode(outputs, (uint256)); + // Check if the output is the square of the input + bool isValid = output == input * input; + require(isValid, "Invalid result"); + } } } diff --git a/blueprints/incredible-squaring/src/lib.rs b/blueprints/incredible-squaring/src/lib.rs index cd49f92a..0e88f748 100644 --- a/blueprints/incredible-squaring/src/lib.rs +++ b/blueprints/incredible-squaring/src/lib.rs @@ -1,10 +1,16 @@ +use gadget_sdk::contexts::TangleClientContext; use gadget_sdk::event_listener::tangle::jobs::{services_post_processor, services_pre_processor}; use gadget_sdk::event_listener::tangle::TangleEventListener; use gadget_sdk::job; use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::JobCalled; -#[derive(Clone)] -pub struct MyContext; +#[derive(Clone, TangleClientContext)] +pub struct MyContext { + #[config] + pub config: gadget_sdk::config::StdGadgetConfiguration, + #[call_id] + pub call_id: Option, +} #[job( id = 0, @@ -17,5 +23,24 @@ pub struct MyContext; )] /// Returns x^2 saturating to [`u64::MAX`] if overflow occurs. pub fn xsquare(x: u64, context: MyContext) -> Result { + assert!(context.call_id.is_some()); Ok(x.saturating_pow(2)) } + +#[job( + id = 1, + params(call_id), + event_listener( + listener = TangleEventListener, + pre_processor = services_pre_processor, + post_processor = services_post_processor, + ), +)] +pub fn test_call_id(context: MyContext, call_id: u64) -> Result { + gadget_sdk::info!("JOB CALL ID: {:?}, {}", context.call_id, call_id); + if context.call_id.unwrap() != call_id { + return Err(gadget_sdk::Error::Other(String::from("Call ID mismatch!"))); + } + + Ok(0) +} diff --git a/blueprints/incredible-squaring/src/main.rs b/blueprints/incredible-squaring/src/main.rs index aefa4287..0bfc6c15 100644 --- a/blueprints/incredible-squaring/src/main.rs +++ b/blueprints/incredible-squaring/src/main.rs @@ -7,7 +7,23 @@ use incredible_squaring_blueprint as blueprint; #[gadget_sdk::main(env)] async fn main() { - let x_square = blueprint::XsquareEventHandler::new(&env, blueprint::MyContext).await?; + let x_square = blueprint::XsquareEventHandler::new( + &env, + blueprint::MyContext { + config: env.clone(), + call_id: None, + }, + ) + .await?; + + let test_call_id = blueprint::TestCallIdEventHandler::new( + &env, + blueprint::MyContext { + config: env.clone(), + call_id: None, + }, + ) + .await?; info!( "Starting the event watcher for {} ...", @@ -18,6 +34,7 @@ async fn main() { let tangle_config = TangleConfig::default(); BlueprintRunner::new(tangle_config, env) .job(x_square) + .job(test_call_id) .run() .await?; diff --git a/blueprints/incredible-squaring/tests/call_id.rs b/blueprints/incredible-squaring/tests/call_id.rs new file mode 100644 index 00000000..ff2e257a --- /dev/null +++ b/blueprints/incredible-squaring/tests/call_id.rs @@ -0,0 +1,87 @@ +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering; + +pub use blueprint_test_utils::{ + get_blueprint_base_dir, read_cargo_toml_file, run_test_blueprint_manager, setup_log, + submit_job, tangle, wait_for_completion_of_tangle_job, Args, Job, Opts, +}; + +use blueprint_test_utils::test_ext::new_test_ext_blueprint_manager; +use blueprint_test_utils::{InputValue, OutputValue}; + +#[gadget_sdk::tokio::test(crate = "::gadget_sdk::tokio")] +async fn call_id_valid() { + const ITERATIONS: u8 = 5; + static CALL_ID: AtomicU64 = AtomicU64::new(0); + + setup_log(); + + const N: usize = 1; + const JOB_ID: usize = 1; + + new_test_ext_blueprint_manager::(String::new(), run_test_blueprint_manager) + .await + .execute_with_async(|client, handles, blueprint| async move { + let keypair = handles[0].sr25519_id().clone(); + let selected_service = &blueprint.services[0]; + let service_id = selected_service.id; + + for _ in 0..ITERATIONS { + gadget_sdk::info!("Submitting job {JOB_ID} with service ID {service_id}"); + + let expected_call_id = CALL_ID.load(Ordering::Relaxed); + let job_args = vec![InputValue::Uint64(expected_call_id)]; + + let job = submit_job( + client, + &keypair, + service_id, + Job::from(JOB_ID as u8), + job_args, + expected_call_id, + ) + .await + .expect("Failed to submit job"); + + let call_id = job.call_id; + + gadget_sdk::info!( + "Submitted job {JOB_ID} with service ID {service_id} has call id {call_id}" + ); + + let job_results = wait_for_completion_of_tangle_job(client, service_id, call_id, N) + .await + .expect("Failed to wait for job completion"); + + assert_eq!(job_results.service_id, service_id); + assert_eq!(job_results.call_id, call_id); + + let expected_outputs = vec![OutputValue::Uint64(0)]; + if expected_outputs.is_empty() { + gadget_sdk::info!("No expected outputs specified, skipping verification"); + return; + } + + assert_eq!( + job_results.result.len(), + expected_outputs.len(), + "Number of outputs doesn't match expected" + ); + + for (result, expected) in job_results + .result + .into_iter() + .zip(expected_outputs.into_iter()) + { + assert_eq!(result, expected); + } + + gadget_sdk::info!( + "*** Finished iteration {} ***", + CALL_ID.load(Ordering::Relaxed) + ); + CALL_ID.fetch_add(1, Ordering::Relaxed); + } + }) + .await +} diff --git a/blueprints/incredible-squaring/tests/e2e.rs b/blueprints/incredible-squaring/tests/e2e.rs index 7446c2c6..3c5ce5f0 100644 --- a/blueprints/incredible-squaring/tests/e2e.rs +++ b/blueprints/incredible-squaring/tests/e2e.rs @@ -4,8 +4,10 @@ const SQUARING_JOB_ID: usize = 0; const N: usize = 5; test_tangle_blueprint!( - N, // Number of nodes + N, // Number of nodes + N, SQUARING_JOB_ID, // Job ID [InputValue::Uint64(5)], // Inputs - [OutputValue::Uint64(25)] // Expected output: input squared + [OutputValue::Uint64(25)], // Expected output: input squared + 0, ); diff --git a/macros/blueprint-proc-macro/Cargo.toml b/macros/blueprint-proc-macro/Cargo.toml index 798d09b2..14a59dad 100644 --- a/macros/blueprint-proc-macro/Cargo.toml +++ b/macros/blueprint-proc-macro/Cargo.toml @@ -19,6 +19,7 @@ proc-macro2 = { workspace = true } serde_json = { workspace = true } gadget-blueprint-proc-macro-core = { workspace = true, default-features = false } indexmap = { workspace = true } +parking_lot = { workspace = true } [dev-dependencies] trybuild = { workspace = true } diff --git a/macros/blueprint-proc-macro/src/job.rs b/macros/blueprint-proc-macro/src/job.rs index cb401933..9454ca4d 100644 --- a/macros/blueprint-proc-macro/src/job.rs +++ b/macros/blueprint-proc-macro/src/job.rs @@ -230,21 +230,21 @@ pub(crate) fn generate_event_workflow_tokenstream( // convert the listener var, which is just a struct name, to an ident let listener = listener_meta.listener.to_token_stream(); + // Raw events have no pre-processor, therefore their inputs are passed directly into the job function + // and NOT as job params + let is_raw = listener_meta.is_raw(); + // Generate the variable that we are passing as the context into EventListener::create(&mut ctx) // We assume the first supplied event handler arg is the context we are injecting into the event listener // Then, pass that into the EventFlowWrapper let fn_name_ident = &input.sig.ident; let static_ctx_get_override = quote! { CTX.get().unwrap() }; - let mut ordered_inputs = - get_fn_call_ordered(param_types, params, Some(static_ctx_get_override))?; + let (ctx_pos_in_ordered_inputs, mut ordered_inputs) = + get_fn_call_ordered(param_types, params, Some(static_ctx_get_override), is_raw)?; let asyncness = get_asyncness(input); let call_id_static_name = get_current_call_id_field_name(input); - // Raw events have no pre-processor, therefore their inputs are passed directly into the job function - // and NOT as job params - let is_raw = listener_meta.is_raw(); - // TODO: task 001: find better way to identify which ident is the raw event // for now, we assume the raw event is always listed first if is_raw { @@ -257,7 +257,12 @@ pub(crate) fn generate_event_workflow_tokenstream( // If is_raw, assume the actual context is the second param quote! { ctx. #field_in_self .clone() } }) - .ok_or_else(|| syn::Error::new(Span::call_site(), "Must specify a context"))?; + .ok_or_else(|| { + syn::Error::new( + Span::call_site(), + "Must specify a context (field_in_self_getter)", + ) + })?; let autogen_struct_name = quote! { #struct_name }; @@ -292,9 +297,9 @@ pub(crate) fn generate_event_workflow_tokenstream( event_listeners, &mut ordered_inputs, fn_name_ident, - &call_id_static_name, &asyncness, &return_type, + ctx_pos_in_ordered_inputs, )?, ListenerType::Evm => get_evm_job_processor_wrapper( @@ -312,7 +317,7 @@ pub(crate) fn generate_event_workflow_tokenstream( quote! { move |param0| async move { - let res = #fn_name_ident (#(#ordered_inputs)*) #asyncness; + let res = #fn_name_ident (#(#ordered_inputs),*) #asyncness; #job_processor_call_return } } @@ -329,7 +334,7 @@ pub(crate) fn generate_event_workflow_tokenstream( let tangle_job_result = gadget_sdk::event_listener::tangle::TangleResult::<_> { results: job_result, service_id: ctx.service_id, - call_id: #call_id_static_name.load(std::sync::atomic::Ordering::Relaxed), + call_id: #call_id_static_name.fetch_add(1, std::sync::atomic::Ordering::Relaxed), client: ctx.client.clone(), signer: ctx.signer.clone(), }; @@ -377,8 +382,7 @@ pub(crate) fn generate_event_workflow_tokenstream( let next_listener = quote! { async fn #listener_function_name (ctx: &#autogen_struct_name) -> Option>> { static ONCE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); - if !ONCE.load(std::sync::atomic::Ordering::Relaxed) { - ONCE.store(true, std::sync::atomic::Ordering::Relaxed); + if !ONCE.fetch_or(true, std::sync::atomic::Ordering::Relaxed) { let (tx, rx) = gadget_sdk::tokio::sync::oneshot::channel(); static CTX: gadget_sdk::tokio::sync::OnceCell<#autogen_struct_name> = gadget_sdk::tokio::sync::OnceCell::const_new(); @@ -568,7 +572,8 @@ pub fn get_fn_call_ordered( param_types: &IndexMap, params_from_job_args: &[Ident], replacement_for_self: Option, -) -> syn::Result> { + is_raw: bool, +) -> syn::Result<(usize, Vec)> { let (event_handler_args, _) = get_event_handler_args(param_types, params_from_job_args)?; let additional_var_indexes: Vec = @@ -583,6 +588,8 @@ pub fn get_fn_call_ordered( // This has all params let mut job_var_idx = 0; + let mut non_job_var_count = 0; + let mut ctx_pos = None; let this = replacement_for_self.unwrap_or_else(|| quote! { self }); let ret = param_types .iter() @@ -595,7 +602,7 @@ pub fn get_fn_call_ordered( if is_job_var { let ident = format_ident!("param{job_var_idx}"); job_var_idx += 1; - return quote! { #ident, }; + return quote! { #ident }; } let (is_ref, is_ref_mut) = match ty { @@ -603,17 +610,35 @@ pub fn get_fn_call_ordered( _ => (false, false), }; + if non_job_var_count == 0 { + // Assume first non-job var is the context + ctx_pos = Some(pos_in_all_args); + } + + non_job_var_count += 1; + if is_ref && is_ref_mut { - quote! { &mut #this .#ident, } + quote! { &mut #this .#ident } } else if is_ref { - quote! { &#this .#ident, } + quote! { &#this .#ident } } else { - quote! { #this .#ident.clone(), } + quote! { #this .#ident.clone() } } }) .collect::>(); - Ok(ret) + if is_raw { + ctx_pos = Some(1); // Raw events have only two events: 0 = the raw event, 1 = the context + } + + let ctx_pos = ctx_pos.ok_or_else(|| { + syn::Error::new( + Span::call_site(), + "Could not find the context in the function signature", + ) + })?; + + Ok((ctx_pos, ret)) } fn get_asyncness(input: &ItemFn) -> proc_macro2::TokenStream { @@ -640,12 +665,9 @@ pub fn generate_specialized_logic( generate_evm_specific_impl(&struct_name, event_listener_args, param_map, job_params) } - ListenerType::Tangle => Ok(generate_tangle_specific_impl( - &struct_name, - param_map, - job_params, - event_listener_args, - )), + ListenerType::Tangle => { + generate_tangle_specific_impl(&struct_name, param_map, job_params, event_listener_args) + } ListenerType::Custom => Ok(proc_macro2::TokenStream::default()), } diff --git a/macros/blueprint-proc-macro/src/special_impls/evm.rs b/macros/blueprint-proc-macro/src/special_impls/evm.rs index f89e3393..1f34992f 100644 --- a/macros/blueprint-proc-macro/src/special_impls/evm.rs +++ b/macros/blueprint-proc-macro/src/special_impls/evm.rs @@ -124,7 +124,7 @@ pub(crate) fn get_evm_job_processor_wrapper( quote! { let inputs = param0; #(#params_tokens)* - let res = #fn_name_ident (#(#ordered_inputs)*) #asyncness; + let res = #fn_name_ident (#(#ordered_inputs),*) #asyncness; } }; diff --git a/macros/blueprint-proc-macro/src/special_impls/tangle.rs b/macros/blueprint-proc-macro/src/special_impls/tangle.rs index 469972ae..4782f026 100644 --- a/macros/blueprint-proc-macro/src/special_impls/tangle.rs +++ b/macros/blueprint-proc-macro/src/special_impls/tangle.rs @@ -11,7 +11,7 @@ pub(crate) fn generate_tangle_specific_impl( param_map: &IndexMap, job_params: &[Ident], event_listener_args: &EventListenerArgs, -) -> TokenStream { +) -> syn::Result { let mut non_job_param_map = get_non_job_arguments(param_map, job_params); let mut new_function_signature = vec![]; let mut constructor_args = vec![]; @@ -45,7 +45,7 @@ pub(crate) fn generate_tangle_specific_impl( let struct_name_as_literal = struct_name.to_string(); - quote! { + Ok(quote! { impl #struct_name { /// Create a new #[doc = "[`"] @@ -69,7 +69,7 @@ pub(crate) fn generate_tangle_specific_impl( #[automatically_derived] impl gadget_sdk::event_listener::markers::IsTangle for #struct_name {} - } + }) } #[allow(clippy::too_many_arguments)] @@ -79,9 +79,9 @@ pub(crate) fn get_tangle_job_processor_wrapper( event_listeners: &EventListenerArgs, ordered_inputs: &mut Vec, fn_name_ident: &Ident, - call_id_static_name: &Ident, asyncness: &TokenStream, return_type: &Type, + ctx_post_in_ordered_inputs: usize, ) -> syn::Result { let params = declared_params_to_field_types(job_params, param_map)?; let params_tokens = event_listeners.get_param_name_tokenstream(¶ms); @@ -91,37 +91,48 @@ pub(crate) fn get_tangle_job_processor_wrapper( const PARAMETER_COUNT: usize = #parameter_count; }; + let injected_context = ordered_inputs[ctx_post_in_ordered_inputs].clone(); + let call_id_injector = quote! { + let mut injected_context = #injected_context; + if let Some(call_id) = tangle_event.call_id { + gadget_sdk::contexts::TangleClientContext::set_call_id(&mut injected_context, call_id); + } + }; + + ordered_inputs[ctx_post_in_ordered_inputs] = quote! { injected_context }; + let job_processor_call = if params_tokens.is_empty() { let second_param = ordered_inputs .pop() .ok_or_else(|| syn::Error::new(Span::call_site(), "Context type required"))?; quote! { + #call_id_injector // If no args are specified, assume this job has no parameters and thus takes in the raw event - let res = #fn_name_ident (param0, #second_param) #asyncness; + let res = #fn_name_ident (tangle_event, #second_param) #asyncness; } } else { quote! { #parameter_count_const - if param0.args.len() != PARAMETER_COUNT { + if tangle_event.args.len() != PARAMETER_COUNT { return Err( - ::gadget_sdk::Error::BadArgumentDecoding(format!("Parameter count mismatch, got `{}`, expected `{PARAMETER_COUNT}`", param0.args.len())) + ::gadget_sdk::Error::BadArgumentDecoding(format!("Parameter count mismatch, got `{}`, expected `{PARAMETER_COUNT}`", tangle_event.args.len())) ); } - let mut args = param0.args.into_iter(); + let mut args = tangle_event.args.clone().into_iter(); #(#params_tokens)* - let res = #fn_name_ident (#(#ordered_inputs)*) #asyncness; + + #call_id_injector + + let res = #fn_name_ident (#(#ordered_inputs),*) #asyncness; } }; let job_processor_call_return = get_return_type_wrapper(return_type); Ok(quote! { - move |param0: gadget_sdk::event_listener::tangle::TangleEvent<_, _>| async move { - if let Some(call_id) = param0.call_id { - #call_id_static_name.store(call_id, std::sync::atomic::Ordering::Relaxed); - } + move |tangle_event: gadget_sdk::event_listener::tangle::TangleEvent<_, _>| async move { #job_processor_call #job_processor_call_return diff --git a/macros/context-derive/src/cfg.rs b/macros/context-derive/src/cfg.rs index 8e9a3122..67bf0a97 100644 --- a/macros/context-derive/src/cfg.rs +++ b/macros/context-derive/src/cfg.rs @@ -5,7 +5,12 @@ pub enum FieldInfo { Unnamed(Index), } -pub fn find_config_field(input_ident: &Ident, data: &Data) -> Result { +pub fn find_config_field( + input_ident: &Ident, + data: &Data, + tag_name: &'static str, + tag_ty: &'static str, +) -> Result { match data { Data::Struct(data_struct) => match &data_struct.fields { Fields::Named(fields) => { @@ -13,19 +18,19 @@ pub fn find_config_field(input_ident: &Ident, data: &Data) -> Result if field .attrs .iter() - .any(|attr| attr.path().is_ident("config")) + .any(|attr| attr.path().is_ident(tag_name)) { return field.ident.clone().map(FieldInfo::Named).ok_or_else(|| { Error::new_spanned( field, - "Expected named field with #[config] attribute", + format!("Expected named field with #[{tag_name}] attribute"), ) }); } } Err(Error::new_spanned( input_ident, - "No field with #[config] attribute found, please add #[config] to the field that holds the `gadget_sdk::config::GadgetConfiguration`", + format!("No field with #[{tag_name}] attribute found, please add #[{tag_name}] to the field that holds the `{tag_ty}`"), )) } Fields::Unnamed(fields) => { @@ -33,14 +38,14 @@ pub fn find_config_field(input_ident: &Ident, data: &Data) -> Result if field .attrs .iter() - .any(|attr| attr.path().is_ident("config")) + .any(|attr| attr.path().is_ident(tag_name)) { return Ok(FieldInfo::Unnamed(Index::from(i))); } } Err(Error::new_spanned( input_ident, - "No field with #[config] attribute found, please add #[config] to the field that holds the `gadget_sdk::config::GadgetConfiguration`", + format!("No field with #[{tag_name}] attribute found, please add #[{tag_name}] to the field that holds the `{tag_ty}`"), )) } Fields::Unit => Err(Error::new_spanned( diff --git a/macros/context-derive/src/lib.rs b/macros/context-derive/src/lib.rs index 04a41650..5a2f0e0b 100644 --- a/macros/context-derive/src/lib.rs +++ b/macros/context-derive/src/lib.rs @@ -26,12 +26,18 @@ mod services; /// Tangle Subxt Client context extension implementation. mod subxt; +const CONFIG_TAG_NAME: &str = "config"; +const CONFIG_TAG_TYPE: &str = "gadget_sdk::config::GadgetConfiguration"; +const CALL_ID_TAG_NAME: &str = "call_id"; +const CALL_ID_TAG_TYPE: &str = "Option"; + /// Derive macro for generating Context Extensions trait implementation for `KeystoreContext`. #[proc_macro_derive(KeystoreContext, attributes(config))] pub fn derive_keystore_context(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); - let result = cfg::find_config_field(&input.ident, &input.data) - .map(|config_field| keystore::generate_context_impl(input, config_field)); + let result = + cfg::find_config_field(&input.ident, &input.data, CONFIG_TAG_NAME, CONFIG_TAG_TYPE) + .map(|config_field| keystore::generate_context_impl(input, config_field)); match result { Ok(expanded) => TokenStream::from(expanded), @@ -43,8 +49,9 @@ pub fn derive_keystore_context(input: TokenStream) -> TokenStream { #[proc_macro_derive(EVMProviderContext, attributes(config))] pub fn derive_evm_provider_context(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); - let result = cfg::find_config_field(&input.ident, &input.data) - .map(|config_field| evm::generate_context_impl(input, config_field)); + let result = + cfg::find_config_field(&input.ident, &input.data, CONFIG_TAG_NAME, CONFIG_TAG_TYPE) + .map(|config_field| evm::generate_context_impl(input, config_field)); match result { Ok(expanded) => TokenStream::from(expanded), @@ -53,11 +60,23 @@ pub fn derive_evm_provider_context(input: TokenStream) -> TokenStream { } /// Derive macro for generating Context Extensions trait implementation for `TangleClientContext`. -#[proc_macro_derive(TangleClientContext, attributes(config))] +#[proc_macro_derive(TangleClientContext, attributes(config, call_id))] pub fn derive_tangle_client_context(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); - let result = cfg::find_config_field(&input.ident, &input.data) - .map(|config_field| subxt::generate_context_impl(input, config_field)); + let result = + cfg::find_config_field(&input.ident, &input.data, CONFIG_TAG_NAME, CONFIG_TAG_TYPE) + .and_then(|res| { + let call_id_field = cfg::find_config_field( + &input.ident, + &input.data, + CALL_ID_TAG_NAME, + CALL_ID_TAG_TYPE, + )?; + Ok((res, call_id_field)) + }) + .map(|(config_field, call_id_field)| { + subxt::generate_context_impl(input, config_field, call_id_field) + }); match result { Ok(expanded) => TokenStream::from(expanded), @@ -69,8 +88,9 @@ pub fn derive_tangle_client_context(input: TokenStream) -> TokenStream { #[proc_macro_derive(ServicesContext, attributes(config))] pub fn derive_services_context(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); - let result = cfg::find_config_field(&input.ident, &input.data) - .map(|config_field| services::generate_context_impl(input, config_field)); + let result = + cfg::find_config_field(&input.ident, &input.data, CONFIG_TAG_NAME, CONFIG_TAG_TYPE) + .map(|config_field| services::generate_context_impl(input, config_field)); match result { Ok(expanded) => TokenStream::from(expanded), @@ -82,8 +102,9 @@ pub fn derive_services_context(input: TokenStream) -> TokenStream { #[proc_macro_derive(EigenlayerContext, attributes(config))] pub fn derive_eigenlayer_context(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); - let result = cfg::find_config_field(&input.ident, &input.data) - .map(|config_field| eigenlayer::generate_context_impl(input, config_field)); + let result = + cfg::find_config_field(&input.ident, &input.data, CONFIG_TAG_NAME, CONFIG_TAG_TYPE) + .map(|config_field| eigenlayer::generate_context_impl(input, config_field)); match result { Ok(expanded) => TokenStream::from(expanded), @@ -95,8 +116,9 @@ pub fn derive_eigenlayer_context(input: TokenStream) -> TokenStream { #[proc_macro_derive(MPCContext, attributes(config))] pub fn derive_mpc_context(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); - let result = cfg::find_config_field(&input.ident, &input.data) - .map(|config_field| mpc::generate_context_impl(input, config_field)); + let result = + cfg::find_config_field(&input.ident, &input.data, CONFIG_TAG_NAME, CONFIG_TAG_TYPE) + .map(|config_field| mpc::generate_context_impl(input, config_field)); match result { Ok(expanded) => TokenStream::from(expanded), diff --git a/macros/context-derive/src/subxt.rs b/macros/context-derive/src/subxt.rs index b8e7f299..75309302 100644 --- a/macros/context-derive/src/subxt.rs +++ b/macros/context-derive/src/subxt.rs @@ -11,8 +11,14 @@ pub fn generate_context_impl( .. }: DeriveInput, config_field: FieldInfo, + call_id_field: FieldInfo, ) -> proc_macro2::TokenStream { - let field_access = match config_field { + let field_access_config = match config_field { + FieldInfo::Named(ident) => quote! { self.#ident }, + FieldInfo::Unnamed(index) => quote! { self.#index }, + }; + + let field_access_call_id = match call_id_field { FieldInfo::Named(ident) => quote! { self.#ident }, FieldInfo::Unnamed(index) => quote! { self.#index }, }; @@ -22,6 +28,11 @@ pub fn generate_context_impl( quote! { impl #impl_generics gadget_sdk::contexts::TangleClientContext for #name #ty_generics #where_clause { type Config = gadget_sdk::ext::subxt::PolkadotConfig; + + fn set_call_id(&mut self, call_id: u64) { + #field_access_call_id = Some(call_id); + } + fn tangle_client(&self) -> impl core::future::Future, gadget_sdk::ext::subxt::Error>> { use gadget_sdk::ext::subxt; @@ -31,7 +42,7 @@ pub fn generate_context_impl( match CLIENT.get() { Some(client) => Ok(client.clone()), None => { - let rpc_url = #field_access.ws_rpc_endpoint.as_str(); + let rpc_url = #field_access_config.ws_rpc_endpoint.as_str(); let client = subxt::OnlineClient::from_url(rpc_url).await?; CLIENT.set(client.clone()).map(|_| client).map_err(|_| { subxt::Error::Io(std::io::Error::new( diff --git a/macros/context-derive/tests/ui/basic.rs b/macros/context-derive/tests/ui/basic.rs index a07eeb6b..89d1dda3 100644 --- a/macros/context-derive/tests/ui/basic.rs +++ b/macros/context-derive/tests/ui/basic.rs @@ -20,6 +20,8 @@ struct MyContext { #[config] config: StdGadgetConfiguration, store: Arc>, + #[call_id] + call_id: Option, } #[allow(dead_code)] @@ -29,6 +31,7 @@ fn main() { foo: "bar".to_string(), config: GadgetConfiguration::default(), store: Arc::new(LocalDatabase::open("test.json")), + call_id: None, }; // Test existing context functions diff --git a/macros/context-derive/tests/ui/generic_struct.rs b/macros/context-derive/tests/ui/generic_struct.rs index c0eecfd4..6ee6f46b 100644 --- a/macros/context-derive/tests/ui/generic_struct.rs +++ b/macros/context-derive/tests/ui/generic_struct.rs @@ -10,6 +10,8 @@ struct MyContext { bar: U, #[config] sdk_config: StdGadgetConfiguration, + #[call_id] + call_id: Option, } #[allow(dead_code)] @@ -19,6 +21,7 @@ fn main() { foo: "bar".to_string(), bar: 42, sdk_config: GadgetConfiguration::default(), + call_id: None, }; let _keystore = ctx.keystore(); let _evm_provider = ctx.evm_provider().await.unwrap(); diff --git a/macros/context-derive/tests/ui/unnamed_fields.rs b/macros/context-derive/tests/ui/unnamed_fields.rs index fb63f8ae..7189ec46 100644 --- a/macros/context-derive/tests/ui/unnamed_fields.rs +++ b/macros/context-derive/tests/ui/unnamed_fields.rs @@ -5,12 +5,16 @@ use gadget_sdk::contexts::{ #[derive(KeystoreContext, EVMProviderContext, TangleClientContext, ServicesContext)] #[allow(dead_code)] -struct MyContext(String, #[config] StdGadgetConfiguration); +struct MyContext( + String, + #[config] StdGadgetConfiguration, + #[call_id] Option, +); #[allow(dead_code)] fn main() { let body = async { - let ctx = MyContext("bar".to_string(), GadgetConfiguration::default()); + let ctx = MyContext("bar".to_string(), GadgetConfiguration::default(), None); let _keystore = ctx.keystore(); let _evm_provider = ctx.evm_provider().await; let tangle_client = ctx.tangle_client().await.unwrap(); diff --git a/macros/playground/src/lib.rs b/macros/playground/src/lib.rs index b38f57da..8e8a57b4 100644 --- a/macros/playground/src/lib.rs +++ b/macros/playground/src/lib.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] -use gadget_sdk::clients::tangle::runtime::TangleClient; +use gadget_sdk::config::StdGadgetConfiguration; +use gadget_sdk::contexts::TangleClientContext; use gadget_sdk::event_listener::tangle::jobs::{services_post_processor, services_pre_processor}; use gadget_sdk::event_listener::tangle::TangleEventListener; use gadget_sdk::tangle_subxt::tangle_testnet_runtime::api::services::events::{ @@ -26,16 +27,21 @@ impl std::fmt::Display for Error { } impl std::error::Error for Error {} -#[derive(Copy, Clone)] -pub struct MyContext; +#[derive(Clone, TangleClientContext)] +pub struct MyContext { + #[config] + pub config: StdGadgetConfiguration, + #[call_id] + pub call_id: Option, +} // ================== // Jobs // ================== /// Simple Threshold (t) Keygen Job for n parties. -#[job(id = 0, params(n, t), event_listener(listener = TangleEventListener, pre_processor = services_pre_processor))] -pub fn keygen(context: TangleClient, n: u16, t: u16) -> Result, Error> { +#[job(id = 0, params(n, t), event_listener(listener = TangleEventListener, pre_processor = services_pre_processor))] +pub fn keygen(context: MyContext, n: u16, t: u16) -> Result, Error> { let _ = (n, t, context); Ok(vec![0; 33]) } @@ -44,9 +50,9 @@ pub fn keygen(context: TangleClient, n: u16, t: u16) -> Result, Error> { #[job( id = 1, params(keygen_id, data), - event_listener(listener = TangleEventListener, pre_processor = services_pre_processor), + event_listener(listener = TangleEventListener, pre_processor = services_pre_processor), )] -pub async fn sign(context: TangleClient, keygen_id: u64, data: Vec) -> Result, Error> { +pub async fn sign(context: MyContext, keygen_id: u64, data: Vec) -> Result, Error> { let _ = (keygen_id, data); Ok(vec![0; 65]) } @@ -55,16 +61,12 @@ pub async fn sign(context: TangleClient, keygen_id: u64, data: Vec) -> Resul id = 2, params(keygen_id, new_t), event_listener( - listener = TangleEventListener, + listener = TangleEventListener, pre_processor = services_pre_processor, post_processor = services_post_processor, ), )] -pub fn refresh( - context: TangleClient, - keygen_id: u64, - new_t: Option, -) -> Result, Error> { +pub fn refresh(context: MyContext, keygen_id: u64, new_t: Option) -> Result, Error> { let _ = (keygen_id, new_t); Ok(vec![0; 33]) } @@ -72,11 +74,11 @@ pub fn refresh( /// Say hello to someone or the world. #[job(id = 3, params(who), event_listener( - listener = TangleEventListener, + listener = TangleEventListener, pre_processor = services_pre_processor, post_processor = services_post_processor, ))] -pub fn say_hello(context: TangleClient, who: Option) -> Result { +pub fn say_hello(context: MyContext, who: Option) -> Result { match who { Some(who) => Ok(format!("Hello, {}!", who)), None => Ok("Hello, World!".to_string()), @@ -102,7 +104,7 @@ pub fn on_request(nft_id: u64); job_id = 0, params(n, t, msgs), event_listener( - listener = TangleEventListener, + listener = TangleEventListener, pre_processor = services_pre_processor, post_processor = services_post_processor, ), @@ -111,7 +113,7 @@ pub fn on_request(nft_id: u64); verifier(evm = "KeygenContract") )] fn report_keygen( - context: TangleClient, + context: MyContext, n: u16, t: u16, msgs: Vec>, @@ -122,13 +124,13 @@ fn report_keygen( #[report( params(uptime, response_time, error_rate), - event_listener(listener = TangleEventListener, pre_processor = services_pre_processor,), + event_listener(listener = TangleEventListener, pre_processor = services_pre_processor,), report_type = "qos", interval = 3600, metric_thresholds(uptime = 99, response_time = 1000, error_rate = 5) )] fn report_service_health( - context: TangleClient, + context: MyContext, uptime: u64, response_time: u64, error_rate: u64, diff --git a/sdk/src/contexts/mod.rs b/sdk/src/contexts/mod.rs index 8e4a801f..73f01c5f 100644 --- a/sdk/src/contexts/mod.rs +++ b/sdk/src/contexts/mod.rs @@ -8,6 +8,7 @@ //! # Example //! //! ```rust,no_run +//! use gadget_context_derive::TangleClientContext; //! use gadget_sdk::config::StdGadgetConfiguration; //! use gadget_sdk::contexts::KeystoreContext; //! use gadget_sdk::event_listener::tangle::jobs::{ @@ -19,12 +20,14 @@ //! //! // This your struct that encapsulates all the things you need from outside world. //! // By deriving KeystoreContext, you can now access the keystore client from your struct. -//! #[derive(Clone, Debug, KeystoreContext)] +//! #[derive(Clone, Debug, KeystoreContext, TangleClientContext)] //! struct MyContext { //! foo: String, //! bar: u64, //! #[config] //! sdk_config: StdGadgetConfiguration, +//! #[call_id] +//! call_id: Option, //! } //! //! #[job( diff --git a/sdk/src/contexts/tangle_client.rs b/sdk/src/contexts/tangle_client.rs index 031dbb5c..3c24c3c3 100644 --- a/sdk/src/contexts/tangle_client.rs +++ b/sdk/src/contexts/tangle_client.rs @@ -7,4 +7,6 @@ pub trait TangleClientContext { fn tangle_client( &self, ) -> impl Future, subxt::Error>>; + + fn set_call_id(&mut self, call_id: u64); } diff --git a/sdk/src/event_listener/tangle/jobs.rs b/sdk/src/event_listener/tangle/jobs.rs index 9592b402..3aa05238 100644 --- a/sdk/src/event_listener/tangle/jobs.rs +++ b/sdk/src/event_listener/tangle/jobs.rs @@ -1,15 +1,16 @@ +use crate::contexts::TangleClientContext; use crate::event_listener::tangle::{EventMatcher, TangleEvent, TangleResult}; use crate::Error; use std::any::Any; use tangle_subxt::tangle_testnet_runtime::api; use tangle_subxt::tangle_testnet_runtime::api::services::events::{JobCalled, JobResultSubmitted}; -pub async fn services_pre_processor>( +pub async fn services_pre_processor>( event: TangleEvent, ) -> Result, Error> { let TangleEvent { evt, - context, + mut context, block_number, signer, client, @@ -29,10 +30,14 @@ pub async fn services_pre_processor>( return Err(Error::SkipPreProcessedType); }; - crate::info!("Pre-processing event for sid/bid = {service_id}/{job_id} ..."); + crate::info!("Pre-processing event for service-id/job-id = {service_id}/{job_id} ..."); if event_job_id == job_id && event_service_id == service_id { - crate::info!("Found actionable event for sid/bid = {event_service_id}/{event_job_id} ..."); + crate::info!( + "Found actionable event for service-id/job-id = {event_service_id}/{event_job_id} ..." + ); + // Set the call ID that way the user can access it in the job function + context.set_call_id(event_call_id); return Ok(TangleEvent { evt: *boxed_item.downcast().unwrap(), context, @@ -64,7 +69,7 @@ pub async fn services_post_processor( let response = api::tx().services().submit_result( service_id, call_id, - vec![dbg!(blueprint_serde::to_field(results)?)], + vec![blueprint_serde::to_field(results)?], ); let _ = crate::tx::tangle::send(&client, &signer, &response) .await diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index a2a32617..2f78b2e4 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -77,6 +77,7 @@ pub use color_eyre; pub use error::Error; pub use futures; pub use gadget_blueprint_proc_macro::*; +pub use k256; pub use libp2p; pub use parking_lot; pub use round_based; diff --git a/sdk/src/utils/hashing.rs b/sdk/src/utils/hashing.rs index 6c16ea2d..66c10498 100644 --- a/sdk/src/utils/hashing.rs +++ b/sdk/src/utils/hashing.rs @@ -2,7 +2,7 @@ macro_rules! compute_sha256_hash { ($($data:expr),*) => { { - use k256::sha2::{Digest, Sha256}; + use gadget_sdk::k256::sha2::{Digest, Sha256}; let mut hasher = Sha256::default(); $(hasher.update($data);)* let result = hasher.finalize();