Repository: stellar/rs-soroban-env
Pull request #1069 (2023-09-14 22:44:18)

Set LedgerEntry extensions on existing entries
Tested in core - https://github.com/stellar/stellar-core/pull/3939


Patch:
diff --git a/soroban-env-host/src/host.rs b/soroban-env-host/src/host.rs
index 6a7ddc47..80f6ab9d 100644
--- a/soroban-env-host/src/host.rs
+++ b/soroban-env-host/src/host.rs
@@ -803,14 +803,14 @@ impl Host {
             .map_err(|e| self.decorate_contract_code_storage_error(e, &Hash(hash_bytes)))?
         {
             self.with_mut_storage(|storage| {
-                let data = LedgerEntryData::ContractCode(ContractCodeEntry {
+                let data = ContractCodeEntry {
                     hash: Hash(hash_bytes),
                     ext: ExtensionPoint::V0,
                     code: wasm_bytes_m,
-                });
+                };
                 storage.put(
                     &code_key,
-                    &Host::ledger_entry_from_data(self, data)?,
+                    &Host::new_contract_code(self, data)?,
                     Some(self.get_min_expiration_ledger(ContractDataDurability::Persistent)?),
                     self.as_budget(),
                 )
@@ -919,17 +919,17 @@ impl Host {
                 )
                 .map_err(|e| self.decorate_contract_data_storage_error(e, k))?;
         } else {
-            let data = LedgerEntryData::ContractData(ContractDataEntry {
+            let data = ContractDataEntry {
                 contract: ScAddress::Contract(self.get_current_contract_id_internal()?),
                 key: self.from_host_val(k)?,
                 val: self.from_host_val(v)?,
                 durability,
                 ext: ExtensionPoint::V0,
-            });
+            };
             self.try_borrow_storage_mut()?
                 .put(
                     &key,
-                    &Host::ledger_entry_from_data(self, data)?,
+                    &Host::new_contract_data(self, data)?,
                     Some(self.get_min_expiration_ledger(durability)?),
                     self.as_budget(),
                 )
diff --git a/soroban-env-host/src/host/data_helper.rs b/soroban-env-host/src/host/data_helper.rs
index 182753e3..a37db9eb 100644
--- a/soroban-env-host/src/host/data_helper.rs
+++ b/soroban-env-host/src/host/data_helper.rs
@@ -2,8 +2,9 @@ use core::cmp::min;
 use std::rc::Rc;
 
 use soroban_env_common::xdr::{
-    BytesM, ContractDataDurability, ContractExecutable, ContractIdPreimage, ExtensionPoint,
-    HashIdPreimageContractId, ScAddress, ScContractInstance, ScErrorCode, ScErrorType,
+    BytesM, ContractCodeEntry, ContractDataDurability, ContractExecutable, ContractIdPreimage,
+    ExtensionPoint, HashIdPreimageContractId, ScAddress, ScContractInstance, ScErrorCode,
+    ScErrorType,
 };
 use soroban_env_common::{AddressObject, Env, U32Val};
 
@@ -134,17 +135,17 @@ impl Host {
                 )
                 .map_err(|e| self.decorate_contract_instance_storage_error(e, &contract_id))?;
         } else {
-            let data = LedgerEntryData::ContractData(ContractDataEntry {
+            let data = ContractDataEntry {
                 contract: ScAddress::Contract(contract_id.metered_clone(self)?),
                 key: ScVal::LedgerKeyContractInstance,
                 val: ScVal::ContractInstance(instance),
                 durability: ContractDataDurability::Persistent,
                 ext: ExtensionPoint::V0,
-            });
+            };
             self.try_borrow_storage_mut()?
                 .put(
                     key,
-                    &Host::ledger_entry_from_data(self, data)?,
+                    &Host::new_contract_data(self, data)?,
                     Some(self.get_min_expiration_ledger(ContractDataDurability::Persistent)?),
                     self.as_budget(),
                 )
@@ -290,22 +291,55 @@ impl Host {
         }
     }
 
-    pub(crate) fn ledger_entry_from_data(
+    pub(crate) fn new_contract_data(
         &self,
-        data: LedgerEntryData,
+        data: ContractDataEntry,
     ) -> Result<Rc<LedgerEntry>, HostError> {
         Rc::metered_new(
             LedgerEntry {
                 // This is modified to the appropriate value on the core side during
                 // commiting the ledger transaction.
                 last_modified_ledger_seq: 0,
-                data,
+                data: LedgerEntryData::ContractData(data),
                 ext: LedgerEntryExt::V0,
             },
             self,
         )
     }
 
+    pub(crate) fn new_contract_code(
+        &self,
+        data: ContractCodeEntry,
+    ) -> Result<Rc<LedgerEntry>, HostError> {
+        Rc::metered_new(
+            LedgerEntry {
+                // This is modified to the appropriate value on the core side during
+                // commiting the ledger transaction.
+                last_modified_ledger_seq: 0,
+                data: LedgerEntryData::ContractCode(data),
+                ext: LedgerEntryExt::V0,
+            },
+            self,
+        )
+    }
+
+    pub(crate) fn modify_ledger_entry_data(
+        &self,
+        original_entry: &LedgerEntry,
+        new_data: LedgerEntryData,
+    ) -> Result<Rc<LedgerEntry>, HostError> {
+        Rc::metered_new(
+            LedgerEntry {
+                // This is modified to the appropriate value on the core side during
+                // commiting the ledger transaction.
+                last_modified_ledger_seq: 0,
+                data: new_data,
+                ext: original_entry.ext.metered_clone(self)?,
+            },
+            self,
+        )
+    }
+
     pub(crate) fn contract_id_from_scaddress(&self, address: ScAddress) -> Result<Hash, HostError> {
         match address {
             ScAddress::Account(_) => Err(self.err(
diff --git a/soroban-env-host/src/native_contract/token/balance.rs b/soroban-env-host/src/native_contract/token/balance.rs
index 6806df50..cf03ace8 100644
--- a/soroban-env-host/src/native_contract/token/balance.rs
+++ b/soroban-env-host/src/native_contract/token/balance.rs
@@ -443,7 +443,7 @@ fn transfer_account_balance(e: &Host, account_id: AccountId, amount: i64) -> Res
         };
         if new_balance >= min_balance && new_balance <= max_balance {
             ae.balance = new_balance;
-            le = Host::ledger_entry_from_data(e, LedgerEntryData::Account(ae))?;
+            le = Host::modify_ledger_entry_data(e, &le, LedgerEntryData::Account(ae))?;
             storage.put(&lk, &le, None, e.as_budget())
         } else {
             Err(err!(
@@ -495,7 +495,7 @@ fn transfer_trustline_balance(
         };
         if new_balance >= min_balance && new_balance <= max_balance {
             tl.balance = new_balance;
-            le = Host::ledger_entry_from_data(e, LedgerEntryData::Trustline(tl))?;
+            le = Host::modify_ledger_entry_data(e, &le, LedgerEntryData::Trustline(tl))?;
             storage.put(&lk, &le, None, e.as_budget())
         } else {
             Err(err!(
@@ -796,7 +796,7 @@ fn set_trustline_authorization(
             tl.flags &= !(TrustLineFlags::AuthorizedFlag as u32);
             tl.flags |= TrustLineFlags::AuthorizedToMaintainLiabilitiesFlag as u32;
         }
-        le = Host::ledger_entry_from_data(e, LedgerEntryData::Trustline(tl))?;
+        le = Host::modify_ledger_entry_data(e, &le, LedgerEntryData::Trustline(tl))?;
         storage.put(&lk, &le, None, e.as_budget())
     })
 }


Test patch:
diff --git a/soroban-env-host/src/native_contract/testutils.rs b/soroban-env-host/src/native_contract/testutils.rs
index 363cdb44..540df1e9 100644
--- a/soroban-env-host/src/native_contract/testutils.rs
+++ b/soroban-env-host/src/native_contract/testutils.rs
@@ -1,12 +1,14 @@
+use std::rc::Rc;
+
 use crate::{Host, LedgerInfo};
 use ed25519_dalek::{Signer, SigningKey};
 use rand::{thread_rng, Rng};
 use soroban_env_common::xdr::{
     AccountEntry, AccountEntryExt, AccountEntryExtensionV1, AccountEntryExtensionV1Ext,
     AccountEntryExtensionV2, AccountEntryExtensionV2Ext, AccountId, Hash, HashIdPreimage,
-    HashIdPreimageSorobanAuthorization, InvokeContractArgs, LedgerEntryData, LedgerKey,
-    Liabilities, PublicKey, ScAddress, ScSymbol, ScVal, SequenceNumber, SignerKey,
-    SorobanAddressCredentials, SorobanAuthorizationEntry, SorobanAuthorizedFunction,
+    HashIdPreimageSorobanAuthorization, InvokeContractArgs, LedgerEntry, LedgerEntryData,
+    LedgerEntryExt, LedgerKey, Liabilities, PublicKey, ScAddress, ScSymbol, ScVal, SequenceNumber,
+    SignerKey, SorobanAddressCredentials, SorobanAuthorizationEntry, SorobanAuthorizedFunction,
     SorobanAuthorizedInvocation, SorobanCredentials, Thresholds, Uint256,
 };
 use soroban_env_common::{EnvBase, TryFromVal, Val};
@@ -321,8 +323,18 @@ pub(crate) fn create_account(
 
     host.add_ledger_entry(
         &key,
-        &Host::ledger_entry_from_data(host, LedgerEntryData::Account(acc_entry)).unwrap(),
+        &new_ledger_entry_from_data(LedgerEntryData::Account(acc_entry)),
         None,
     )
     .unwrap();
 }
+
+pub(crate) fn new_ledger_entry_from_data(data: LedgerEntryData) -> Rc<LedgerEntry> {
+    Rc::new(LedgerEntry {
+        // This is modified to the appropriate value on the core side during
+        // commiting the ledger transaction.
+        last_modified_ledger_seq: 0,
+        data,
+        ext: LedgerEntryExt::V0,
+    })
+}
diff --git a/soroban-env-host/src/test/token.rs b/soroban-env-host/src/test/token.rs
index 50a76022..62588894 100644
--- a/soroban-env-host/src/test/token.rs
+++ b/soroban-env-host/src/test/token.rs
@@ -11,7 +11,8 @@ use crate::{
         testutils::{
             account_to_address, authorize_single_invocation,
             authorize_single_invocation_with_nonce, contract_id_to_address, create_account,
-            generate_signing_key, signing_key_to_account_id, AccountSigner, HostVec, TestSigner,
+            generate_signing_key, new_ledger_entry_from_data, signing_key_to_account_id,
+            AccountSigner, HostVec, TestSigner,
         },
         token::test_token::TestToken,
     },
@@ -179,8 +180,9 @@ impl TokenTest {
                 match entry.data.clone() {
                     LedgerEntryData::Account(mut account) => {
                         account.flags = new_flags;
-                        let update = Host::ledger_entry_from_data(
+                        let update = Host::modify_ledger_entry_data(
                             &self.host,
+                            &entry,
                             LedgerEntryData::Account(account),
                         )?;
                         s.put(key, &update, None, self.host.as_budget())
@@ -241,11 +243,7 @@ impl TokenTest {
         self.host
             .add_ledger_entry(
                 &key,
-                &Host::ledger_entry_from_data(
-                    &self.host,
-                    LedgerEntryData::Trustline(trustline_entry),
-                )
-                .unwrap(),
+                &new_ledger_entry_from_data(LedgerEntryData::Trustline(trustline_entry)),
                 None,
             )
             .unwrap();
@@ -260,8 +258,9 @@ impl TokenTest {
                 match entry.data.clone() {
                     LedgerEntryData::Trustline(mut trustline) => {
                         trustline.flags = new_flags;
-                        let update = Host::ledger_entry_from_data(
+                        let update = Host::modify_ledger_entry_data(
                             &self.host,
+                            &entry,
                             LedgerEntryData::Trustline(trustline),
                         )?;
                         s.put(key, &update, None, self.host.as_budget())