diff --git a/StellarDotnetSdk.Tests/ScValTest.cs b/StellarDotnetSdk.Tests/ScValTest.cs index 97aa7973..333c3b38 100644 --- a/StellarDotnetSdk.Tests/ScValTest.cs +++ b/StellarDotnetSdk.Tests/ScValTest.cs @@ -341,9 +341,9 @@ public void TestScUint128() } [TestMethod] - public void TestScInt128() + public void TestScInt128FromParts() { - var scInt128 = new SCInt128(18446744073709551615, -9223372036854775807); + var scInt128 = new SCInt128(-9223372036854775807, 18446744073709551615); // Act var scInt128XdrBase64 = scInt128.ToXdrBase64(); @@ -354,6 +354,41 @@ public void TestScInt128() Assert.AreEqual(scInt128.Hi, fromXdrBase64ScInt128.Hi); } + [TestMethod] + public void TestScInt128ConstructedFromValidString() + { + var scInt128FromString = new SCInt128("18446744073709551616"); + + var scInt128FromParts = new SCInt128(1, 0); + // Act + var scInt128XdrBase64 = scInt128FromString.ToXdrBase64(); + var fromXdrBase64ScInt128 = (SCInt128)SCVal.FromXdrBase64(scInt128XdrBase64); + + // Assert + Assert.AreEqual(scInt128FromString.Lo, fromXdrBase64ScInt128.Lo); + Assert.AreEqual(scInt128FromString.Hi, fromXdrBase64ScInt128.Hi); + + Assert.AreEqual(scInt128FromString.Lo, scInt128FromParts.Lo); + Assert.AreEqual(scInt128FromString.Hi, scInt128FromParts.Hi); + } + + [TestMethod] + public void TestScInt128ConstructedFromTooBigNumericString() + { + var ex = Assert.ThrowsException(() => + { + _ = new SCInt128("170141183460469231731687303715884105728"); + }); + Assert.IsTrue(ex.Message.Contains("Value must be between -2^127 and 2^127 - 1.")); + } + + [TestMethod] + public void TestScInt128ConstructedFromInvalidNumericString() + { + var ex = Assert.ThrowsException(() => { _ = new SCInt128("9,223,372,036,854,775,807"); }); + Assert.IsTrue(ex.Message.Contains("Invalid numeric string.")); + } + [TestMethod] public void TestScUint256() { diff --git a/StellarDotnetSdk.Tests/SorobanServerTest.cs b/StellarDotnetSdk.Tests/SorobanServerTest.cs index c00c4e0a..afa826bf 100644 --- a/StellarDotnetSdk.Tests/SorobanServerTest.cs +++ b/StellarDotnetSdk.Tests/SorobanServerTest.cs @@ -24,6 +24,7 @@ using Claimant = StellarDotnetSdk.Claimants.Claimant; using CollectionAssert = NUnit.Framework.CollectionAssert; using DiagnosticEvent = StellarDotnetSdk.Soroban.DiagnosticEvent; +using EvictionIterator = StellarDotnetSdk.LedgerEntries.EvictionIterator; using LedgerFootprint = StellarDotnetSdk.Soroban.LedgerFootprint; using LedgerKey = StellarDotnetSdk.LedgerKeys.LedgerKey; using SCBytes = StellarDotnetSdk.Soroban.SCBytes; @@ -33,6 +34,7 @@ using SCVec = StellarDotnetSdk.Soroban.SCVec; using SorobanResources = StellarDotnetSdk.Soroban.SorobanResources; using SorobanTransactionData = StellarDotnetSdk.Soroban.SorobanTransactionData; +using StateArchivalSettings = StellarDotnetSdk.LedgerEntries.StateArchivalSettings; using Transaction = StellarDotnetSdk.Transactions.Transaction; using TransactionResult = StellarDotnetSdk.Responses.Results.TransactionResult; @@ -568,6 +570,7 @@ private async Task SimulateAndUpdateTransaction(Tra { tx.SetSorobanAuthorization(simulateResponse.SorobanAuthorization); } + Assert.IsNotNull(simulateResponse.MinResourceFee); tx.AddResourceFee(simulateResponse.MinResourceFee.Value); tx.Sign(signer ?? _sourceAccount); @@ -1665,6 +1668,297 @@ public async Task TestGetTransactions() "AAAAAwAAAAAAAAACAAAAAwAc0RwAAAAAAAAAADEswRzGZ9SA3Mvrzsmzixf+OYVAOpOjUuPgoOgLU95JAAAAFxzxIbUAAAIJAAtMUAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAABzRGgAAAABmWd/VAAAAAAAAAAEAHNEcAAAAAAAAAAAxLMEcxmfUgNzL687Js4sX/jmFQDqTo1Lj4KDoC1PeSQAAABcc8SG1AAACCQALTFEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAAAc0RwAAAAAZlnf3wAAAAAAAAAAAAAAAAAAAAA=", tx5.ResultMetaXdr); } - // TODO TestGetLedgerEntriesOfTypeTTL() - // TODO TestGetLedgerEntriesOfTypeConfigSetting() + + [TestMethod] + public async Task TestGetLedgerEntriesOfTypeConfigSetting() + { + const string json = + """ + { + "jsonrpc": "2.0", + "id": "cee63f05-e7ad-42c8-bc79-ceb9374043a4", + "result": { + "entries": [ + { + "key": "AAAACAAAAAA=", + "xdr": "AAAACAAAAAAAAQAA", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAE=", + "xdr": "AAAACAAAAAEAAAAAHc1lAAAAAAAF9eEAAAAAAAAAABkCgAAA", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAI=", + "xdr": "AAAACAAAAAIAAADIAAehIAAAAH0AARFwAAAAKAADDUAAAAAZAAEEAAAAAAAAABhqAAAAAAAAJxAAAAAAAAAG+gAAAAAR4aMAAAAAAAAAJmwAAAAAAAAvVAAAE4g=", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAM=", + "xdr": "AAAACAAAAAMAAAAAAAA/aw==", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAQ=", + "xdr": "AAAACAAAAAQAACAGAAAAAAAAJxA=", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAU=", + "xdr": "AAAACAAAAAUAARgAAAEYAAAAAAAAAAZY", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAY=", + "xdr": "AAAACAAAAAYAAAAtAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAbIAAAAAAAAAEAAAAAAAAAAAAAAAKgAAAAAAAAAQAAAAAAAAAAAAAAAsAAAAAAAAABAAAAAAAAAAAAAAAScAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAADdAAAAAAAAABoAAAAAAAAAAAAAAUsAAAAAAAAREQAAAAAAAAAAAAAONAAAAAAAABtlAAAAAAAAAAAAAJ1AAAAAAAAAAAAAAAAAAAAAAAAFws8AAAAAAAAP2wAAAAAAAAAAAAZeygAAAAAAALKQAAAAAAAAAAAAAKC2AAAAAAAAAnoAAAAAAAAAAAAAB5kAAAAAAAAAAAAAAAAAAAAAAAAZUQAAAAAAABc3AAAAAAAAAAAAAALHAAAAAAAAAAAAAAAAAAAAAAAjUjQAAAAAAAAAAAAAAAAAAAAAAAAQUAAAAAAAAAAAAAAAAAAAAAAAABJsAAAAAAAAAAAAAAAAAAAAAAAAEkgAAAAAAAAAAAAAAAAAAAAAAAAQoAAAAAAAAAAAAAAAAAAAAAAAAAN0AAAAAAAAAAAAAAAAAAAAAAAABCMAAAAAAAAB9gAAAAAAAAAAAAEddQAAAAAAAGNCAAAAAAAAAAAAAAAAAAAAAAAIQFAAAAAAAAAAAAAAAAAAAAAAAAKw6wAAAAAAAAAAAAAAAAAAAAAAAHUlAAAAAAAAAAAAAAAAAAAAAAAQMkkAAAAAAAAAAAAAAAAAAAAAAAOfGAAAAAAAAAAAAAAAAAAAAAAABQMcAAAAAAAAAAAAAAAAAAAAAAAKtZUAAAAAAAAAAAAAAAAAAAAAAAaNRwAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAKgWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdhAAAAAAAAAAAAAAAAAAAAAAAACnXAAAAAAAAAAAAAAAAAAAAAAAADOQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFn+AAAAAAAAAAAAAAAAAAAAAAAApfgAAAAAAAAAAAAAAAAAAAAAAAymLgAAAAAAAAAAAAAAAAAAAAAABIiMAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAB1oAAAAAAAAAAAAAAAAAAAAAAC3KSgAAAAAAAAAA", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAc=", + "xdr": "AAAACAAAAAcAAAAtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIGpQAAAAAAABMnAAAAAAAAAAAAAQ9gAAAAAAAABMEAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALUAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAAAAAAAAAAAAAAAAAAAAABjAAAAAAAAAAAAAAAAAAAAAAAAAGMAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAAAAAAAAAAAAAAAAAAAAABjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEnAAAAAAAABk5AAAAAAAAAAAAAAAAAAAAAAAAuWgAAAAAAAAAAAAAAAAAAAAAAAA0bAAAAAAAAAAAAAAAAAAAAAAAABiNAAAAAAAAAAAAAAAAAAAAAAAA/J4AAAAAAAAAAAAAAAAAAAAAAABxkgAAAAAAAAAAAAAAAAAAAAAAALvfAAAAAAAAAAAAAAAAAAAAAAABkz0AAAAAAAAAAAAAAAAAAAAAAACOKgAAAAAAAAAAAAAAAAAAAAAAAAEBAAAAAAAAAAAAARQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5FQAAAAAAAAAAAAAAAAAAAAAAABqxAAAAAAAAAAAAAAAAAAAAAAAABAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfpgAAAAAAAAAAAAAAAAAAAAAAAANWEAAAAAAAAAAAAAAAAAAAAAAAF9ZQAAAAAAAAAAAAAAAAAAAAAAACPYAAAAAAAAAAAAAAAAAAAAAAAAAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAg=", + "xdr": "AAAACAAAAAgAAAD6", + "lastModifiedLedgerSeq": 276293 + }, + { + "key": "AAAACAAAAAk=", + "xdr": "AAAACAAAAAkAAQAA", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAo=", + "xdr": "AAAACAAAAAoAL3YAAABDgAAfpAAAAAAAAAAINwAAAAAAABBuAAAD6AAAAB4AAABAAAGGoAAAAAc=", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAs=", + "xdr": "AAAACAAAAAsAAABk", + "lastModifiedLedgerSeq": 1157 + }, + { + "key": "AAAACAAAAAw=", + "xdr": "AAAACAAAAAwAAAAeAAAAAAAAAGQAAAAAAAAAZAAAAAAAAABkAAAAAAAAAGQAAAAAAAAAZAAAAAAAAABkAAAAAAAAAGQAAAAAAAAAZAAAAAAAAABkAAAAAAAAAGQAAAAAAAAAZAAAAAAAAABkAAAAAAAAAGQAAAAAAAAAZAAAAAAAAABkAAAAAAAAAGQAAAAAAAAAZAAAAAAAAABkAAAAAAAAAGQAAAAAAAAAZAAAAAAAAABkAAAAAAAAAGQAAAAAAAALxAAAAAAAAA0IAAAAAAAADkwAAAAAAAAOTAAAAAAAAA+QAAAAAAAAD5AAAAAAAAAPkAAAAAAAAA+Q", + "lastModifiedLedgerSeq": 512 + }, + { + "key": "AAAACAAAAA0=", + "xdr": "AAAACAAAAA0AAAAGAAAAAQAAAAAAAAAA", + "lastModifiedLedgerSeq": 575 + } + ], + "latestLedger": 1172233 + } + } + """; + var ledgerKeyConfigSetting = new LedgerKey[] + { + new LedgerKeyConfigSetting( + ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum.CONFIG_SETTING_CONTRACT_MAX_SIZE_BYTES)), + new LedgerKeyConfigSetting( + ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum.CONFIG_SETTING_CONTRACT_COMPUTE_V0)), + new LedgerKeyConfigSetting( + ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum.CONFIG_SETTING_CONTRACT_LEDGER_COST_V0)), + new LedgerKeyConfigSetting(ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum + .CONFIG_SETTING_CONTRACT_HISTORICAL_DATA_V0)), + new LedgerKeyConfigSetting( + ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum.CONFIG_SETTING_CONTRACT_EVENTS_V0)), + new LedgerKeyConfigSetting( + ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum.CONFIG_SETTING_CONTRACT_BANDWIDTH_V0)), + new LedgerKeyConfigSetting(ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum + .CONFIG_SETTING_CONTRACT_COST_PARAMS_CPU_INSTRUCTIONS)), + new LedgerKeyConfigSetting(ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum + .CONFIG_SETTING_CONTRACT_COST_PARAMS_MEMORY_BYTES)), + new LedgerKeyConfigSetting(ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum + .CONFIG_SETTING_CONTRACT_DATA_KEY_SIZE_BYTES)), + new LedgerKeyConfigSetting(ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum + .CONFIG_SETTING_CONTRACT_DATA_ENTRY_SIZE_BYTES)), + new LedgerKeyConfigSetting( + ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum.CONFIG_SETTING_STATE_ARCHIVAL)), + new LedgerKeyConfigSetting(ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum + .CONFIG_SETTING_CONTRACT_EXECUTION_LANES)), + new LedgerKeyConfigSetting( + ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum.CONFIG_SETTING_BUCKETLIST_SIZE_WINDOW)), + new LedgerKeyConfigSetting( + ConfigSettingID.Create(ConfigSettingID.ConfigSettingIDEnum.CONFIG_SETTING_EVICTION_ITERATOR)), + }; + using var sorobanServer = Utils.CreateTestSorobanServerWithContent(json); + var response = await sorobanServer.GetLedgerEntries(ledgerKeyConfigSetting); + + Assert.IsNotNull(response); + var entries = response.LedgerEntries; + Assert.IsNotNull(entries); + Assert.AreEqual(1172233U, response.LatestLedger); + Assert.AreEqual(14, entries.Length); + + var entry0 = entries[0] as ConfigSettingContractMaxSizeBytes; + Assert.IsNotNull(entry0); + Assert.AreEqual(65536U, entry0.InnerValue); + + var entry1 = entries[1] as ConfigSettingContractCompute; + Assert.IsNotNull(entry1); + Assert.AreEqual(500000000L, entry1.LedgerMaxInstructions); + Assert.AreEqual(100000000L, entry1.TxMaxInstructions); + Assert.AreEqual(25L, entry1.FeeRatePerInstructionsIncrement); + Assert.AreEqual(41943040U, entry1.TxMemoryLimit); + + var entry2 = entries[2] as ConfigSettingContractLedgerCost; + Assert.IsNotNull(entry2); + Assert.AreEqual(200U, entry2.LedgerMaxReadLedgerEntries); + Assert.AreEqual(500000U, entry2.LedgerMaxReadBytes); + Assert.AreEqual(125U, entry2.LedgerMaxWriteLedgerEntries); + Assert.AreEqual(70000U, entry2.LedgerMaxWriteBytes); + Assert.AreEqual(40U, entry2.TxMaxReadLedgerEntries); + Assert.AreEqual(200000U, entry2.TxMaxReadBytes); + Assert.AreEqual(25U, entry2.TxMaxWriteLedgerEntries); + Assert.AreEqual(66560U, entry2.TxMaxWriteBytes); + Assert.AreEqual(6250L, entry2.FeeReadLedgerEntry); + Assert.AreEqual(10000L, entry2.FeeWriteLedgerEntry); + Assert.AreEqual(1786L, entry2.FeeRead1Kb); + Assert.AreEqual(300000000L, entry2.BucketListTargetSizeBytes); + Assert.AreEqual(9836L, entry2.WriteFee1KbBucketListLow); + Assert.AreEqual(12116L, entry2.WriteFee1KbBucketListHigh); + Assert.AreEqual(5000U, entry2.BucketListWriteFeeGrowthFactor); + + var entry3 = entries[3] as ConfigSettingContractHistoricalData; + Assert.IsNotNull(entry3); + Assert.AreEqual(16235L, entry3.FeeHistorical1Kb); + + var entry4 = entries[4] as ConfigSettingContractEvents; + Assert.IsNotNull(entry4); + Assert.AreEqual(8198U, entry4.TxMaxContractEventsSizeBytes); + Assert.AreEqual(10000L, entry4.FeeContractEvents1Kb); + + var entry5 = entries[5] as ConfigSettingContractBandwidth; + Assert.IsNotNull(entry5); + Assert.AreEqual(71680U, entry5.LedgerMaxTxsSizeBytes); + Assert.AreEqual(71680U, entry5.TxMaxSizeBytes); + Assert.AreEqual(1624L, entry5.FeeTxSize1Kb); + + var entry6 = entries[6] as ConfigSettingContractCostParamsCpuInstructions; + Assert.IsNotNull(entry6); + var paramEntries = entry6.ParamEntries; + Assert.IsNotNull(paramEntries); + Assert.AreEqual(45, paramEntries.Length); + + var pEntry0 = paramEntries[0]; + Assert.IsNotNull(pEntry0); + Assert.IsInstanceOfType(pEntry0.ExtensionPoint, typeof(ExtensionPointZero)); + Assert.AreEqual(4L, pEntry0.ConstTerm); + Assert.AreEqual(0L, pEntry0.LinearTerm); + + var pEntry1 = paramEntries[1]; + Assert.IsNotNull(pEntry1); + Assert.IsInstanceOfType(pEntry1.ExtensionPoint, typeof(ExtensionPointZero)); + Assert.AreEqual(434L, pEntry1.ConstTerm); + Assert.AreEqual(16L, pEntry1.LinearTerm); + + var pEntry33 = paramEntries[33]; + Assert.IsNotNull(pEntry33); + Assert.IsInstanceOfType(pEntry33.ExtensionPoint, typeof(ExtensionPointZero)); + Assert.AreEqual(43030L, pEntry33.ConstTerm); + Assert.AreEqual(0L, pEntry33.LinearTerm); + + var pEntry44 = paramEntries[44]; + Assert.IsNotNull(pEntry44); + Assert.IsInstanceOfType(pEntry44.ExtensionPoint, typeof(ExtensionPointZero)); + Assert.AreEqual(3000906L, pEntry44.ConstTerm); + Assert.AreEqual(0L, pEntry44.LinearTerm); + + var entry7 = entries[7] as ConfigSettingContractCostParamsMemoryBytes; + Assert.IsNotNull(entry7); + paramEntries = entry7.ParamEntries; + Assert.IsNotNull(paramEntries); + Assert.AreEqual(45, paramEntries.Length); + + var pEntry3 = paramEntries[3]; + Assert.IsNotNull(pEntry3); + Assert.IsInstanceOfType(pEntry3.ExtensionPoint, typeof(ExtensionPointZero)); + Assert.AreEqual(0L, pEntry3.ConstTerm); + Assert.AreEqual(0L, pEntry3.LinearTerm); + + var pEntry6 = paramEntries[6]; + Assert.IsNotNull(pEntry6); + Assert.IsInstanceOfType(pEntry6.ExtensionPoint, typeof(ExtensionPointZero)); + Assert.AreEqual(242L, pEntry6.ConstTerm); + Assert.AreEqual(384L, pEntry6.LinearTerm); + + var pEntry12 = paramEntries[12]; + Assert.IsNotNull(pEntry12); + Assert.IsInstanceOfType(pEntry12.ExtensionPoint, typeof(ExtensionPointZero)); + Assert.AreEqual(69472L, pEntry12.ConstTerm); + Assert.AreEqual(1217L, pEntry12.LinearTerm); + + var pEntry30 = paramEntries[30]; + Assert.IsNotNull(pEntry30); + Assert.IsInstanceOfType(pEntry30.ExtensionPoint, typeof(ExtensionPointZero)); + Assert.AreEqual(0L, pEntry30.ConstTerm); + Assert.AreEqual(103229L, pEntry30.LinearTerm); + + var entry8 = entries[8] as ConfigSettingContractDataKeySizeBytes; + Assert.IsNotNull(entry8); + Assert.AreEqual(250U, entry8.InnerValue); + + var entry9 = entries[9] as ConfigSettingContractDataEntrySizeBytes; + Assert.IsNotNull(entry9); + Assert.AreEqual(65536U, entry9.InnerValue); + + var entry10 = entries[10] as StateArchivalSettings; + Assert.IsNotNull(entry10); + Assert.AreEqual(3110400U, entry10.MaxEntryTTL); + Assert.AreEqual(17280U, entry10.MinTemporaryTTL); + Assert.AreEqual(2073600U, entry10.MinPersistentTTL); + Assert.AreEqual(2103L, entry10.PersistentRentRateDenominator); + Assert.AreEqual(4206L, entry10.TempRentRateDenominator); + Assert.AreEqual(1000U, entry10.MaxEntriesToArchive); + Assert.AreEqual(30U, entry10.BucketListSizeWindowSampleSize); + Assert.AreEqual(64U, entry10.BucketListWindowSamplePeriod); + Assert.AreEqual(100000U, entry10.EvictionScanSize); + Assert.AreEqual(7U, entry10.StartingEvictionScanLevel); + + var entry11 = entries[11] as ConfigSettingContractExecutionLanes; + Assert.IsNotNull(entry11); + Assert.AreEqual(100U, entry11.LedgerMaxTxCount); + + var entry12 = entries[12] as ConfigSettingBucketListSizeWindow; + Assert.IsNotNull(entry12); + Assert.AreEqual(30, entry12.InnerValue.Length); + Assert.AreEqual(100UL, entry12.InnerValue[0]); + Assert.AreEqual(3012UL, entry12.InnerValue[22]); + Assert.AreEqual(3984UL, entry12.InnerValue[29]); + + var entry13 = entries[13] as EvictionIterator; + Assert.IsNotNull(entry13); + Assert.AreEqual(6U, entry13.BucketListLevel); + Assert.AreEqual(true, entry13.IsCurrBucket); + Assert.AreEqual(0UL, entry13.BucketFileOffset); + } + + [TestMethod] + public async Task TestGetLedgerEntriesOfTypeTtl() + { + const string json = + """ + { + "jsonrpc": "2.0", + "id": "fd6785fe-3535-4106-b979-b0f01e2ab541", + "error": { + "code": -32602, + "message": "ledger ttl entries cannot be queried directly" + } + } + """; + + var ledgerKeyTtl = new LedgerKey[] + { + new LedgerKeyTTL("fsh67B45yRcC/gKPI2ky8EPbFMtc8y0fnjUDaI36OKc="), + }; + using var sorobanServer = Utils.CreateTestSorobanServerWithContent(json); + + var response = await sorobanServer.GetLedgerEntries(ledgerKeyTtl); + Assert.IsNull(response); + } } \ No newline at end of file diff --git a/StellarDotnetSdk/Requests/DefaultStellarSdkHttpClient.cs b/StellarDotnetSdk/Requests/DefaultStellarSdkHttpClient.cs new file mode 100644 index 00000000..8e251852 --- /dev/null +++ b/StellarDotnetSdk/Requests/DefaultStellarSdkHttpClient.cs @@ -0,0 +1,25 @@ +using System.Net.Http; +using System.Net.Http.Headers; +using System.Reflection; + +namespace StellarDotnetSdk.Requests; + +public class DefaultStellarSdkHttpClient : HttpClient +{ + /// + /// Creates an HTTP client with some default request headers and the given bearer token. + /// + /// Bearer token in case the server requires it. + /// Name of the client. + /// Version of the client. + public DefaultStellarSdkHttpClient(string? bearerToken = null, string? clientName = null, string? clientVersion = null) + { + var assembly = Assembly.GetAssembly(GetType())!.GetName(); + DefaultRequestHeaders.Add("X-Client-Name", clientName ?? "stellar-dotnet-sdk"); + DefaultRequestHeaders.Add("X-Client-Version", clientVersion ?? assembly.Version!.ToString()); + if (!string.IsNullOrEmpty(bearerToken)) + { + DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); + } + } +} \ No newline at end of file diff --git a/StellarDotnetSdk/Requests/SorobanRpc/GetTransactionsRequest.cs b/StellarDotnetSdk/Requests/SorobanRpc/GetTransactionsRequest.cs index 4df15028..390bb14e 100644 --- a/StellarDotnetSdk/Requests/SorobanRpc/GetTransactionsRequest.cs +++ b/StellarDotnetSdk/Requests/SorobanRpc/GetTransactionsRequest.cs @@ -3,7 +3,9 @@ public class GetTransactionsRequest { /// - /// Ledger sequence number to start fetching responses from (inclusive). This method will return an error if startLedger is less than the oldest ledger stored in this node, or greater than the latest ledger seen by this node. If a cursor is included in the request, startLedger must be omitted. + /// Ledger sequence number to start fetching responses from (inclusive). This method will return an error if + /// startLedger is less than the oldest ledger stored in this node, or greater than the latest ledger seen by this + /// node. If a cursor is included in the request, startLedger must be omitted. /// public long? StartLedger { get; set; } diff --git a/StellarDotnetSdk/Requests/SorobanRpc/PaginationOptions.cs b/StellarDotnetSdk/Requests/SorobanRpc/PaginationOptions.cs index e7334bc8..5087bdff 100644 --- a/StellarDotnetSdk/Requests/SorobanRpc/PaginationOptions.cs +++ b/StellarDotnetSdk/Requests/SorobanRpc/PaginationOptions.cs @@ -1,18 +1,20 @@ namespace StellarDotnetSdk.Requests.SorobanRpc; /// -/// Pagination in RPC is similar to pagination in Horizon. -/// See: Pagination +/// Pagination in RPC is similar to pagination in Horizon. +/// See: Pagination /// public class PaginationOptions { /// - /// A unique identifier (specifically, a TOID) that points to a specific location in a collection of responses and is pulled from the paging_token value of a record. When a cursor is provided, RPC will not include the element whose ID matches the cursor in the response: only elements which appear after the cursor will be included. + /// A unique identifier (specifically, a TOID) that points to a specific location in a collection of responses and is + /// pulled from the paging_token value of a record. When a cursor is provided, RPC will not include the element whose + /// ID matches the cursor in the response: only elements which appear after the cursor will be included. /// public string? Cursor { get; set; } /// - /// The maximum number of records returned. For getTransactions, this ranges from 1 to 200 and defaults to 50. + /// The maximum number of records returned. For getTransactions, this ranges from 1 to 200 and defaults to 50. /// public long? Limit { get; set; } } \ No newline at end of file diff --git a/StellarDotnetSdk/Responses/SorobanRpc/TransactionInfo.cs b/StellarDotnetSdk/Responses/SorobanRpc/TransactionInfo.cs index 39e3ed78..6ac4ed93 100644 --- a/StellarDotnetSdk/Responses/SorobanRpc/TransactionInfo.cs +++ b/StellarDotnetSdk/Responses/SorobanRpc/TransactionInfo.cs @@ -13,7 +13,7 @@ public enum TransactionStatus { NOT_FOUND, SUCCESS, - FAILED + FAILED, } public TransactionInfo(TransactionStatus status, long? ledger, long? createdAt, int? applicationOrder, @@ -86,7 +86,10 @@ public SCVal? ResultValue { get { - if (Status != TransactionStatus.SUCCESS || ResultMetaXdr == null) return null; + if (Status != TransactionStatus.SUCCESS || ResultMetaXdr == null) + { + return null; + } var bytes = Convert.FromBase64String(ResultMetaXdr); var reader = new XdrDataInputStream(bytes); @@ -102,7 +105,10 @@ public Soroban_TransactionMetaV3? TransactionMeta { get { - if (ResultMetaXdr == null) return null; + if (ResultMetaXdr == null) + { + return null; + } try { return Soroban_TransactionMetaV3.FromXdrBase64(ResultMetaXdr); @@ -118,7 +124,10 @@ public string? WasmHash { get { - if (ResultValue is SCBytes bytes) return Convert.ToHexString(bytes.InnerValue); + if (ResultValue is SCBytes bytes) + { + return Convert.ToHexString(bytes.InnerValue); + } return null; } @@ -129,7 +138,9 @@ public string? CreatedContractId get { if (ResultValue is SCContractId contract) + { return contract.InnerValue; + } return null; } } diff --git a/StellarDotnetSdk/Server.cs b/StellarDotnetSdk/Server.cs index d90d4aa3..6a63ad88 100644 --- a/StellarDotnetSdk/Server.cs +++ b/StellarDotnetSdk/Server.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Reflection; using System.Threading.Tasks; using stellar_dotnet_sdk; @@ -272,11 +273,15 @@ public async Task CheckMemoRequired(TransactionBase transaction) } } + [Obsolete( + "Pass your own HttpClient instance to Server(string uri, HttpClient httpClient) instead. Otherwise call Server(string uri). Will be removed in the next major version.")] public static HttpClient CreateHttpClient() { return CreateHttpClient(new HttpClientHandler()); } + [Obsolete( + "Pass your own HttpClient instance to Server(string uri, HttpClient httpClient) instead. Otherwise call Server(string uri). Will be removed in the next major version.")] public static HttpClient CreateHttpClient(HttpMessageHandler handler) { var httpClient = new HttpClient(handler); @@ -286,6 +291,18 @@ public static HttpClient CreateHttpClient(HttpMessageHandler handler) return httpClient; } + /// + /// Constructs a new instance that will interact with the provided URL. + /// + /// URL of the Horizon server. + /// Bearer token in case the server requires it. + public Server(string uri, string? bearerToken = null) + { + _serverUri = new Uri(uri); + _httpClient = new DefaultStellarSdkHttpClient(bearerToken); + _internalHttpClient = true; + } + private Transaction GetTransactionToCheck(TransactionBase transaction) { switch (transaction) diff --git a/StellarDotnetSdk/Soroban/SCVal.cs b/StellarDotnetSdk/Soroban/SCVal.cs index b1602285..d215b252 100644 --- a/StellarDotnetSdk/Soroban/SCVal.cs +++ b/StellarDotnetSdk/Soroban/SCVal.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Numerics; using StellarDotnetSdk.Accounts; using StellarDotnetSdk.Xdr; using Int32 = StellarDotnetSdk.Xdr.Int32; @@ -773,12 +774,37 @@ public static SCUint128 FromSCValXdr(Xdr.SCVal xdrVal) public class SCInt128 : SCVal { - public SCInt128(ulong lo, long hi) + /// + /// Constructs a new SCInt128 object from high and low parts. + /// + /// High parts. + /// Low parts. + public SCInt128(long hi, ulong lo) { Hi = hi; Lo = lo; } + /// + /// Constructs a new SCInt128 object from a numeric string. + /// + /// A string represents a 128-bit signed integer. + public SCInt128(string input) + { + if (!BigInteger.TryParse(input, out var bigInt)) + { + throw new ArgumentException("Invalid numeric string.", nameof(input)); + } + if (bigInt < BigInteger.MinusOne << 127 || bigInt > (BigInteger.One << 127) - 1) + { + throw new ArgumentOutOfRangeException(nameof(input), "Value must be between -2^127 and 2^127 - 1."); + } + var low = (ulong)(bigInt & ulong.MaxValue); + var high = (long)(bigInt >> 64); + Hi = high; + Lo = low; + } + public ulong Lo { get; set; } public long Hi { get; set; } @@ -809,7 +835,7 @@ public Xdr.SCVal ToSCValXdr() public static SCInt128 FromXdr(Int128Parts xdrInt128Parts) { - return new SCInt128(xdrInt128Parts.Lo.InnerValue, xdrInt128Parts.Hi.InnerValue); + return new SCInt128(xdrInt128Parts.Hi.InnerValue, xdrInt128Parts.Lo.InnerValue); } public static SCInt128 FromSCValXdr(Xdr.SCVal xdrVal) @@ -819,7 +845,7 @@ public static SCInt128 FromSCValXdr(Xdr.SCVal xdrVal) throw new ArgumentException("Not an SCInt128", nameof(xdrVal)); } - return new SCInt128(xdrVal.I128.Lo.InnerValue, xdrVal.I128.Hi.InnerValue); + return new SCInt128(xdrVal.I128.Hi.InnerValue, xdrVal.I128.Lo.InnerValue); } } diff --git a/StellarDotnetSdk/Soroban/SorobanServer.cs b/StellarDotnetSdk/Soroban/SorobanServer.cs index ac41e532..ec19a5e4 100644 --- a/StellarDotnetSdk/Soroban/SorobanServer.cs +++ b/StellarDotnetSdk/Soroban/SorobanServer.cs @@ -16,6 +16,11 @@ namespace StellarDotnetSdk.Soroban; +/// +/// This class helps you to connect to a local or remote Soroban RPC server +/// and send requests to the server. It parses the results and provides +/// corresponding response objects. +/// public class SorobanServer : IDisposable { private const string ClientNameHeader = "X-Client-Name"; @@ -24,6 +29,11 @@ public class SorobanServer : IDisposable private readonly bool _internalHttpClient; private readonly Uri _serverUri; + /// + /// Constructs a new instance that will interact with the provided URL. + /// + /// URL of the Soroban RPC server. + /// HttpClient instance to use for requests. public SorobanServer(string uri, HttpClient httpClient) { _httpClient = httpClient; @@ -31,9 +41,15 @@ public SorobanServer(string uri, HttpClient httpClient) _internalHttpClient = false; } - public SorobanServer(string uri) - : this(uri, CreateHttpClient()) + /// + /// Constructs a new instance that will interact with the provided URL. + /// + /// URL of the Soroban RPC server. + /// Bearer token in case the server requires it. + public SorobanServer(string uri, string? bearerToken = null) { + _serverUri = new Uri(uri); + _httpClient = new DefaultStellarSdkHttpClient(bearerToken); _internalHttpClient = true; } @@ -45,11 +61,15 @@ public void Dispose() } } + [Obsolete( + "Pass your own HttpClient instance to SorobanServer(string uri, HttpClient httpClient) instead. Otherwise call SorobanServer(string uri). Will be removed in the next major version.")] public static HttpClient CreateHttpClient() { return CreateHttpClient(new HttpClientHandler()); } + [Obsolete( + "Pass your own HttpClient instance to SorobanServer(string uri, HttpClient httpClient) instead. Otherwise call SorobanServer(string uri). Will be removed in the next major version.")] public static HttpClient CreateHttpClient(HttpMessageHandler handler) { var httpClient = new HttpClient(handler); diff --git a/StellarDotnetSdk/StellarDotnetSdk.csproj b/StellarDotnetSdk/StellarDotnetSdk.csproj index 230b4920..0ead8258 100644 --- a/StellarDotnetSdk/StellarDotnetSdk.csproj +++ b/StellarDotnetSdk/StellarDotnetSdk.csproj @@ -1,7 +1,7 @@  net8.0 - 10.0.0 + 12.0.0 Library