diff --git a/contents/cap-0046/Stellar-contract.x b/contents/cap-0046/Stellar-contract.x index 7c5fe684a..d7f34b486 100644 --- a/contents/cap-0046/Stellar-contract.x +++ b/contents/cap-0046/Stellar-contract.x @@ -250,14 +250,14 @@ case NEGATIVE: enum SCContractCodeType { - SCCONTRACT_CODE_WASM = 0, + SCCONTRACT_CODE_WASM_REF = 0, SCCONTRACT_CODE_TOKEN = 1 }; union SCContractCode switch (SCContractCodeType type) { -case SCCONTRACT_CODE_WASM: - opaque wasm; +case SCCONTRACT_CODE_WASM_REF: + Hash wasm_id; case SCCONTRACT_CODE_TOKEN: void; }; diff --git a/core/cap-0046-02.md b/core/cap-0046-02.md index afa33b662..c4b07571f 100644 --- a/core/cap-0046-02.md +++ b/core/cap-0046-02.md @@ -14,7 +14,8 @@ Protocol version: TBD ``` ## Simple Summary -This proposal defines the structure of smart contracts on Stellar, and specifies + +This proposal defines the structure of smart contracts on Stellar and specifies how users can create them. ## Motivation and Goals Alignment @@ -22,279 +23,288 @@ how users can create them. See the Soroban overview CAP. ## Abstract + Users need a way to manage smart contracts on the network. This CAP allows users -to upload WASM code into a LedgerEntry. This CAP also lets the validators turn -off all smart contract functionality if some unexpected behavior is found in the -protocol. +to deploy the smart contracts to the network and specifies the supported +contract code kinds. + +This CAP also lets the validators turn off all smart contract functionality if +some unexpected behavior is found in the protocol. ## Specification ### XDR -See the XDR diffs in the Soroban overview CAP, specifically those covering -`InvokeHostFunctionOp`. +See the XDR diffs in the Soroban overview CAP, specifically those referring to +`HOST_FUNCTION_TYPE_CREATE_CONTRACT` and +`HOST_FUNCTION_TYPE_INSTALL_CONTRACT_CODE`. ## Semantics -### Creating a contract using InvokeHostFunctionOp -This CAP specifies a `create_contract_from_ed25519` host function, which will -create a new `ContractDataEntry` from -[CAP-0053](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0053.md) -with a `SCV_STATIC` key type, and `SCS_LEDGER_KEY_CONTRACT_CODE_WASM` key value. -The contractID will be the SHA-256 hash of a `HashIDPreimage`, with type -`ENVELOPE_TYPE_CONTRACT_ID_FROM_ED25519`, which contains a public key, and a -salt provided by the user. The `create_contract_from_ed25519` host function also -does some validation to ensure the contract and contractID are created securely. - -The `InvokeHostFunctionOp` operation from -[CAP-0052](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0052.md), -if used with `function = HostFunction::HOST_FN_CREATE_CONTRACT`, will call into -`create_contract_from_ed25519`. The `parameters` field should be populated with -a `ScVec` that contains the four `ScVal` parameters for -`create_contract_from_ed25519` (these are `contract`, `salt`, `key`, `sig`). - -Note that there is no nonce, so `create_contract_from_ed25519` can be replayed. This only -matters if we add functionality for deleting contracts, and we allow -contractID's to be reused. We don't want to allow reusable contractID's even -with removable contracts, so this shouldn't be an issue. - -The transaction will fail if a contract with the calculated contractID already -exists. - -TODO: Reserve requirement for `ContractDataEntry`? +### Contract structure -```rust -// Define CREATE_CONTRACT_SEPARATOR = -// "create_contract_from_ed25519(contract: Vec, salt: u256, key: u256, sig: Vec)" -// Verifies that sha256(params) was signed by key -// params = vec![CREATE_SEPARATOR, salt, contract] -// key = key -// sig = sig -// Creates a new contract. -fn create_contract_from_ed25519(contract: Vec, salt: Vec, key: u256, sig: Vec) -> ContractID; -``` +This defines the terms we use in the following sections without going into their +design and implementation details. -### Creating a contract within a contract -Factory contracts are quite popular already on other networks, so this CAP adds -functionality to support them. The contractID for these contracts are generated -a little differently than a contract created using `InvokeHostFunctionOp` for -simplicity. The `create_contract_from_contract` call will create the new -contractID by taking the SHA-256 hash of a `HashIDPreimage`, with type -`ENVELOPE_TYPE_CONTRACT_ID_FROM_CONTRACT`, which contains the creating contracts -contractID, and a salt that the creating contract passes to -`create_contract_from_contract`. +#### Contract source -`create_contract_from_contract` will trap if it is not called from within -another contract. +Contract source can be thought of as a 'class' of a contract. Multiple contracts +can share the same source, but have their own state. Thanks to that sharing +capability, we can reduce the amount of duplication in ledger and only store +unique contract sources. -Contract creators still have the option to use `create_contract_from_ed25519` if they choose to. -This can be helpful in factory contracts where the salt is specified by the -contract caller. +This CAP defines two possible kinds of contract sources: -```rust -// Can only be used inside another contract. Will use the creating contracts contractID. -fn create_contract_from_contract(contract: Vec, salt: Vec) -> ContractID -``` +- WASM source: a blob of WASM code that is stored in a separate ledger entry and + is deduplicated based on contents. This is installed to ledger by the users. +- Built-in contract: this is a 'source' compiled into host directly that has a + protocol-defined interface and behavior. + +#### Contract instance + +Contract instance can be thought of as an instance of the contract 'class'. +Contract instance consists of: + +- Identifier: SHA-256 hash of a pre-image payload +- Source reference: a pointer to the WASM source or a tag of a built-in + contract + +A contract instance may own an arbitrary amount of ledger entries attributed to +its identifier. Contracts that share the same source in no way may influence +each other; from the perspective of a contract invoker there is no difference +between calling the contracts with the same or different source references +(besides the possible contract-defined behavior differences). + +### Contract identifier preimage types + +This CAP defines the following supported contract identifier preimage kinds. The +use cases for every identifier type are described in the following sections. +Every preimage is a part of the `HashIDPreimage` union and has a unique tag +associated with it in order to ensure that there are no collisions with other +hashes in the protocol. + +- `ENVELOPE_TYPE_CONTRACT_ID_FROM_ED25519`: built from an `ed25519` public key + and the user-specified `uint256` salt. +- `ENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE_ACCOUNT`: built from a Stellar account + identifier and the user-specified `uint256` salt. +- `ENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET`: built from a Stellar `Asset` + structure. +- `ENVELOPE_TYPE_CONTRACT_ID_FROM_CONTRACT`: built from another contract + identifier and contract-specified `uint256` salt. + +Every preimage must also include a `networkID` (a hash of the network +passphrase) which ensures that every network has unique set of contract +identifiers. -TODO: How does this work with the new fee model? +### Installing WASM sources using `InvokeHostFunctionOp` -### Max contract size setting +WASM contract sources can be installed to the network without instantiating a +contract via `InvokeHostFunctionOp`(defined in [CAP-0046-04] +(./cap-0046-04.md)) with `HOST_FUNCTION_TYPE_INSTALL_CONTRACT_CODE` host +function type. + +This function accepts `InstallContractCodeArgs` struct that contains the WASM +contract code. + +Installed contracts are stored in `ContractCodeEntry` ledger entries. These +entries are keyed by the hash of `InstallContractCodeArgs` used to install +them. + +Contract installation host function will compute the hash of +`InstallContractCodeArgs` and check if such a contract code already exists. If +the entry exists, the operation will immediately succeed. If it doesn't, the +new `ContractCodeEntry` will be created. + +Host does not perform any validation on the installed contract code, besides +checking its size. + +#### Max contract size setting The maximum WASM contract size will be introduced as a `ConfigSettingEntry`(see -[CAP-0046-09] -(https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046-09.md) -for details on config entries). +[CAP-0046-09](./cap-0046-09.md) for details on config entries). It is set during the protocol version upgrade using a new `ConfigSettingEntry`, with `configSettingID` == `CONFIG_SETTING_CONTRACT_MAX_SIZE_BYTES`, and -`contractMaxSizeBytes` == `16384`. +`contractMaxSizeBytes` == `16384`. The valid values for +`contractMaxSizeBytes` are[0, 256000] (inclusive). + +#### No contract-driven WASM installation + +This CAP does not specify a way to install WASM sources from within a +contract. + +This is done to encourage efficient code reuse and deduplication: if the +contract was allowed to install the WASM code, then we'd need to store it +twice (in the installer contract and in the source entry). + +### Instantiating contracts using `InvokeHostFunctionOp` + +Contracts can be instantiated via `InvokeHostFunctionOp` with +`HOST_FUNCTION_TYPE_CREATE_CONTRACT` host function type. + +The function accepts `CreateContractArgs` struct that defines the input for +building the contract identifier preimage (`contractID` field) and the contract +source reference (`source` field). + +All the preimage types besides `ENVELOPE_TYPE_CONTRACT_ID_FROM_CONTRACT` can be +built from the `contractID` field. + +The source and identifier arguments are normally independent of each other with +an exception: identifiers that are built from `CONTRACT_ID_FROM_ASSET` may only +be used in conjunction with built-in token contract source. This handles the +special case of instantiating token contracts corresponding to the classic +Stellar assets (see more details in [CAP-0046-06](./CAP-0046-06.md)). + +The host builds the actual contract identifier by computing SHA-256 of the +`HashIDPreimage` corresponding to the `contractID`. If the contract identifier +already exists, the operation fails. + +If the identifier is new, the host will a new `ContractDataEntry` from[CAP-0053] +(./cap-0053.md) with a `SCV_STATIC` key type, and +`SCS_LEDGER_KEY_CONTRACT_CODE` key value. The value of the entry is +`SCContractCode` that either refers to the WASM code entry or to a built-in +contract (according to the value of `source` field in `CreateContractArgs`). + +#### ED25519-based contract identifiers + +Building a `ENVELOPE_TYPE_CONTRACT_ID_FROM_ED25519` preimage based on a public +ED25519 key has an a additional signature verification step as to make sure +that this key has authorized creating a contract on their behalf. + +The owner of the key must sign SHA-256 hash of `HashIDPreimage` of type +`ENVELOPE_TYPE_CREATE_CONTRACT_ARGS`, that includes the network id, `salt`, and +`CreateContractSource` args that must match the respective args of +`HOST_FUNCTION_TYPE_CREATE_CONTRACT` invocation. + +#### Installation fused with instantiation + +One of the possible types of `CreateContractSource` is +`CONTRACT_SOURCE_INSTALLED`, that accepts `InstallContractCodeArgs`. This is a +convenience argument that allows to install the code and instantiate a contract +using that code in a single operation. + +The installation implementation is exactly the same as for the case when +`HOST_FUNCTION_TYPE_INSTALL_CONTRACT_CODE` function is called. The contract +will be instantiated with WASM code reference source type that points to the +hash of the newly installed contract. + +As mentioned in the installation section, if the contract code already exists in +the ledger, the operation will still succeed, but no code entry will be +created. + +### Instantiating a contract from a contract + +Factory contracts are quite popular already on other networks, so this CAP adds +functionality to support them. + +The following host functions are provided to instantiate contracts: + +```rust +// Instantiates a contract with the source referring to the provided wasm_hash. +fn create_contract_from_contract(wasm_hash: Object /* 32-bytes array */, + salt: Object /* 32-bytes array */) -> Object /* 32-bytes array */ +// Instantiates a contract with the source referring to the built-in token. +fn create_token_from_contract(salt: Object /* 32-bytes array */) -> Object /* 32-bytes array */ +``` + +All of these functions return the identifier of the newly created contract. + +The identifier of the created contract is generated by hashing the +`HashIDPreimage` with type `ENVELOPE_TYPE_CONTRACT_ID_FROM_CONTRACT` with the +salt provided by the host function call. ### Validator override + This proposal adds two new `LedgerHeader` flags that can disable the create and -invoke contract operations using upgrades. The validators can use this mechanism -in case unexpected behaviour is seen. We also considered adding a mechanism for -validators to opt accounts into smart contracts to allow for a "soft" launch, -but the implementation changes to get this to work are not simple. The -validators have the `LedgerHeader` overrides to fall back on, so it's not clear -that the complexity of adding a "soft" launch mechanism is worth it. +invoke contract operations using upgrades. The validators can use this +mechanism in case unexpected behaviour is seen. We also considered adding a +mechanism for validators to opt accounts into smart contracts to allow for +a "soft" launch, but the implementation changes to get this to work are not +simple. The validators have the `LedgerHeader` overrides to fall back on, so +it's not clear that the complexity of adding a "soft" launch mechanism is worth +it. ## Design Rationale ### There are no built in controls for contracts + Controls like pausing invocation or mutability for all or a subset of a contract -should be put into a contract itself. Leaving it to the contract writer is a much -more general solution than baking it into the protocol. The downside is this is -more error prone and will take more space since the same logic will be +should be put into a contract itself. Leaving it to the contract writer is a +much more general solution than baking it into the protocol. The downside is +this is more error prone and will take more space since the same logic will be implemented multiple times. -### ContractDataEntry has no account associated with it -The account that creates the `ContractDataEntry` that contains the contract code +### `ContractDataEntry` has no owner associated with it + +The entity that creates the `ContractDataEntry` that contains the contract code is not tied to it in any way. This allows for contract management and -authorization to be handled in the contract using whichever custom mechanism the -contract creator chooses. +authorization to be handled in the contract using whichever custom mechanism +the contract creator chooses. + +### `ContractCodeEntry` has no owner associated with it + +Contract source code entries with the WASM code don't have any ownership. Anyone +can install contract sources to the ledger and then anyone can use them. This +encourages sharing the contract code and allows contracts that use it to be +sure that their implementation can't unexpectedly change. ### Contracts cannot be updated and deleted -The contract code is stored in a `ContractDataEntry`, but contract code cannot -be updated or deleted in the initial version. The host functions in -[CAP-0053](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0053.md#host-function-additions) -to update or delete `ContractDataEntry` should trap if they are used on contract -code. + +The contract code reference is stored in a `ContractDataEntry`, but contract +code cannot be updated or deleted in the initial version. The host functions in +[CAP-0046-05](./CAP-0046-05#host-function-additions) to update or delete +`ContractDataEntry` should trap if they are used on contract code. ### Malicious contracts + The validators do not have a mechanism to ban specific contracts. Any kind of targeted banning mechanism can be worked around quite easily by creating new accounts and contracts. ### Maximum WASM contract code size is configurable + The maximum contract size will be set during the protocol upgrade, and can be -updated by the validators. This limit should be enforced in the -`create_contract_from_ed25519` host function. +updated by the validators. This allows to adjust the contract sizes depending +on the demand and network load requirements. + +### ContractIDs are deterministic -### There are two ways to derive ContractIDs Pulling contractIDs from `LedgerHeader.idPool` would be easier but it would make parallelizing contract creation more difficult in the future. It's also more difficult to determine what the contractID will be since the id pool would be used by offers and other contracts. This CAP uses a `Hash` instead as the contractID. -You can either use `create_contract_from_ed25519` or -`create_contract_from_contract`. `create_contract_from_ed25519` is needed if it -is called from `InvokeHostFunctionOp` since there is no creating contract (and -therefore no existing contractID). It is also helpful in situations where the -salt is provided by the user in a factory contract. -`create_contract_from_ed25519` uses a ED25519 with signature verification, so -you can guarantee your contract ID won't be taken. -`create_contract_from_contract` can only be used from within another contract, -but it is much simpler since it just uses the creating contracts contractID and -a salt. +With this CAP we provide several ways of building the contractID preimages that +can be reproduced off-chain and then used to address the contracts that may or +may not exist (for example, some general contracts like tokens or AMMs). ## Security Concerns + The security concerns from CAP-0046 (https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046.md#security-concerns) -apply here as well. In addition to those concerns, this CAP does not provide -validators with much control over contracts on the network. The only mechanism -they have is blocking all contract creations and invocations, which should only -be used in drastic situations. This CAP does not define a way for validators to -block specific contracts. - -## Future Work - -### Mutable contract code - -We can allow contracts to be updated if we provide a host function and follow a few rules - - -- If a previous call in the call stack is from the modifying contract (e.g. A -> - B -> C -> B(update)) then the invocation should fail. -- An update should successfully terminate that contracts invocation, but the - caller can continue (e.g. A -> B(update). B terminates successfully on the - update host function call without running anything after, but A can continue. - If A calls B again in the same invocation, it will interact with the updated - contract) -- A new host function will be provided that takes the new contract code and a - return value as a parameter. This return value is required because the current - contract execution will be terminated after the `update_contract` call, but - the caller may still expect a return value. - ```rust - fn update_contract(contract: Vec, return_val: SCVal); - ``` - -### Contract metadata -A ContractMetadata union can accompany the WASM contract as another -`ContractDataEntry` with a new `SCV_STATIC` key type, which would specify the -functions available in the contract, along with the return and argument types -for each function. The host function to call into the WASM contract should first -validate the contract call against the metadata. If the contract call does not -match one of the functions specified in the metadata, then an error will be -thrown. - -Users can also load the ContractMetadata to see what the interface looks like. - -This metadata can be extended to include -versioning or the router logic mentioned at the end of this CAP. - -TODO: The xdr currently puts an arbitrary limit (10) on the number of function -signatures and arguments in the metadata. This needs to be revisited. - -```c++ -//SCST_BOOL will match against a SCStatic with either a SCS_TRUE or SCS_FALSE value -enum SCStaticTypeGroups -{ - SCST_VOID = 0, - SCST_BOOL = 1 -}; - -union SCType switch (SCValType type) -{ -case SCV_U63: -case SCV_U32: -case SCV_I32: - void; -case SCV_STATIC: - SCStaticTypeGroups staticGroups; -case SCV_OBJECT: - SCObjectType objType; -case SCV_SYMBOL: -case SCV_BITSET: -case SCV_STATUS: - void; -}; - -struct FunctionSignature -{ - SCSymbol function; - SCType returnType; - SCType argTypes<10>; -} - -enum ContractMetadataType -{ - METADATA_TYPE_V0 = 0 -}; - -union ContractMetadata switch (ContractMetadataType type) -{ -case METADATA_TYPE_V0: - FunctionSignature interface<10>; -}; +apply here as well. -``` -### Include a router along with the raw WASM -A router can be added as a `ContractDataEntry` with a new `SCV_STATIC` key type. - -- This has a couple advantages - - - A contract function that just calls into another contract can specify that - route in the router, allowing the initial contract to avoid spinning up a - WASM VM. - - Possible routes are - - - This contract - - External contract - - Host function - - This will allow contracts to build off the functionality of other contracts - without having to duplicate existing functionality, saving space on the - ledger. - -#### XDR - -```c++ -enum CallType -{ - SELF_CONTRACT = 0, - EXTERNAL_CONTRACT = 1, - HOST_FUNCTION = 2 -}; - -struct Route -{ - SCSymbol function; - - union switch (CallType v) - { - case EXTERNAL_CONTRACT: - Hash contractID; - case SELF_CONTRACT: - case HOST_FUNCTION: - void; - } callType; -} -``` +In addition to those concerns, this CAP does not provide validators with much +control over contracts on the network. The only mechanism they have is blocking +all contract creations and invocations, which should only be used in drastic +situations. This CAP does not define a way for validators to block specific +contracts. + +## Potential Future Work + +### Mutable contracts support + +While the contracts are immutable in this CAP, it's already possible to make +them 'mutable' via proxy contracts (for example, contract A forwards its +method calls to contract B and ID of contract B is stored in the data of +the contract A). + +To further support mutation via the proxy pattern we could do the following: +- Allow contract to modify its `SCS_LEDGER_KEY_CONTRACT_CODE` entry (as the + modification can only happen from within the contract, this would need to be + implemented in the first installed version of the contract) +- Allow specifying a contract ID as the contract's source reference, so that the + contract would be guaranteed to have exactly the same implementation as the + referred contract without any additional code. diff --git a/core/cap-0046.md b/core/cap-0046.md index 1f33da12f..cda99e2de 100644 --- a/core/cap-0046.md +++ b/core/cap-0046.md @@ -124,9 +124,30 @@ That calculates the following difference between the `src/protocol-curr` and `src/protocol-next` directories: ```diff mddiffcheck.ignore=true +diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xdr/Stellar-contract.x src/protocol-next/xdr/Stellar-contract.x +--- src/protocol-curr/xdr/Stellar-contract.x 2022-11-01 17:03:53.517489900 -0400 ++++ src/protocol-next/xdr/Stellar-contract.x 2022-11-01 19:59:58.500101500 -0400 +@@ -250,14 +250,14 @@ + + enum SCContractCodeType + { +- SCCONTRACT_CODE_WASM = 0, ++ SCCONTRACT_CODE_WASM_REF = 0, + SCCONTRACT_CODE_TOKEN = 1 + }; + + union SCContractCode switch (SCContractCodeType type) + { +-case SCCONTRACT_CODE_WASM: +- opaque wasm; ++case SCCONTRACT_CODE_WASM_REF: ++ Hash wasm_id; + case SCCONTRACT_CODE_TOKEN: + void; + }; diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xdr/Stellar-ledger-entries.x src/protocol-next/xdr/Stellar-ledger-entries.x --- src/protocol-curr/xdr/Stellar-ledger-entries.x 2022-11-01 19:19:35.769341600 -0400 -+++ src/protocol-next/xdr/Stellar-ledger-entries.x 2022-11-01 17:03:53.669248500 -0400 ++++ src/protocol-next/xdr/Stellar-ledger-entries.x 2022-11-02 12:16:24.349998800 -0400 @@ -3,11 +3,11 @@ // of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 @@ -140,18 +161,19 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd typedef opaque Thresholds[4]; typedef string string32<32>; typedef string string64<64>; -@@ -98,7 +98,9 @@ +@@ -98,7 +98,10 @@ OFFER = 2, DATA = 3, CLAIMABLE_BALANCE = 4, - LIQUIDITY_POOL = 5 + LIQUIDITY_POOL = 5, + CONTRACT_DATA = 6, -+ CONFIG_SETTING = 7 ++ CONTRACT_CODE = 7, ++ CONFIG_SETTING = 8 }; struct Signer -@@ -491,6 +493,23 @@ +@@ -491,6 +494,34 @@ body; }; @@ -161,6 +183,17 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd + SCVal val; +}; + ++struct ContractCodeEntry { ++ Hash hash; ++ opaque code; ++ union switch (int v) ++ { ++ case 0: ++ void; ++ } ++ ext; ++}; ++ +enum ConfigSettingID +{ + CONFIG_SETTING_CONTRACT_MAX_SIZE_BYTES = 0 @@ -175,18 +208,20 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd struct LedgerEntryExtensionV1 { SponsorshipDescriptor sponsoringID; -@@ -521,6 +540,10 @@ +@@ -521,6 +552,12 @@ ClaimableBalanceEntry claimableBalance; case LIQUIDITY_POOL: LiquidityPoolEntry liquidityPool; + case CONTRACT_DATA: + ContractDataEntry contractData; ++ case CONTRACT_CODE: ++ ContractCodeEntry contractCode; + case CONFIG_SETTING: + ConfigSettingEntry configSetting; } data; -@@ -575,6 +598,17 @@ +@@ -575,6 +612,22 @@ { PoolID liquidityPoolID; } liquidityPool; @@ -196,6 +231,11 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd + Hash contractID; + SCVal key; + } contractData; ++case CONTRACT_CODE: ++ struct ++ { ++ Hash hash; ++ } contractCode; +case CONFIG_SETTING: + struct + { @@ -204,7 +244,7 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd }; // list of all envelope types used in the application -@@ -589,6 +623,10 @@ +@@ -589,6 +642,11 @@ ENVELOPE_TYPE_SCPVALUE = 4, ENVELOPE_TYPE_TX_FEE_BUMP = 5, ENVELOPE_TYPE_OP_ID = 6, @@ -213,12 +253,13 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd + ENVELOPE_TYPE_CONTRACT_ID_FROM_ED25519 = 8, + ENVELOPE_TYPE_CONTRACT_ID_FROM_CONTRACT = 9, + ENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET = 10, -+ ENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE_ACCOUNT = 11 ++ ENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE_ACCOUNT = 11, ++ ENVELOPE_TYPE_CREATE_CONTRACT_ARGS = 12 }; } diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xdr/Stellar-ledger.x src/protocol-next/xdr/Stellar-ledger.x --- src/protocol-curr/xdr/Stellar-ledger.x 2022-11-01 19:19:35.769341600 -0400 -+++ src/protocol-next/xdr/Stellar-ledger.x 2022-11-01 17:03:53.670267500 -0400 ++++ src/protocol-next/xdr/Stellar-ledger.x 2022-11-01 19:44:03.183849200 -0400 @@ -47,13 +47,17 @@ ext; }; @@ -402,7 +443,7 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd } diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xdr/Stellar-overlay.x src/protocol-next/xdr/Stellar-overlay.x --- src/protocol-curr/xdr/Stellar-overlay.x 2022-11-01 19:19:35.770344000 -0400 -+++ src/protocol-next/xdr/Stellar-overlay.x 2022-11-01 17:04:28.632486900 -0400 ++++ src/protocol-next/xdr/Stellar-overlay.x 2022-11-01 19:44:25.869507400 -0400 @@ -83,7 +83,7 @@ uint32 numFailures; }; @@ -440,7 +481,7 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd Only in src/protocol-curr/xdr: Stellar-overlay.x.bak diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xdr/Stellar-transaction.x src/protocol-next/xdr/Stellar-transaction.x --- src/protocol-curr/xdr/Stellar-transaction.x 2022-11-01 19:19:35.771360700 -0400 -+++ src/protocol-next/xdr/Stellar-transaction.x 2022-11-01 17:03:53.520503800 -0400 ++++ src/protocol-next/xdr/Stellar-transaction.x 2022-11-03 14:34:08.450342900 -0400 @@ -2,6 +2,7 @@ // under the Apache License, Version 2.0. See the COPYING file at the root // of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 @@ -473,27 +514,91 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd }; /* CreateAccount -@@ -465,6 +474,27 @@ +@@ -465,6 +474,91 @@ int64 minAmountB; // minimum amount of second asset to withdraw }; -+enum HostFunction ++enum HostFunctionType ++{ ++ HOST_FUNCTION_TYPE_INVOKE_CONTRACT = 0, ++ HOST_FUNCTION_TYPE_CREATE_CONTRACT = 1, ++ HOST_FUNCTION_TYPE_INSTALL_CONTRACT_CODE = 2 ++}; ++ ++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 ++}; ++ ++struct InstallContractCodeArgs ++{ ++ opaque code; ++}; ++ ++enum CreateContractSourceType { ++ CONTRACT_SOURCE_REF = 0, ++ CONTRACT_SOURCE_INSTALLED = 1 ++}; ++ ++union CreateContractSource switch (CreateContractSourceType type) ++{ ++case CONTRACT_SOURCE_REF: ++ SCContractCode codeRef; ++case CONTRACT_SOURCE_INSTALLED: ++ InstallContractCodeArgs installContractCodeArgs; ++}; ++ ++union ContractIDPublicKey switch (ContractIDPublicKeyType type) ++{ ++case CONTRACT_ID_PUBLIC_KEY_SOURCE_ACCOUNT: ++ void; ++case CONTRACT_ID_PUBLIC_KEY_ED25519: ++ struct ++ { ++ uint256 key; ++ Signature signature; ++ } ed25519KeyWithSignature; ++}; ++ ++union ContractID switch (ContractIDType type) +{ -+ HOST_FN_INVOKE_CONTRACT = 0, -+ HOST_FN_CREATE_CONTRACT_WITH_ED25519 = 1, -+ HOST_FN_CREATE_CONTRACT_WITH_SOURCE_ACCOUNT = 2, -+ HOST_FN_CREATE_TOKEN_CONTRACT_WITH_SOURCE_ACCOUNT = 3, -+ HOST_FN_CREATE_TOKEN_CONTRACT_WITH_ASSET = 4 ++case CONTRACT_ID_FROM_PUBLIC_KEY: ++ struct ++ { ++ ContractIDPublicKey keySource; ++ uint256 salt; ++ } publicKey; ++case CONTRACT_ID_FROM_ASSET: ++ Asset asset; ++}; ++ ++struct CreateContractArgs ++{ ++ ContractID contractID; ++ CreateContractSource source; ++}; ++ ++union HostFunction switch (HostFunctionType type) ++{ ++case HOST_FUNCTION_TYPE_INVOKE_CONTRACT: ++ SCVec invokeArgs; ++case HOST_FUNCTION_TYPE_CREATE_CONTRACT: ++ CreateContractArgs createContractArgs; ++case HOST_FUNCTION_TYPE_INSTALL_CONTRACT_CODE: ++ InstallContractCodeArgs installContractCodeArgs; +}; + +struct InvokeHostFunctionOp +{ + // The host function to invoke + HostFunction function; -+ -+ // Parameters to the host function -+ SCVec parameters; -+ + // The footprint for this invocation + LedgerFootprint footprint; +}; @@ -501,7 +606,7 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd /* An operation is the lowest unit of work that a transaction does */ struct Operation { -@@ -523,6 +553,8 @@ +@@ -523,6 +617,8 @@ LiquidityPoolDepositOp liquidityPoolDepositOp; case LIQUIDITY_POOL_WITHDRAW: LiquidityPoolWithdrawOp liquidityPoolWithdrawOp; @@ -510,34 +615,48 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd } body; }; -@@ -545,6 +577,26 @@ +@@ -545,6 +641,40 @@ PoolID liquidityPoolID; Asset asset; } revokeID; +case ENVELOPE_TYPE_CONTRACT_ID_FROM_ED25519: + struct + { ++ Hash networkID; + uint256 ed25519; + uint256 salt; + } ed25519ContractID; +case ENVELOPE_TYPE_CONTRACT_ID_FROM_CONTRACT: + struct + { ++ Hash networkID; + Hash contractID; + uint256 salt; + } contractID; +case ENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET: -+ Asset fromAsset; ++ struct ++ { ++ Hash networkID; ++ Asset asset; ++ } fromAsset; +case ENVELOPE_TYPE_CONTRACT_ID_FROM_SOURCE_ACCOUNT: + struct + { ++ Hash networkID; + AccountID sourceAccount; + uint256 salt; + } sourceAccountContractID; ++case ENVELOPE_TYPE_CREATE_CONTRACT_ARGS: ++ struct ++ { ++ Hash networkID; ++ CreateContractSource source; ++ uint256 salt; ++ } createContractArgs; }; enum MemoType -@@ -1588,6 +1640,25 @@ +@@ -1588,6 +1718,25 @@ void; }; @@ -563,7 +682,7 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd /* High level Operation Result */ enum OperationResultCode { -@@ -1654,6 +1725,8 @@ +@@ -1654,6 +1803,8 @@ LiquidityPoolDepositResult liquidityPoolDepositResult; case LIQUIDITY_POOL_WITHDRAW: LiquidityPoolWithdrawResult liquidityPoolWithdrawResult; @@ -574,7 +693,7 @@ diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xd case opBAD_AUTH: diff -ru '--exclude=*.h' '--exclude=.git*' '--exclude=*.md' src/protocol-curr/xdr/Stellar-types.x src/protocol-next/xdr/Stellar-types.x --- src/protocol-curr/xdr/Stellar-types.x 2022-11-01 19:19:35.771360700 -0400 -+++ src/protocol-next/xdr/Stellar-types.x 2022-11-01 17:03:53.520503800 -0400 ++++ src/protocol-next/xdr/Stellar-types.x 2022-11-01 19:44:03.008942400 -0400 @@ -79,6 +79,7 @@ typedef opaque SignatureHint[4];