Skip to content

Latest commit

 

History

History
705 lines (645 loc) · 20.1 KB

cap-0046.md

File metadata and controls

705 lines (645 loc) · 20.1 KB

Preamble

CAP: 0046
Title: Soroban smart contract system overview
Working Group:
    Owner: Graydon Hoare <@graydon>
    Authors: Graydon Hoare <@graydon>, Siddharth Suresh <@sisuresh>, Dmytro Kozhevin <@dmkozh>, Jay Geng <@jayz22>
    Consulted: Leigh McCulloch <@leighmcculloch>, Tomer Weller <@tomerweller>, Jon Jove <@jonjove>, Nicolas Barry <@MonsieurNicolas>, Thibault de Lacheze-Murel <@C0x41lch0x41>
Status: Draft
Created: 2022-10-27
Discussion: 
Protocol version: TBD

Simple Summary

This CAP is an overview of changes to stellar-core and the Stellar Protocol needed to enable the Soroban smart contract system.

Various aspects of the system design are described in Soroban "sub-CAPs". This "overview CAP" exists to

  • Discuss motivation and design choices across the overall project, to avoid repeating it in each sub-CAP.
  • Give a cumulative XDR diff covering changes made in all related CAPs, to ease the burden of keeping the XDR diff current during development.
  • Link to and describe the relationships between sub-CAPs and the XDR changes.

Working Group

The authors of the linked sub-CAPs are members of SDF's core team. Each sub-CAP lists an owner.

Consultation on the Soroban project's core design necessarily encompasses a large proportion of the Stellar ecosystem. It has included and will continue to include members of the Horizon team, the Security team, the teams building the Soroban SDK, CLI and RPC server, Stellar and Soroban SDK developers, Soroban contract and application developers, and Stellar network validator operators.

Motivation

The Stellar Network currently supports a rich but fixed repertoire of transactions. Developers have indicated this repertoire is insufficiently flexible in adapting to new application needs, and wish to be able to submit custom turing-complete code to run in the transaction-execution phase of the network.

The Soroban project provides such an ability, through mechanisms specified in the various sub-CAPs linked from this CAP. Each sub-CAP specifies its relationship to the whole Soroban project and, where necessary, links to other sub-CAPs that it depends on or interacts with.

Goals Alignment

This CAP is aligned with the following Stellar Network Goals:

  • The Stellar Network should make it easy for developers of Stellar projects to create highly usable products

Abstract

Soroban adds a platform for execuiting smart contracts to the Stellar network.

It is small, simple, efficient, and based on standardized technology, leveraging standard tools and techniques whenever possible, and focusing on providing a high-quality and low-effort developer experience for writing smart contracts.

Specification

All specifications besides the cumulative XDR diffs below are provided in the following sub-CAPs:

XDR changes

There are three entirely new XDR files:

As well as updates to several of the other XDR files, which are maintained and modified on an ongoing basis during the development of Soroban in a separate, parallel src/protocol-next directory within the [stellar-core repository].

The diff showing the updates is therefore not generated by git diff, but by running the following command:

diff -ru --exclude='*.h' --exclude='.git*' --exclude='*.md' src/protocol-{curr,next}/xdr

That calculates the following difference between the src/protocol-curr and src/protocol-next directories:

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<SCVAL_LIMIT>;
+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-02 12:16:24.349998800 -0400
@@ -3,11 +3,11 @@
 // of this distribution or at http://www.apache.org/licenses/LICENSE-2.0
 
 %#include "xdr/Stellar-types.h"
+%#include "xdr/Stellar-contract.h"
 
 namespace stellar
 {
 
-typedef PublicKey AccountID;
 typedef opaque Thresholds[4];
 typedef string string32<32>;
 typedef string string64<64>;
@@ -98,7 +98,10 @@
     OFFER = 2,
     DATA = 3,
     CLAIMABLE_BALANCE = 4,
-    LIQUIDITY_POOL = 5
+    LIQUIDITY_POOL = 5,
+    CONTRACT_DATA = 6,
+    CONTRACT_CODE = 7,
+    CONFIG_SETTING = 8
 };
 
 struct Signer
