-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
XDR side of the contract deployment changes specified in CAP-46-02. #51
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The structure of the new types is somewhat ambiguous as to how to use them. Some questions inline about it.
Stellar-transaction.x
Outdated
enum ContractIDType | ||
{ | ||
CONTRACT_ID_FROM_PUBLIC_KEY = 0, | ||
CONTRACT_ID_FROM_ASSET = 1 | ||
}; | ||
|
||
enum ContractIDPublicKeyType | ||
{ | ||
CONTRACT_ID_PUBLIC_KEY_SOURCE_ACCOUNT = 0, | ||
CONTRACT_ID_PUBLIC_KEY_ED25519 = 1 | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This relationship feels a bit backwards. It suggests a source account is a public key, when a source account contains a public key. Could "source account" be a ContractIDType
variant instead? Then you don't need as much nesting. Nesting comes at a XDR size cost, and hierarchies make more assumptions about the future. It doesn't appear to offer a ton of value in this case. Am I missing something of value there?
enum ContractIDType | |
{ | |
CONTRACT_ID_FROM_PUBLIC_KEY = 0, | |
CONTRACT_ID_FROM_ASSET = 1 | |
}; | |
enum ContractIDPublicKeyType | |
{ | |
CONTRACT_ID_PUBLIC_KEY_SOURCE_ACCOUNT = 0, | |
CONTRACT_ID_PUBLIC_KEY_ED25519 = 1 | |
}; | |
enum ContractIDType | |
{ | |
CONTRACT_ID_FROM_SOURCE_ACCOUNT = 0, | |
CONTRACT_ID_FROM_PUBLIC_KEY_ED25519 = 1, | |
CONTRACT_ID_FROM_ASSET = 2 | |
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use nesting for the sake of avoiding duplication and to represent the logical structure of the data. Any kind of id inherited from a public key would contain salt, but the source of the public key itself might be different. If we add one more type of a public key in the future, it would just go into ContractIDPublicKeyType
enum and will by definition have the salt.
I'm not feeling too strongly about that though and I agree the difference is pretty marginal. If that apparently doesn't improve clarity, we can remove the nesting as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any kind of id inherited from a public key would contain salt
This is an assumption. I don't think we know if it would be true for all ways we create contracts from public keys. This is what I mean by:
hierarchies make more assumptions about the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two ways to do a thing is confusing to me, and I struggle to see us actually promoting both ways in docs. See inline comment.
case HOST_FUNCTION_TYPE_CREATE_CONTRACT: | ||
CreateContractArgs createContractArgs; | ||
case HOST_FUNCTION_TYPE_INSTALL_CONTRACT_CODE: | ||
InstallContractCodeArgs installContractCodeArgs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels like an unnecessary optimization to support two ways to install contracts. Developers are going to want to be told one way to do it for 99% of the time. In our docs, we will want to describe one way and not have to tell a long story about when to use either way.
If installing separately is a critical feature we need, could we make that the only way to upload code? Two ops are a small cost, so we should instead make it trivial to do two ops, one install, one create.
If the ref is just a sha256, that's a small lift to require developers to provide in the second operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still a bit concerned about the multi-op transactions and creating a contract with a single operation seems important enough to have this as a precaution if we come back to single op.
Adding or removing this seems pretty easy, I would probably keep this around until we have decided on multi-op txs, but I could remove this for now if you feel strongly about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I defer to @sisuresh.
But if we are concerned about multi-op transactions, then it feels like the contract lifecycle story as a whole has some holes, because last I remember we're planning to rely on multi-op for atomic initialization. Or is that still undecided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the potential risk with multi-op transactions is that the fee model won't work or will become more difficult to get right. For this reason, we should be careful about making decisions off of this. We may need to add functionality for atomic initializations if the multi-op experiment doesn't work out.
But if we do want a single way to install a contract, why do both operations need to be in the same transaction? The install and create need to run sequentially, but not atomically, so you could use two separate transactions instead right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may actual expose my lack of knowledge with Horizon - Is it easy to "batch" submit two transactions? Or is the typical flow submit tx1 -> ack tx1 in ledger -> submit tx2
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if we do want a single way to install a contract, why do both operations need to be in the same transaction?
I guess that's mostly a UX thing here.
Horizon should I think deliver both transactions into the same ledger if it can,
It can do this now because we perform a significant effort to allow multiple txs from the same account per ledger. That's pretty hard to maintain and given that eventually we may want to execute soroban txs in parallel, we may not even start supporting that behavior for soroban txs even in V1. That's still TBD, but definitely something to keep in mind.
Given the feedback, I'll remove this for now. Returning both atomic installation and initialization will be a simple incremental change if we need it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this is helpful perspectives. I think separate operations for install and create only work if we can do them in a single tx from a DX point-of-view. Maybe the unnecessary piece is the ability to install without creating, even though that sounds more logically pure.
Given the feedback, I'll remove this for now.
So it's clear, which piece is being removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the fused install option for now. I agree we should come back to it if we can't make multi-op work (the same applies to the initializers).
While install without create doesn't seem to be needed in the most of the cases, it supports the contract factories in a pretty clean fashion: you would need to install the source(s) to instantiate with the factory, install the source of the factory, then instantiate the factory contract (preferably all in the same tx if we can make it). So if we don't have a separate, then the developer would need to instantiate some throw-away contracts. I don't have intuition on usefulness of the factories (given that a non-empty set of their use-cases is already covered by decoupling the source from instance), but since we can easily come up with a use case, it doesn't feel right to make it awkward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I wouldn't feel too bad if we had two options and promoted the fused option for the general use case, but have a separate documentation on 'contract factories' that refers to install specifically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, yeah this sounds fine and we can iterate on this again if the multiop doesn't work out.
HOST_FN_CREATE_TOKEN_CONTRACT_WITH_SOURCE_ACCOUNT = 3, | ||
HOST_FN_CREATE_TOKEN_CONTRACT_WITH_ASSET = 4 | ||
HOST_FUNCTION_TYPE_INVOKE_CONTRACT = 0, | ||
HOST_FUNCTION_TYPE_CREATE_CONTRACT = 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand this correctly, we can call these three "host functions" from InvokeHostFunctionOp
, but contracts won't necessarily have the same access. For example, it doesn't sound like contracts have access to HOST_FUNCTION_TYPE_CREATE_CONTRACT
. Does the naming here make sense then? Should HOST_FUNCTION
still be used here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's something I've been wondering about too. Currently we have this referring actual host functions that are exposed through the env, but are prohibited to be called from the contracts. I think that is confusing. Now I'm using XDR which is easier to pass around (given any sort of complexity in argument structure), but also now I wouldn't even expose anything via env (which I think makes sense given that it wouldn't be usable anyway). So indeed calling this 'host function' feels weird.
I see the following options:
- With the current auth approach I would probably rename this to something else to not create confusion. Not sure what though. Also both this and 'invoke' would need to be renamed
- If we unify the auth approach, then we will be able to just expose the same functions to the contracts, so they would be able to perform the same operations. Then the naming will be legitimate. But that's contingent on where we end up with auth.
FWIW I'm not a big fan of the op name in either case (as it seems overly specific to implementation vs referring to smart contracts). Any ideas on better names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The invoke-host-function-invoke-contract-function nested concept is not particularly fun to explain to folks either in person, or in docs.
I don't feel strongly about where this goes, but I suspect from a developer experience point-of-view if we are adding XDR types – which is attractive – we could considering having separate operations for each Soroban operation, which falls in line with historically what we've done, and has some benefits for ingesting applications that categorize based on operation type (this isn't something that needs to drive any decision, just noting alignment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could just remove the HOST_FUNCTION_TYPE*
. You've already done a good job of abstracting away the host function details by no longer requiring the user to pass the exact ScVec
parameters that get passed to the host function. So why even keep the concept of host functions here?
Separate operations is an interesting idea, and one that would be easy to do. One of the advantages of a single op with different options is that we don't need to plumb each new operation through core as we iterate. This is not that big of a deal, so I'm not opposed to separate operations if we see the benefit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate ops is something to consider before V1, but that's a relatively significant change from the core standpoint (in terms of diffs etc, not necessarily in terms of complexity). I would propose to not try doing that within this PR to keep the reviews focused on one thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree - separate ops should not be part of this PR and require further discussion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually suggest to also do the renaming separately for the same reason (unless we only rename the enum; but then the op name itself will be confusing). There is a significant amount of diffs in core/host related only to the deployment changes and I don't want to additionally mix it with no-op renaming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me.
This introduces the ledger entries to store the wasm code and also changes the host functions to support creating/installing the contracts.
This relies on the ability to include multiple Soroban operations in the transaction. We can bring this back if we decide against that.
Since we seem to have agreed to keep the naming for now and do the renaming separately, is there anything else that needs to be addressed before merge? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dmkozh LGTM
* Initial commit * Create check.yml (#2) Defines the 'complete' status check. * populate (#1) * Incorporate CAP-42 changes (#3) * Pick up Stellar-internal.x (#4) * add .gitignore (#5) * Absorb changes from rs-stellar-xdr repo (#7) * Flatten contract spec discriminants (#8) * Namespace the contract spec types (#9) * Delete Stellar-contract-meta.x (#12) * CAP-0047 - update names (#6) * Fix contract spec definitions after rename (#13) * Add contract meta types (#10) * Rename BINARY to BYTES (#16) * Add SCContractCode and update related types (#17) * Add names to function inputs in contract spec (#18) * Pick up persistent state changes (#19) * Fix repeated errorCode in SCStatus (#20) * Pick up changes incorrectly committed to rs-stellar-xdr (#21) * Add rest of CAP-0056 (#22) * Add BytesN as type (#23) * Add Val as a spec type (#25) * Add name of lib to struct and union spec entries (#26) * Add adverts & demands to StellarMessage (#24) * Add SST_CONTRACT_ERROR to SCStatusType (#29) * Remove `ScHash` and `PublicKey` from object type. (#31) * Add enum as a contract spec type (#34) * Add error enum as a distinct UDT type from enum (#35) * Add SCVal success to INVOKE_HOST_FUNCTION_SUCCESS, fix stellar/stellar-protocol#1307 (#36) * Updated xdr for token wrapper and source auth (#37) * add ENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET * add new HostFunction type and HashIDPreimage for using the source account in the host * add missing enum value (#38) * rename HOST_FN_CREATE_CONTRACT (#39) * Add invoker to contract spec (#40) * Add account id as object type (#41) * Rename HOST_FN_CREATE_CONTRACT_WITH_SOURCE to HOST_FN_CREATE_CONTRACT_WITH_SOURCE_ACCOUNT (#42) * Rename ENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE to ENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE_ACCOUNT (#43) * Rename sourceContractID to sourceAccountContractID (#44) * Add AccountID as type to contract spec (#45) * move AccountID to avoid circular reference (#46) * Add new host functions to xdr (#47) * Add new host functions to xdr * rename * Trivial whitespace changes to Stellar-overlay.x to sync with curr (#50) * XDR side of the contract deployment changes specified in CAP-46-02. (#51) * XDR side of the contract deployment changes specified in CAP-46-02. This introduces the ledger entries to store the wasm code and also changes the host functions to support creating/installing the contracts. * Remove option to create and install contract in the same operation. This relies on the ability to include multiple Soroban operations in the transaction. We can bring this back if we decide against that. * Replace BigInt object with {iu}128 (#57) * Bigint to int128 cont'd -- spec changes (#58) * Migrate SC_SPEC from BIG_INT to {IU}128 * Make events a list of lists so we can associate events with their operation (#59) * Make events a list of lists so we can associate events with their operation * Add a OperationEvents struct * Update overlay XDR (#62) * XDR changes for Auth Next. (#65) - Introduce the `ScAddress` type to generically represent the address in contracts - Introduce structured authorization data and structured signature payload to use for auth in contracts * Add fields for docs to the contract spec (#66) * Make unit/void case explicit and support more tuples in union spec (#67) * Make unit/void case explicit and support more tuples in union spec * avoid void * Fix syntax (#68) * Add auth errors (#69) * Add auth errors * fixup! Add auth errors * Add nonce to the signature payload (#71) * Preliminary "remove objects from XDR" change (#70) * Add diagnosticEvents (#74) * XDR for upgradeable config entries (#75) * Generalize configuration-related XDR. The changes here are summarized in proposed updated to CAP-47 (stellar/stellar-protocol#1291). - Use unique keys to identify settings - Only distribute a hash for config upgrades in `StellarValue` - Add SCP messages for exchanging config upgrade sets * Remove unused ConfigSetting --------- Co-authored-by: Dmytro Kozhevin <[email protected]> * Fix U/I128 and U/I256 number representation for consistent sorting (#78) * Fix 128 and 256 bits number representation * fixup! Fix 128 and 256 bits number representation * Add fee and limit-related configuration XDR based on CAP-0046-07. (#79) Co-authored-by: Graydon Hoare <[email protected]> * add config setting for host logic version (#80) * Meta xdr (#82) * Add XDR types for contract meta * generic * Update Stellar-contract-meta.x Co-authored-by: Leigh McCulloch <[email protected]> * Update Stellar-contract-meta.x * Update Stellar-contract-meta.x --------- Co-authored-by: Leigh McCulloch <[email protected]> * Define config settings for contract costs (#81) * Define cost parameters * fixup! Define cost parameters * Move config settings to separate file * Remove spaces * Add stellar namespace * Transaction changes to support Soroban fee model. (#84) * Transaction changes to support Soroban fee model. - Moved all the resources (including the footprint) to the transaction level. - Added host fn batching to compensate for removal of multi-operation tx support - Did some passing-by naming cleanup (as we never really have time for that) * Back out the host logic version config setting, will not use it (#85) * Change cost param type to int64 (#87) * Add config settings for contract data limits (#90) * Add `txSOROBAN_RESOURCE_LIMIT_EXCEEDED` to the respective structs. (#91) * Remove all TransactionResultSetV2 related changes and puts the hash of the events and return values in InvokeHostFunctionResult (#83) * Remove all TransactionResultSetV2 related changes and puts the hash of TxHashOfMetaHashesSet in the new LedgerHeaderExtensionV2 * Remove hashing of tx meta components * Remove nested events now that we only have one op per tx * Return hash of events and return values in InvokeHostFunctionResult * Err reform (#92) * Remove comment with improbable suggestion * Simplify error codes * update overlay xdr (#94) * update overlay xdr * Add comment * Replace ContractAuth addressWithNonce option with explicit union (#88) * Replace ContractAuth addressWithNonce option with explicit union (#88) * Move ContractAuth signatureArgs into Authorization (#89) * Remove trailing , (#97) * Changes to auth-related XDR and a bit of cleanup. (#95) * Changes to auth-related XDR and a bit of cleanup. - Prepare create contract host fn for using auth next - Get rid of unnecessary envelopes - Passing-by cleanup: get rid of `SCVAL_LIMIT`. * Rename `HostFunctionArgs` back to just `HostFunction`. * Use `ScAddress` to identify contracts in auth payload. * Revert invoke host fn return value to be a single value. (#98) * One more update to return value. (#99) * State expiration (#93) * Adds support for state expiration * Cleanup and refactoring * Added rent fees and revert footprint changes * Get rid of floating point math for rent fees * Add changes for env * Adapt names to recent consensus on state expiration terminology * Add state expiration related entries to LedgerCloseMeta as v2 * Move extension point to front of structure. --------- Co-authored-by: Graydon Hoare <[email protected]> Co-authored-by: Siddharth Suresh <[email protected]> * Make `returnValue` optional in meta. (#100) * Make `returnValue` optional in meta. This is meaningless for non-Soroban txs. * Make whole soroban tx meta optional. Also did some small extension point cleanup. * Add execution lanes config (#101) * Add tx limit * Minor naming tweak * Small XDR fix. (#102) * Add costs for new cryptography host functions (#105) * Switch Soroban nonces from autoincrement to random values with signature expiration. (#103) * Expiration bump op (#106) * bump op * Update thresholds * Remove mergeable (#108) * back out ContractCostType::VerifyEcdsaSecp256k1Sig, keeping Recover (#109) * Add cost types for int256 arithmetics (#110) * Add footprint to bump expiration name (#111) * Remove Op postfix for result code (#113) * Add support for contract instance storage. (#115) - Store contract instance that includes executable and storage map under a special key - Make contract executable separate from ScVal * Add `VmCachedInstantiation` for future use (#116) * Update XDR comments (#117) * Remove ContractDataType from ScVal and rename (#118) * Adds expiration iterator (#104) * Adds expiration iterator * Add BucketList size window and remove eviction iterator * XDR for RestoreFootprintOp (#120) * XDR for RestoreFootprintOp * Use extension point instead * Replace 'restorable' -> 'persistent' for state expiration config to match new terminology (#114) * Fix comment (#121) * Add error when accessing expired entry (#122) * Refactor config XDR to account for dynamic write fees. (#123) - Remove the flat fee - Rename the fields that contribute to the write fee for clarity * Soroban tx set size upgrade support and XDR cleanup. (#124) - Use dedicated struct for `InvokeContract` host fn - Replace `ScVec` with `SCVal` or `SCVal<>` depending on the context * Make SCError into a union to allow user errors to be u32 (#125) * Remove incorrect comment about Soroban u256 representation (#126) * Change metadata fee config to only account for contract events. (#127) Also renamed a couple tx-size related fields for clarity. * Update `SorobanResources` for consistency with config update. (#128) * One more metadata->events rename. (#129) * Adds eviction iterator (#130) * Remove `ContractCostType::GuardFrame` (#131) * Clean up and clearify some `ContractCostType`s (#133) * Add an error for exceeding refundable fee. (#134) * Add errors for exceeding the refundable fee. These have to be operation errors, as core is hard-wired to only return `txFAILED` on transaction failure and modifying this behavior is risky/slow. * Remove `contractEventsSizeBytes` from `SorobanResources`. This field is almost redundant and only helps to avoid apply-time error in the rare cases when the user sets the events resource, but forgets to set high enough refundable fee. It does, on the other hand, introduce another apply-time failure condition if the contracts emits a bit more events than expected (even if the refundable fee is high enough to cover that). The total size of the events emitted is still governed by the network setting. * Remove ScSpecTypeSet and SC_SPEC_TYPE_SET (#136) * Expiration Entry rework (#137) * typo (#139) * expand SCError comments, no functional change (#140) * expand SCError comments, no functional change * Update Stellar-contract.x Co-authored-by: Siddharth Suresh <[email protected]> --------- Co-authored-by: Siddharth Suresh <[email protected]> * rename txSOROBAN_RESOURCE_LIMIT_EXCEEDED to more general txSOROBAN_INVALID (#143) * Update .github/workflows/check.yml Co-authored-by: Graydon Hoare <[email protected]> --------- Co-authored-by: stellar-terraform <[email protected]> Co-authored-by: Graydon Hoare <[email protected]> Co-authored-by: Leigh McCulloch <[email protected]> Co-authored-by: jonjove <[email protected]> Co-authored-by: mlo <[email protected]> Co-authored-by: Hidenori <[email protected]> Co-authored-by: Jay Geng <[email protected]> Co-authored-by: Dmytro Kozhevin <[email protected]> Co-authored-by: Paul Bellamy <[email protected]> Co-authored-by: mlo <[email protected]> Co-authored-by: Garand Tyson <[email protected]> Co-authored-by: Jay Geng <[email protected]> Co-authored-by: Brian Anderson <[email protected]>
This introduces the ledger entries to store the wasm code and also changes the host functions to support creating/installing the contracts.
See stellar/stellar-protocol#1315 for the general overview of the changes.