From 07a33cb3574293a0a3699418622f94243bd08b9c Mon Sep 17 00:00:00 2001 From: Yaroslav Erohin Date: Thu, 27 Dec 2018 13:09:05 +0300 Subject: [PATCH 1/6] Get account actions --- Sources/SwiftyEOS/Models/ActionModels.swift | 61 +++++++++++++++++++ .../Network/History/EOSRPC+History.swift | 8 +++ .../Network/History/HistoryRouter.swift | 10 ++- SwiftyEOS.xcodeproj/project.pbxproj | 4 ++ 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 Sources/SwiftyEOS/Models/ActionModels.swift diff --git a/Sources/SwiftyEOS/Models/ActionModels.swift b/Sources/SwiftyEOS/Models/ActionModels.swift new file mode 100644 index 0000000..bee2ce9 --- /dev/null +++ b/Sources/SwiftyEOS/Models/ActionModels.swift @@ -0,0 +1,61 @@ +// +// ActionModels.swift +// SwiftyEOS +// +// Created by ysoftware on 27/12/2018. +// Copyright © 2018 ProChain. All rights reserved. +// + +import Foundation + +struct ActionsResult: Codable { + let actions:[ActionReceipt] + let lastIrreversibleBlock:Int +} + +struct ActionReceipt: Codable { + let blockNum:Int + let globalActionSeq:Int + let accountActionSeq:Int + let blockTime:String + let actionTrace: ActionTrace +} + +struct ActionTrace: Codable { + let receipt:Receipt + let act:ActionDetails + let contextFree:Bool + let elapsed:Int + let console:String + let trxId:String + let blockNum:Int + let blockTime:String + let producerBlockId:String + let accountRamDeltas:[ActionRamDelta] + // TO-DO: unknown types for these fields +// let except:Int? +// let inlineTraces:[Int] +} + +struct ActionRamDelta: Codable { + let account:String + let delta:Int +} + +struct Receipt: Codable { + let receiver:String + let actDigest:String + let globalSequence: Int + let recvSequence:Int + let authSequence:[AnyCodable] + let codeSequence:Int + let abiSequence:Int +} + +struct ActionDetails: Codable { + let authorization: [Authorization] + let data: [String:AnyCodable] + let account: String + let name: String + let hexData: String +} diff --git a/Sources/SwiftyEOS/Network/History/EOSRPC+History.swift b/Sources/SwiftyEOS/Network/History/EOSRPC+History.swift index 2d02789..3f4f122 100644 --- a/Sources/SwiftyEOS/Network/History/EOSRPC+History.swift +++ b/Sources/SwiftyEOS/Network/History/EOSRPC+History.swift @@ -13,4 +13,12 @@ extension EOSRPC { let router = HistoryRouter(endpoint: .GetKeyAccounts(pub: pub)) internalRequest(router: router, completion: completion) } + + func getActions(accountName: String, position: Int, offset: Int, + completion: @escaping (_ result: ActionsResult?, _ error: Error?) -> Void) { + let router = HistoryRouter(endpoint: .GetActions(accountName: accountName, + pos: position, + offset: offset)) + internalRequest(router: router, completion: completion) + } } diff --git a/Sources/SwiftyEOS/Network/History/HistoryRouter.swift b/Sources/SwiftyEOS/Network/History/HistoryRouter.swift index 83f97ea..828d9f9 100644 --- a/Sources/SwiftyEOS/Network/History/HistoryRouter.swift +++ b/Sources/SwiftyEOS/Network/History/HistoryRouter.swift @@ -10,6 +10,7 @@ import Foundation enum HistoryEndpoint { case GetKeyAccounts(pub: String) + case GetActions(accountName: String, pos: Int, offset: Int) } class HistoryRouter: BaseRouter { @@ -20,13 +21,15 @@ class HistoryRouter: BaseRouter { override var method: HTTPMethod { switch endpoint { - case .GetKeyAccounts: return .post + case .GetKeyAccounts: return .post + case .GetActions: return .post } } override var path: String { switch endpoint { case .GetKeyAccounts: return "/history/get_key_accounts" + case .GetActions: return "/history/get_actions" } } @@ -37,11 +40,14 @@ class HistoryRouter: BaseRouter { } override var body: Data? { + let encoder = JSONEncoder() switch endpoint { case .GetKeyAccounts(let pub): - let encoder = JSONEncoder() let jsonData = try! encoder.encode(["public_key": "\(pub)"]) return jsonData + case .GetActions(let accountName, let pos, let offset): + let data = ["account_name": accountName, "pos": "\(pos)", "offset": "\(offset)"] + return try! encoder.encode(data) } } } diff --git a/SwiftyEOS.xcodeproj/project.pbxproj b/SwiftyEOS.xcodeproj/project.pbxproj index bca7e09..cddbd25 100644 --- a/SwiftyEOS.xcodeproj/project.pbxproj +++ b/SwiftyEOS.xcodeproj/project.pbxproj @@ -109,6 +109,7 @@ 27FC751520BD247700435C50 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27FC751220BD247700435C50 /* AnyDecodable.swift */; }; 27FC751620BD247700435C50 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27FC751320BD247700435C50 /* AnyCodable.swift */; }; 27FC751720BD247700435C50 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27FC751420BD247700435C50 /* AnyEncodable.swift */; }; + 71C2439B21D4D14F00E86F64 /* ActionModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71C2439A21D4D14F00E86F64 /* ActionModels.swift */; }; /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ @@ -220,6 +221,7 @@ 27FC751220BD247700435C50 /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = ""; }; 27FC751320BD247700435C50 /* AnyCodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = ""; }; 27FC751420BD247700435C50 /* AnyEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = ""; }; + 71C2439A21D4D14F00E86F64 /* ActionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModels.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -567,6 +569,7 @@ 27FC74F920BD10B900435C50 /* Models */ = { isa = PBXGroup; children = ( + 71C2439A21D4D14F00E86F64 /* ActionModels.swift */, 27FC74FA20BD10B900435C50 /* ChainModels.swift */, 27FC74FB20BD10B900435C50 /* BigInt.swift */, 2783777920F8A308003CC8DB /* Error.swift */, @@ -793,6 +796,7 @@ 2720E71B21257D9E00643AE6 /* TransactionUtil.swift in Sources */, 27FC750E20BD10B900435C50 /* main.swift in Sources */, 2730778E21916C1B0099E6B0 /* sha3.c in Sources */, + 71C2439B21D4D14F00E86F64 /* ActionModels.swift in Sources */, 27FC750D20BD10B900435C50 /* BigInt.swift in Sources */, 27FC750C20BD10B900435C50 /* ChainModels.swift in Sources */, 27FC750920BD10B900435C50 /* KeyPair.swift in Sources */, From 29d1e3acd7057fb63d87ea1d2c45dd440f297149 Mon Sep 17 00:00:00 2001 From: Yaroslav Erohin Date: Thu, 27 Dec 2018 16:01:25 +0300 Subject: [PATCH 2/6] producer block id can be null on a testnode --- Sources/SwiftyEOS/Models/ActionModels.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftyEOS/Models/ActionModels.swift b/Sources/SwiftyEOS/Models/ActionModels.swift index bee2ce9..bf6fdc6 100644 --- a/Sources/SwiftyEOS/Models/ActionModels.swift +++ b/Sources/SwiftyEOS/Models/ActionModels.swift @@ -30,7 +30,7 @@ struct ActionTrace: Codable { let trxId:String let blockNum:Int let blockTime:String - let producerBlockId:String + let producerBlockId:String? // can be null on a testnode let accountRamDeltas:[ActionRamDelta] // TO-DO: unknown types for these fields // let except:Int? From 5e1389832f8e795861cf72a606c64013991a472a Mon Sep 17 00:00:00 2001 From: Yaroslav Erohin Date: Fri, 28 Dec 2018 10:17:42 +0300 Subject: [PATCH 3/6] data can be also be an empty string decided to use AnyCodable for action data since it can be either a dictionary or an empty string --- Sources/SwiftyEOS/Models/ActionModels.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftyEOS/Models/ActionModels.swift b/Sources/SwiftyEOS/Models/ActionModels.swift index bf6fdc6..ce286aa 100644 --- a/Sources/SwiftyEOS/Models/ActionModels.swift +++ b/Sources/SwiftyEOS/Models/ActionModels.swift @@ -54,7 +54,7 @@ struct Receipt: Codable { struct ActionDetails: Codable { let authorization: [Authorization] - let data: [String:AnyCodable] + let data: AnyCodable let account: String let name: String let hexData: String From 63110b61b8d913ee748237d92aa8b80ced898817 Mon Sep 17 00:00:00 2001 From: Yaroslav Erohin Date: Fri, 28 Dec 2018 10:18:07 +0300 Subject: [PATCH 4/6] hexData can be null --- Sources/SwiftyEOS/Models/ActionModels.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftyEOS/Models/ActionModels.swift b/Sources/SwiftyEOS/Models/ActionModels.swift index ce286aa..32524c0 100644 --- a/Sources/SwiftyEOS/Models/ActionModels.swift +++ b/Sources/SwiftyEOS/Models/ActionModels.swift @@ -57,5 +57,5 @@ struct ActionDetails: Codable { let data: AnyCodable let account: String let name: String - let hexData: String + let hexData: String? } From 07efa056fde9f225aae076cb3744b7d24115cd6b Mon Sep 17 00:00:00 2001 From: Yaroslav Erohin Date: Wed, 9 Jan 2019 12:33:27 +0300 Subject: [PATCH 5/6] inline traces array type --- Sources/SwiftyEOS/Models/ActionModels.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftyEOS/Models/ActionModels.swift b/Sources/SwiftyEOS/Models/ActionModels.swift index 32524c0..47422e8 100644 --- a/Sources/SwiftyEOS/Models/ActionModels.swift +++ b/Sources/SwiftyEOS/Models/ActionModels.swift @@ -32,9 +32,9 @@ struct ActionTrace: Codable { let blockTime:String let producerBlockId:String? // can be null on a testnode let accountRamDeltas:[ActionRamDelta] + let inlineTraces:[ActionTrace] // TO-DO: unknown types for these fields // let except:Int? -// let inlineTraces:[Int] } struct ActionRamDelta: Codable { From e28e84044a276d0e31f730855d5e633d66032367 Mon Sep 17 00:00:00 2001 From: Yaroslav Erohin Date: Fri, 25 Jan 2019 11:43:36 +0300 Subject: [PATCH 6/6] correctly parse action sequence After reaching sequence number of 2^32, sequence value is being represented as a string instead of int --- Sources/SwiftyEOS/Models/ActionModels.swift | 22 ++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftyEOS/Models/ActionModels.swift b/Sources/SwiftyEOS/Models/ActionModels.swift index 47422e8..744f626 100644 --- a/Sources/SwiftyEOS/Models/ActionModels.swift +++ b/Sources/SwiftyEOS/Models/ActionModels.swift @@ -8,6 +8,19 @@ import Foundation +// After reaching sequence number of 2^32, sequence value is being represented as a string instead of int +// This is used to make sure both options work +typealias ActionSeq = AnyCodable + +// Use intValue to unpack sequence number as Int +extension ActionSeq { + var intValue:Int { + if let i = value as? Int { return i } + else if let s = value as? String, let i = Int(s) { return i } + return 0 // fall back + } +} + struct ActionsResult: Codable { let actions:[ActionReceipt] let lastIrreversibleBlock:Int @@ -15,8 +28,8 @@ struct ActionsResult: Codable { struct ActionReceipt: Codable { let blockNum:Int - let globalActionSeq:Int - let accountActionSeq:Int + let globalActionSeq:ActionSeq + let accountActionSeq:ActionSeq let blockTime:String let actionTrace: ActionTrace } @@ -33,8 +46,7 @@ struct ActionTrace: Codable { let producerBlockId:String? // can be null on a testnode let accountRamDeltas:[ActionRamDelta] let inlineTraces:[ActionTrace] - // TO-DO: unknown types for these fields -// let except:Int? + let except:AnyCodable? } struct ActionRamDelta: Codable { @@ -45,7 +57,7 @@ struct ActionRamDelta: Codable { struct Receipt: Codable { let receiver:String let actDigest:String - let globalSequence: Int + let globalSequence: ActionSeq let recvSequence:Int let authSequence:[AnyCodable] let codeSequence:Int