@@ -491,6 +494,34 @@
     body;
 };
 
+struct ContractDataEntry {
+    Hash contractID;
+    SCVal key;
+    SCVal val;
+};
+
+struct ContractCodeEntry {
+    Hash hash;
+    opaque code<SCVAL_LIMIT>;
+    union switch (int v)
+    {
+    case 0:
+        void;
+    }
+    ext;
+};
+
+enum ConfigSettingID
+{
+    CONFIG_SETTING_CONTRACT_MAX_SIZE_BYTES = 0
+};
+
+union ConfigSettingEntry switch (ConfigSettingID configSettingID)
+{
+case CONFIG_SETTING_CONTRACT_MAX_SIZE_BYTES:
+    uint32 contractMaxSizeBytes;
+};
+
 struct LedgerEntryExtensionV1
 {
     SponsorshipDescriptor sponsoringID;
@@ -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 +612,22 @@
     {
         PoolID liquidityPoolID;
     } liquidityPool;
+case CONTRACT_DATA:
+    struct
+    {
+        Hash contractID;
+        SCVal key;
+    } contractData;
+case CONTRACT_CODE:
+    struct
+    {
+        Hash hash;
+    } contractCode;
+case CONFIG_SETTING:
+    struct
+    {
+        ConfigSettingID configSettingID;
+    } configSetting;
 };
 
 // list of all envelope types used in the application
@@ -589,6 +642,11 @@
     ENVELOPE_TYPE_SCPVALUE = 4,
     ENVELOPE_TYPE_TX_FEE_BUMP = 5,
     ENVELOPE_TYPE_OP_ID = 6,
-    ENVELOPE_TYPE_POOL_REVOKE_OP_ID = 7
+    ENVELOPE_TYPE_POOL_REVOKE_OP_ID = 7,
+    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_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 19:44:03.183849200 -0400
@@ -47,13 +47,17 @@
     ext;
 };
 
-const MASK_LEDGER_HEADER_FLAGS = 0x7;
+const MASK_LEDGER_HEADER_FLAGS = 0x7F;
 
 enum LedgerHeaderFlags
 {
     DISABLE_LIQUIDITY_POOL_TRADING_FLAG = 0x1,
     DISABLE_LIQUIDITY_POOL_DEPOSIT_FLAG = 0x2,
-    DISABLE_LIQUIDITY_POOL_WITHDRAWAL_FLAG = 0x4
+    DISABLE_LIQUIDITY_POOL_WITHDRAWAL_FLAG = 0x4,
+    DISABLE_CONTRACT_CREATE = 0x8,
+    DISABLE_CONTRACT_UPDATE = 0x10,
+    DISABLE_CONTRACT_REMOVE = 0x20,
+    DISABLE_CONTRACT_INVOKE = 0x40
 };
 
 struct LedgerHeaderExtensionV1
@@ -122,7 +126,8 @@
     LEDGER_UPGRADE_BASE_FEE = 2,
     LEDGER_UPGRADE_MAX_TX_SET_SIZE = 3,
     LEDGER_UPGRADE_BASE_RESERVE = 4,
-    LEDGER_UPGRADE_FLAGS = 5
+    LEDGER_UPGRADE_FLAGS = 5,
+    LEDGER_UPGRADE_CONFIG = 6
 };
 
 union LedgerUpgrade switch (LedgerUpgradeType type)
@@ -137,6 +142,12 @@
     uint32 newBaseReserve; // update baseReserve
 case LEDGER_UPGRADE_FLAGS:
     uint32 newFlags; // update flags
+case LEDGER_UPGRADE_CONFIG:
+    Hash configUpgradeSetHash;
+};
+
+struct ConfigUpgradeSet {
+    ConfigSettingEntry updatedEntry<>;
 };
 
 /* Entries used to define the bucket list */
@@ -264,6 +275,32 @@
     ext;
 };
 
