diff --git a/Example/SubstrateSdk.xcodeproj/project.pbxproj b/Example/SubstrateSdk.xcodeproj/project.pbxproj index 57ddc77..e521b3e 100644 --- a/Example/SubstrateSdk.xcodeproj/project.pbxproj +++ b/Example/SubstrateSdk.xcodeproj/project.pbxproj @@ -82,6 +82,7 @@ 84AF377F271DE550007408D6 /* ScaleInfoMappingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AF377E271DE550007408D6 /* ScaleInfoMappingTests.swift */; }; 84AF378527215DB4007408D6 /* ValidatorPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AF378427215DB4007408D6 /* ValidatorPrefs.swift */; }; 84AF378727221F02007408D6 /* common-v14.json in Resources */ = {isa = PBXBuildFile; fileRef = 84AF378627221F01007408D6 /* common-v14.json */; }; + 84C41F3A28EE157600DB1CD3 /* SignedIntNodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C41F3928EE157600DB1CD3 /* SignedIntNodeTests.swift */; }; 84CB472424DBE82C00837E11 /* KeystoreExtractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CB472324DBE82C00837E11 /* KeystoreExtractorTests.swift */; }; 84CB472524DBE98500837E11 /* keystore-sr25519.json in Resources */ = {isa = PBXBuildFile; fileRef = 84CB472024DBE7E100837E11 /* keystore-sr25519.json */; }; 84DA3B3C24C8CE5900B5E27F /* ScaleUInt32Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DA3B3224C8CE5900B5E27F /* ScaleUInt32Tests.swift */; }; @@ -216,6 +217,7 @@ 84AF377E271DE550007408D6 /* ScaleInfoMappingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScaleInfoMappingTests.swift; sourceTree = ""; }; 84AF378427215DB4007408D6 /* ValidatorPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorPrefs.swift; sourceTree = ""; }; 84AF378627221F01007408D6 /* common-v14.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "common-v14.json"; sourceTree = ""; }; + 84C41F3928EE157600DB1CD3 /* SignedIntNodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignedIntNodeTests.swift; sourceTree = ""; }; 84CB472024DBE7E100837E11 /* keystore-sr25519.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "keystore-sr25519.json"; sourceTree = ""; }; 84CB472324DBE82C00837E11 /* KeystoreExtractorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeystoreExtractorTests.swift; sourceTree = ""; }; 84DA3B3224C8CE5900B5E27F /* ScaleUInt32Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScaleUInt32Tests.swift; sourceTree = ""; }; @@ -431,6 +433,7 @@ 84452C7C25D3F75800F47EC5 /* GenericCallNodeTests.swift */, 84452C8225D3F97F00F47EC5 /* GenericEventNodeTests.swift */, 84452D9225D48FC100F47EC5 /* ExtrinsicNodeTests.swift */, + 84C41F3928EE157600DB1CD3 /* SignedIntNodeTests.swift */, ); path = Generic; sourceTree = ""; @@ -890,6 +893,7 @@ 84DA3B4024C8CE5900B5E27F /* ScaleInt8Tests.swift in Sources */, 84AF377F271DE550007408D6 /* ScaleInfoMappingTests.swift in Sources */, 84DA3B4524C8CE5A00B5E27F /* ScaleUInt8Tests.swift in Sources */, + 84C41F3A28EE157600DB1CD3 /* SignedIntNodeTests.swift in Sources */, 84F43A6125DC701F00AEDA56 /* Reasons.swift in Sources */, 84AF377A271DA9A2007408D6 /* ScaleRegistryTests.swift in Sources */, 84F43B4625DE800F00AEDA56 /* ExtrinsicBuilderTests.swift in Sources */, diff --git a/SubstrateSdk.podspec b/SubstrateSdk.podspec index 742db03..89f0c22 100644 --- a/SubstrateSdk.podspec +++ b/SubstrateSdk.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'SubstrateSdk' - s.version = '1.4.0' + s.version = '1.4.1' s.summary = 'Utility library that implements clients specific logic to interact with substrate based networks' s.homepage = 'https://github.com/nova-wallet/substrate-sdk-ios' diff --git a/SubstrateSdk/Classes/Runtime/Nodes/Items/BasicNode.swift b/SubstrateSdk/Classes/Runtime/Nodes/Items/BasicNode.swift index a244d8d..70f1e2c 100644 --- a/SubstrateSdk/Classes/Runtime/Nodes/Items/BasicNode.swift +++ b/SubstrateSdk/Classes/Runtime/Nodes/Items/BasicNode.swift @@ -118,11 +118,11 @@ public class I32Node: Node { public init() {} public func accept(encoder: DynamicScaleEncoding, value: JSON) throws { - try encoder.appendU32(json: value) + try encoder.appendI32(json: value) } public func accept(decoder: DynamicScaleDecoding) throws -> JSON { - try decoder.readU32() + try decoder.readI32() } } diff --git a/SubstrateSdk/Classes/Scale/DynamicScaleDecoder.swift b/SubstrateSdk/Classes/Scale/DynamicScaleDecoder.swift index 75cb9f5..845f8c2 100644 --- a/SubstrateSdk/Classes/Scale/DynamicScaleDecoder.swift +++ b/SubstrateSdk/Classes/Scale/DynamicScaleDecoder.swift @@ -64,7 +64,7 @@ public class DynamicScaleDecoder { private func decodeSignedInt(length: Int) throws -> JSON { let data = try decoder.readAndConfirm(count: length) let magnitude = BigUInt(Data(data.reversed())) - let signMask = BigUInt(1) << (length - 1) + let signMask = BigUInt(1) << (8 * length - 1) let sign: BigInt.Sign = (magnitude & signMask) == 0 ? .plus : .minus let value: BigInt @@ -175,27 +175,27 @@ extension DynamicScaleDecoder: DynamicScaleDecoding { } public func readI8() throws -> JSON { - try decodeFixedInt(length: 1) + try decodeSignedInt(length: 1) } public func readI16() throws -> JSON { - try decodeFixedInt(length: 2) + try decodeSignedInt(length: 2) } public func readI32() throws -> JSON { - try decodeFixedInt(length: 4) + try decodeSignedInt(length: 4) } public func readI64() throws -> JSON { - try decodeFixedInt(length: 8) + try decodeSignedInt(length: 8) } public func readI128() throws -> JSON { - try decodeFixedInt(length: 16) + try decodeSignedInt(length: 16) } public func readI256() throws -> JSON { - try decodeFixedInt(length: 32) + try decodeSignedInt(length: 32) } public func readBool() throws -> JSON { diff --git a/SubstrateSdk/Classes/Scale/DynamicScaleEncoder.swift b/SubstrateSdk/Classes/Scale/DynamicScaleEncoder.swift index ef2228a..94d2a3c 100644 --- a/SubstrateSdk/Classes/Scale/DynamicScaleEncoder.swift +++ b/SubstrateSdk/Classes/Scale/DynamicScaleEncoder.swift @@ -59,7 +59,8 @@ public final class DynamicScaleEncoder { case .plus: magnitude = intValue.magnitude case .minus: - let invertingMask = (BigUInt(1) << byteLength) - 1 + let bitLength = 8 * byteLength + let invertingMask = (BigUInt(1) << bitLength) - 1 magnitude = (intValue.magnitude ^ invertingMask) + 1 } diff --git a/Tests/Runtime/Generic/SignedIntNodeTests.swift b/Tests/Runtime/Generic/SignedIntNodeTests.swift new file mode 100644 index 0000000..d6cba6c --- /dev/null +++ b/Tests/Runtime/Generic/SignedIntNodeTests.swift @@ -0,0 +1,57 @@ +import XCTest +import SubstrateSdk +import BigInt + +class SignedIntNodeTests: XCTestCase { + let typeRegistry = try! RuntimeHelper.createTypeRegistryCatalog( + from: "default", + networkName: "westend", + runtimeMetadataName: "westend-metadata" + ) + + func testSignedIntEncodingDecoding() { + let bitLengths = [8, 16, 32, 64, 128, 256] + + bitLengths.forEach { bitLength in + let type = "I\(bitLength)" + performEncodingDecodingTest(for: .stringValue("0"), type: type) + performEncodingDecodingTest(for: .stringValue("1"), type: type) + performEncodingDecodingTest(for: .stringValue("-1"), type: type) + performEncodingDecodingTest(for: .stringValue("127"), type: type) + performEncodingDecodingTest(for: .stringValue("-127"), type: type) + performEncodingDecodingTest(for: .stringValue("53"), type: type) + performEncodingDecodingTest(for: .stringValue("-53"), type: type) + + let typeValue = BigUInt(1) << (bitLength - 2) + let positiveValue = String(typeValue) + let negativeValue = "-" + String(typeValue) + + performEncodingDecodingTest(for: .stringValue(positiveValue), type: type) + performEncodingDecodingTest(for: .stringValue(negativeValue), type: type) + } + } + + // MARK: Private + + private func performEncodingDecodingTest(for value: JSON, type: String) { + do { + let encodedValue = try performEncoding(value: value, type: type) + try performDecodingTest(data: encodedValue, type: type, expected: value) + } catch { + XCTFail("Unexpected error: \(error)") + } + } + + private func performDecodingTest(data: Data, type: String, expected: JSON) throws { + let decoder = try DynamicScaleDecoder(data: data, registry: typeRegistry, version: 45) + let result = try decoder.read(type: type) + XCTAssertEqual(expected, result) + XCTAssertEqual(decoder.remained, 0) + } + + private func performEncoding(value: JSON, type: String) throws -> Data { + let encoder = DynamicScaleEncoder(registry: typeRegistry, version: 45) + try encoder.append(json: value, type: type) + return try encoder.encode() + } +}