free-honey / naumachia Goto Github PK
View Code? Open in Web Editor NEWCardano Smart Contract SDK and Testing Framework
License: Apache License 2.0
Cardano Smart Contract SDK and Testing Framework
License: Apache License 2.0
"I'm using CML to build a TX for minting a one-shot token. Meaning I need to manually specify an input UTxO for the Policy to pass.
I've gotten it to work once, but I think I've encountered a subtle bug on my second run. The input it is specifying has the minimum Coin value, so it shouldn't be enough for an output after fees, but for some reason the let input_total = builder.get_total_input()?; in the method add_change_if_needed(), doesn't add any extra inputs to make up for the difference :(. i.e. add_change_if_needed() fails with the error
"Not enough ADA leftover to include non-ADA assets in a change address"
In playing around with the code, I removed the input UTxO from the transaction builder, just to see what inputs it gave me. And in that case it goes ahead and adds a big juicy UTxO to cover the fees + change (but of course the Policy fails on execution).
Is this a bug? Or could I be doing something different in the tx builder to help it add extra inputs?"
Right now we're just using strings
CI takes too long. I assume it's mostly the Aiken
compilation that happens during the build process for each of the example projects.
I assume that if we split them up they could be handled by separate workers? That would parallelize the process.
This is long overdue. Let's add tracing to all the main intersections in Naumachia so consumers can use that for debugging, etc.
WE currently just choose the smallest "valid" UTxO as our collateral. But according to this:
https://twitter.com/_KtorZ_/status/1598471789574856704?s=20&t=DFEkjQZKu-ajVvRMc2UB9w
we can use whichever UTxO and specify the right amount of change. That's much more robust.
This is confusing, so maybe we just bite the bullet and force all addresses to be valid. It's just been nice to put Address::new("alice")
into tests and not have to think about it being correct. But since some of our impls take a dep on Address
and do in fact expect a certain shape, we kinda need to do something. Specifically, the test clients are affected. The live clients kinda force you into us real addresses, whereas in the test code, it'll just give you weird errors when it tries to convert into bytes and stuff.
We can do better.
We just check that the provided script is valid, not that the spent output is associated with that script :P
Good chance we can just wrap the CNCLI or something similar with a port adapter. I haven't spent a lot of time looking into what this will take. Good chance this could be broken down into a feature with multiple tasks.
I just used these numbers to calculate the Second conversion to Slot:
https://cardano.stackexchange.com/questions/6955/when-was-the-slot-duration-set-to-1-sec-on-cardano-testnet
I don't know if that is general enough, and it's definitely not going to work on Mainnet
There shouldn't be a default signer in the ContextBuilder::new()
, it should just be like every other method.
This will make it more flexible.
Essentially, the signature is currently:
pub trait LedgerClient<Datum, Redeemer>: Send + Sync {
...
async fn outputs_at_address(&self, address: &Address)
-> LedgerClientResult<Vec<Output<Datum>>>;
...
async fn issue(&self, tx: Transaction<Datum, Redeemer>) -> LedgerClientResult<()>;
and we can make it
pub trait LedgerClient: Send + Sync {
...
async fn outputs_at_address<Datum>(&self, address: &Address)
-> LedgerClientResult<Vec<Output<Datum>>>;
...
async fn issue<Datum, Redeemer>(&self, tx: Transaction<Datum, Redeemer>) -> LedgerClientResult<()>;
Right now, CML TxBuilder
only has a set_validity_start_interval
for setting validity range. There is no way to set an upper bound.
We need to change that, possibly by making a PR to CML.
It think it's safe to say that all endpoints will result in a transaction being submitted. That transaction should be reported back to the caller.
This isn't a big surprise, but we need to introduce a better intermediary representation of the UTxO and then let the LedgerClient
adapter deal with either iding them or letting the blockchain give you that info.
REgardless, it needs to be pushed out of the domain. There are a few TODOs scattered through the code that relates to this.
The Cost Model can change at any moment and they are currently hardcoded.
In the mean time, here is some janky code I wrote to compare values from
https://book.world.dev.cardano.org/cost-model.html
with the values I have in code:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9689ba273c74fe4d0b6d519a7fedef8a
Ogmios Endpoint:
https://ogmios.dev/mini-protocols/local-state-query/
Currently, there are no fees. We need to include for actual on-chain contracts. The fee calculation should be abstracted and possibly implemented on the TxoRecord, or whatever that becomes after more development.
There is limited support for using networks other than TESTNET
currently. For example, the AlwaysSucceedsScript
sample dApp's network is hard-coded, and it should be parameterized, or maybe the scripts shouldn't even worry about the network?
I think the easiest solution though is just adding a network(&self) -> u8
method to the LedgerClient
trait. Then we don't need to worry about it and everyone has access to it that needs it.
Seems like a smell... A bit of a got type. But it's an easy solution for now.
The Validator SCript can be used by many ledger clients. This is just the wrong place for it.
Right now we just have PolicyId.
Maybe instead of Option<Address>
this could be
enum PolicyId {
ADA,
Id(String),
IdWithAssetName(String, String)
}
And then a From
impl from Address or something.
Still sorting it out.
Each release of Naumachia should have a pinned version of Aiken to get a deterministic script address mostly.
We might need a more robust solution to this long-term, but this is the first step.
Right now it just does what you tell it. We should use an actual minting policy with checks. Similar to the RedeemScriptOutput and ValidatorCode stuff.
Currently SCLogic
includes the associated types:
type Endpoints: Send + Sync;
type Lookups: Send + Sync;
type LookupResponses: Send + Sync;
type Datums: Clone + Eq + Debug + Send + Sync;
type Redeemers: Clone + PartialEq + Eq + Hash + Send + Sync;
This was meant to constrain the LedgerClient
to be able to handle the correct Datums and Redeemers. This might not be necessary anymore, now that we have a domain concept of PlutusData
and conversions between.
It might be better to put the conversion constraint at the implementation level if you want the conversion guarantees.
They are broken right now because the Plutus scripts follow different patterns than Aiken, and I've been prioritizing Aiken. The best solution would be to rewrite the scripts in Aiken, but we can also do custom Constrs around some of the data types to make them work
Currently can't mint any native tokens on the real chain. This needs to be added to the issue
implementation for CMLLedgerClient
When you hit an endpoint and it successfully submits a transaction, it will print the transaction id. We don't want this, we want it to return the tx_id
and the caller can choose to print it if they'd like.
We can include a trace of the info as well if we want.
These can be essentially the same code in a lot of places. It might just work to abstract the utxo storage part of it away behind a trait.
I don't think Backend
is giving us much value at this point. Worth checking if we can just pass an LC in directly instead of dealing with the intermediate type.
The process
method can just be added to the default methods on the LedgerClient
trait.
I just copied a lot of code when adding the key manager and ledger code to the Trireme Ledger Client. Essentially, we only want Trireme, and we can use Trireme in all those ignored CML tests instead of just some floating configs.
This is the domain representation of a transaction, not the ledger representation. But everything that is included on a ledger transation needs to be represented here in some form--the information needs to be all here.
Kinda blocked by free-honey/scrolls-client#3 (which is obviously bad because its external, but that's the point of the other issue)
Right now, my contracts are generic for just 1 type of datum and 1 type of redeemer. Granted, these can be enum
s, but, importantly, this still only allows 1 Validator per contract.
That's a bad constraint.
I want, at the very least, to provide a pattern to allow a contract writer to include multiple validator scripts in their contract. It might be as simple as doing nested datums and having one off-chain datum type that will hold the necessary on-chain datums, but we should make sure that this can be type checked before submission.
enum MyDatums {
ValidatorA(ValidatorADatum),
ValidatorB(ValidatorBDatum),
}
enum MyValidators {
ValidatorA(ValidatorACode),
ValidatorB(ValidatorBCode),
}
Something like this might work and just make the contract generic for MyDatums
and your implementation will enable the matching to happen. But this is far from a pit-of-success solution for consumers. Might be a good stop-gap, since it's a less common pattern probably.
I'm just keeping it close for the time being, but I'll want to move it out once things feel stablish.
Let's hold ourselves to high standard and shoot for high coverage. And lets get a badge up there to remind us how much we're failng :P
Right now we're using a very naive approach: including every UTxO you own. Need to use better approach. See:
https://cips.cardano.org/cips/cip2/
Right now we're using String for convenience, but it should depend on the TxORecord impl.
There needs to be different Tx types for V1 and V2 transactions. This will have implications for the whole framework.
Let's help people understand the structure and why things work the way they do. It might still change a lot, but at least we can document those changes and stuff if we have a baseline.
Both the in memory and the local persisted ledger clients are just haphazardly creating tx_hashes. This won't break anything... so I haven't bothered changing that. But eventually we really need to do it in a sane way similar to how it's actually done, i.e. we need to have each tx only have one tx_hash and then manage all the indexes at once.
Right now it's just a String
under the hood and there is no difference between wallet addresses, policies, and script addresses.
At the very least, we should reevaluate this.
Transfer
Mint
InitScript
RedeemScriptOutput
...More as added
The methods on the LedgerClient
trait should all be fallible.
Currently the CMLValidator
type (name not final) doesn't have an execute
implementation because we need to give it some way to evaluate locally.
Aiken provides a way to evaluate (and even cost) locally. We 100% should use it at least for evaluating Plutus scripts locally.
There are features in rust-fmt nightly that will automatically nest your imports. There might be other features as well that you can specify. This would tidy up a lot of files and would keep things tidy in the future.
https://github.com/blockfrost/blockfrost-rust
It looks like they've improved a lot since I originally looked and it doesn't make sense to maintain our own if that one is perfectly good. I'm not a fan of some of their choices--too many macros, but I don't really want to maintain a client when everyone else is gonna use that client.
The TxContext
is very underdeveloped right now. Part of that is I don't know how it fits in. For example, it might only be relevant to our local, test ledger clients, so it might get moved there.
I like to keep as much as possible inside the Naumachia domain, but it's looking like a lot needs to be in our specific implementations.
We should use cargo-workspaces
like they use in Aiken. Then we can keep track of changes in the Changelog and we don't need to bump the version with every commit.
Probably only matters on the live backends, but it would be good to include it on all of them.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.