+struct TransactionResultPairV2
+{
+    Hash transactionHash;
+    Hash hashOfMetaHashes; // hash of hashes in TransactionMetaV3
+                           // TransactionResult is in the meta
+};
+
+struct TransactionResultSetV2
+{
+    TransactionResultPairV2 results<>;
+};
+
+struct TransactionHistoryResultEntryV2
+{
+    uint32 ledgerSeq;
+    TransactionResultSetV2 txResultSet;
+
+    // reserved for future use
+    union switch (int v)
+    {
+    case 0:
+        void;
+    }
+    ext;
+};
+
 struct LedgerHeaderHistoryEntry
 {
     Hash hash;
@@ -348,6 +385,48 @@
                                         // applied if any
 };
 
+enum ContractEventType
+{
+    SYSTEM = 0,
+    CONTRACT = 1
+};
+
+struct ContractEvent
+{
+    // We can use this to add more fields, or because it
+    // is first, to change ContractEvent into a union.
+    ExtensionPoint ext;
+
+    Hash* contractID;
+    ContractEventType type;
+
+    union switch (int v)
+    {
+    case 0:
+        struct
+        {
+            SCVec topics;
+            SCVal data;
+        } v0;
+    }
+    body;
+};
+
+struct TransactionMetaV3
+{
+    LedgerEntryChanges txChangesBefore; // tx level changes before operations
+                                        // are applied if any
+    OperationMeta operations<>;         // meta for each operation
+    LedgerEntryChanges txChangesAfter;  // tx level changes after operations are
+                                        // applied if any
+    ContractEvent events<>;            // custom events populated by the
+                                        // contracts themselves
+    TransactionResult txResult;
+
+    Hash hashes[3];                     // stores sha256(txChangesBefore, operations, txChangesAfter),
+                                        // sha256(events), and sha256(txResult)
+};
+
 // this is the meta produced when applying transactions
 // it does not include pre-apply updates such as fees
 union TransactionMeta switch (int v)
@@ -358,6 +437,8 @@
     TransactionMetaV1 v1;
 case 2:
     TransactionMetaV2 v2;
+case 3:
+    TransactionMetaV3 v3;
 };
 
 // This struct groups together changes on a per transaction basis
@@ -370,6 +451,13 @@
     TransactionMeta txApplyProcessing;
 };
 
+struct TransactionResultMetaV2
+{
+    TransactionResultPairV2 result;
+    LedgerEntryChanges feeProcessing;
+    TransactionMeta txApplyProcessing;
+};
+
 // this represents a single upgrade that was performed as part of a ledger
 // upgrade
 struct UpgradeEntryMeta
@@ -414,11 +502,32 @@
     SCPHistoryEntry scpInfo<>;
 };
 
+// only difference between V1 and V2 is this uses TransactionResultMetaV2
+struct LedgerCloseMetaV2
+{
+    LedgerHeaderHistoryEntry ledgerHeader;
+    
+    GeneralizedTransactionSet txSet;
+
+    // NB: transactions are sorted in apply order here
+    // fees for all transactions are processed first
+    // followed by applying transactions
+    TransactionResultMetaV2 txProcessing<>;
+
+    // upgrades are applied last
+    UpgradeEntryMeta upgradesProcessing<>;
+
+    // other misc information attached to the ledger close
+    SCPHistoryEntry scpInfo<>;
+};
+
 union LedgerCloseMeta switch (int v)
 {
 case 0:
     LedgerCloseMetaV0 v0;
 case 1:
     LedgerCloseMetaV1 v1;
+case 2:
+    LedgerCloseMetaV2 v2;
 };
 }
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 19:44:25.869507400 -0400
@@ -83,7 +83,7 @@
     uint32 numFailures;
 };
 
-// Next ID: 18
+// Next ID: 20
 enum MessageType
 {
     ERROR_MSG = 0,
@@ -113,7 +113,11 @@
 
     SEND_MORE = 16,
     FLOOD_ADVERT = 18,
-    FLOOD_DEMAND = 19
+    FLOOD_DEMAND = 19,
+    
+    // Configuration upgrades
+    GET_CONFIG_UPGRADE_SET = 20,
+    CONFIG_UPGRADE_SET = 21
 };
 
 struct DontHave
@@ -243,6 +247,11 @@
 case SURVEY_RESPONSE:
     SignedSurveyResponseMessage signedSurveyResponseMessage;
 
+case GET_CONFIG_UPGRADE_SET:
+    uint256 configUgradeSetHash;
+case CONFIG_UPGRADE_SET:
+    ConfigUpgradeSet configUpgradeSet;
+
 // SCP
 case GET_SCP_QUORUMSET:
     uint256 qSetHash;
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-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
 
+%#include "xdr/Stellar-contract.h"
 %#include "xdr/Stellar-ledger-entries.h"
 
 namespace stellar
@@ -32,6 +33,13 @@
     Signature signature; // actual signature
 };
 
+// Ledger key sets touched by a smart contract transaction.
+struct LedgerFootprint
+{
+    LedgerKey readOnly<>;
+    LedgerKey readWrite<>;
+};
+
 enum OperationType
 {
     CREATE_ACCOUNT = 0,
@@ -57,7 +65,8 @@
     CLAWBACK_CLAIMABLE_BALANCE = 20,
     SET_TRUST_LINE_FLAGS = 21,
     LIQUIDITY_POOL_DEPOSIT = 22,
-    LIQUIDITY_POOL_WITHDRAW = 23
+    LIQUIDITY_POOL_WITHDRAW = 23,
+    INVOKE_HOST_FUNCTION = 24
 };
 
 /* CreateAccount
@@ -465,6 +474,91 @@
     int64 minAmountB; // minimum amount of second asset to withdraw
 };
 
+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<SCVAL_LIMIT>;
+};
+
+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)
+{
+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;
+    // The footprint for this invocation
+    LedgerFootprint footprint;
+};
+
 /* An operation is the lowest unit of work that a transaction does */
 struct Operation
 {
@@ -523,6 +617,8 @@
         LiquidityPoolDepositOp liquidityPoolDepositOp;
     case LIQUIDITY_POOL_WITHDRAW:
         LiquidityPoolWithdrawOp liquidityPoolWithdrawOp;
+    case INVOKE_HOST_FUNCTION:
+        InvokeHostFunctionOp invokeHostFunctionOp;
     }
     body;
 };
@@ -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:
+    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 +1718,25 @@
     void;
 };
 
+enum InvokeHostFunctionResultCode
+{
+    // codes considered as "success" for the operation
+    INVOKE_HOST_FUNCTION_SUCCESS = 0,
+
+    // codes considered as "failure" for the operation
+    INVOKE_HOST_FUNCTION_MALFORMED = -1,
+    INVOKE_HOST_FUNCTION_TRAPPED = -2
+};
+
+union InvokeHostFunctionResult switch (InvokeHostFunctionResultCode code)
+{
+case INVOKE_HOST_FUNCTION_SUCCESS:
+    SCVal success;
+case INVOKE_HOST_FUNCTION_MALFORMED:
+case INVOKE_HOST_FUNCTION_TRAPPED:
+    void;
+};
+
 /* High level Operation Result */
 enum OperationResultCode
 {
@@ -1654,6 +1803,8 @@
         LiquidityPoolDepositResult liquidityPoolDepositResult;
     case LIQUIDITY_POOL_WITHDRAW:
         LiquidityPoolWithdrawResult liquidityPoolWithdrawResult;
+    case INVOKE_HOST_FUNCTION:
+        InvokeHostFunctionResult invokeHostFunctionResult;
     }
     tr;
 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 19:44:03.008942400 -0400
@@ -79,6 +79,7 @@
 typedef opaque SignatureHint[4];
 
 typedef PublicKey NodeID;
+typedef PublicKey AccountID;
 
 struct Curve25519Secret
 {