Skip to content

Commit 39a9996

Browse files
author
Alex Vlasov
committed
add plain keystores
finalize event filtering by indexed parameters
1 parent 883ecaa commit 39a9996

File tree

7 files changed

+230
-172
lines changed

7 files changed

+230
-172
lines changed

web3swift.xcodeproj/project.pbxproj

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,10 @@
146146
81C5DA322074EC1E00424CD6 /* ContractProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81C5DA302074EC1E00424CD6 /* ContractProtocol.swift */; };
147147
81D7D97220A31FB700A193EC /* ComparisonExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D7D97120A31FB700A193EC /* ComparisonExtensions.swift */; };
148148
81D7D97320A31FB700A193EC /* ComparisonExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D7D97120A31FB700A193EC /* ComparisonExtensions.swift */; };
149-
81D7D97520A3240900A193EC /* EthereumStringEncodingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D7D97420A3240900A193EC /* EthereumStringEncodingExtensions.swift */; };
150-
81D7D97620A3240900A193EC /* EthereumStringEncodingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D7D97420A3240900A193EC /* EthereumStringEncodingExtensions.swift */; };
149+
81D7D97520A3240900A193EC /* EthereumFilterEncodingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D7D97420A3240900A193EC /* EthereumFilterEncodingExtensions.swift */; };
150+
81D7D97620A3240900A193EC /* EthereumFilterEncodingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D7D97420A3240900A193EC /* EthereumFilterEncodingExtensions.swift */; };
151+
81D7D97820A61E3800A193EC /* EventFiltering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D7D97720A61E3800A193EC /* EventFiltering.swift */; };
152+
81D7D97920A61E3800A193EC /* EventFiltering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D7D97720A61E3800A193EC /* EventFiltering.swift */; };
151153
81DDECCF1FDF004E0063684A /* Web3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81DDECCE1FDF004E0063684A /* Web3.swift */; };
152154
81EB1E4B208173D7003BD47F /* Web3+Personal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81EB1E4A208173D7003BD47F /* Web3+Personal.swift */; };
153155
81EB1E4C208173D7003BD47F /* Web3+Personal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81EB1E4A208173D7003BD47F /* Web3+Personal.swift */; };
@@ -280,7 +282,8 @@
280282
81C5DA2D2074EBF500424CD6 /* ContractABIv2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContractABIv2.swift; sourceTree = "<group>"; };
281283
81C5DA302074EC1E00424CD6 /* ContractProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContractProtocol.swift; sourceTree = "<group>"; };
282284
81D7D97120A31FB700A193EC /* ComparisonExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComparisonExtensions.swift; sourceTree = "<group>"; };
283-
81D7D97420A3240900A193EC /* EthereumStringEncodingExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumStringEncodingExtensions.swift; sourceTree = "<group>"; };
285+
81D7D97420A3240900A193EC /* EthereumFilterEncodingExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumFilterEncodingExtensions.swift; sourceTree = "<group>"; };
286+
81D7D97720A61E3800A193EC /* EventFiltering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventFiltering.swift; sourceTree = "<group>"; };
284287
81DDECCE1FDF004E0063684A /* Web3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Web3.swift; sourceTree = "<group>"; };
285288
81EB1E4A208173D7003BD47F /* Web3+Personal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Web3+Personal.swift"; sourceTree = "<group>"; };
286289
81FA43F32044097000EE14D5 /* web3swift-macOS_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "web3swift-macOS_Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -546,7 +549,8 @@
546549
81C5DA2D2074EBF500424CD6 /* ContractABIv2.swift */,
547550
81C5DA302074EC1E00424CD6 /* ContractProtocol.swift */,
548551
81D7D97120A31FB700A193EC /* ComparisonExtensions.swift */,
549-
81D7D97420A3240900A193EC /* EthereumStringEncodingExtensions.swift */,
552+
81D7D97420A3240900A193EC /* EthereumFilterEncodingExtensions.swift */,
553+
81D7D97720A61E3800A193EC /* EventFiltering.swift */,
550554
);
551555
path = Classes;
552556
sourceTree = "<group>";
@@ -1028,7 +1032,7 @@
10281032
8125F0662047D9FF00A0F2FE /* ABIEncoder.swift in Sources */,
10291033
8113D2C61FD7E1590074282C /* LibSecp256k1Extension.swift in Sources */,
10301034
81EB1E4B208173D7003BD47F /* Web3+Personal.swift in Sources */,
1031-
81D7D97520A3240900A193EC /* EthereumStringEncodingExtensions.swift in Sources */,
1035+
81D7D97520A3240900A193EC /* EthereumFilterEncodingExtensions.swift in Sources */,
10321036
817EBB122004FE2F00E02EAA /* BIP32HDNode.swift in Sources */,
10331037
8113D2C41FD7E1590074282C /* CryptoExtensions.swift in Sources */,
10341038
8103BBB72076391F00499769 /* Web3+Concurrency.swift in Sources */,
@@ -1052,6 +1056,7 @@
10521056
81C5DA16207261C800424CD6 /* ABIRecordParser.swift in Sources */,
10531057
81C5DA282072E18200424CD6 /* NativeTypesEncoding+Extensions.swift in Sources */,
10541058
8123E1C7200CBAC200B6D3AB /* Dictionary+Extension.swift in Sources */,
1059+
81D7D97820A61E3800A193EC /* EventFiltering.swift in Sources */,
10551060
8103BBC920779E2200499769 /* Web3+TransactionAndBlockDetailsOperations.swift in Sources */,
10561061
81FB21F12078142D007F9A83 /* Web3+Deprecated.swift in Sources */,
10571062
810B0F9C1FEC520500CF0DA2 /* Web3+Methods.swift in Sources */,
@@ -1117,7 +1122,7 @@
11171122
8125F0672047D9FF00A0F2FE /* ABIEncoder.swift in Sources */,
11181123
41948125203630530065A83B /* Web3+Methods.swift in Sources */,
11191124
81EB1E4C208173D7003BD47F /* Web3+Personal.swift in Sources */,
1120-
81D7D97620A3240900A193EC /* EthereumStringEncodingExtensions.swift in Sources */,
1125+
81D7D97620A3240900A193EC /* EthereumFilterEncodingExtensions.swift in Sources */,
11211126
41948126203630530065A83B /* Web3+Eth.swift in Sources */,
11221127
8103BBB82076391F00499769 /* Web3+Concurrency.swift in Sources */,
11231128
81C5DA262072E14E00424CD6 /* ABIv2Encoding.swift in Sources */,
@@ -1141,6 +1146,7 @@
11411146
81C5DA292072E18200424CD6 /* NativeTypesEncoding+Extensions.swift in Sources */,
11421147
41948130203630530065A83B /* BIP32Keystore.swift in Sources */,
11431148
8103BBCA20779E2200499769 /* Web3+TransactionAndBlockDetailsOperations.swift in Sources */,
1149+
81D7D97920A61E3800A193EC /* EventFiltering.swift in Sources */,
11441150
81FB21F22078142D007F9A83 /* Web3+Deprecated.swift in Sources */,
11451151
41948131203630530065A83B /* BIP32KeystoreJSONStructure.swift in Sources */,
11461152
41948132203630530065A83B /* BIP32HDNode.swift in Sources */,

web3swift/Concurrency/Classes/Web3+EventOperations.swift

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -119,45 +119,10 @@ final class ParseTransactionForEventsOperation: Web3Operation {
119119
let receiptCallback = { (res: Result<AnyObject, Web3Error>) -> () in
120120
switch res {
121121
case .success(let result):
122-
var allEvents = [EventParserResultProtocol]()
123122
guard let receipt = result as? TransactionReceipt else {
124123
return self.processError(Web3Error.dataError)
125124
}
126-
guard let bloom = receipt.logsBloom else {
127-
return self.processError(Web3Error.dataError)
128-
}
129-
if contract.address != nil {
130-
let addressPresent = bloom.test(topic: contract.address!.addressData)
131-
if (addressPresent != true) {
132-
return self.processSuccess(allEvents as AnyObject)
133-
}
134-
}
135-
guard let eventOfSuchTypeIsPresent = contract.testBloomForEventPrecence(eventName: eventName, bloom: bloom) else {
136-
return self.processError(Web3Error.dataError)
137-
}
138-
if (!eventOfSuchTypeIsPresent) {
139-
return self.processSuccess(allEvents as AnyObject)
140-
}
141-
var allLogs = receipt.logs
142-
if contract.address != nil {
143-
allLogs = receipt.logs.filter({ (log) -> Bool in
144-
log.address == contract.address
145-
})
146-
}
147-
let decodedLogs = allLogs.compactMap({ (log) -> EventParserResultProtocol? in
148-
let (n, d) = contract.parseEvent(log)
149-
guard let evName = n, let evData = d else {return nil}
150-
return EventParserResult(eventName: evName, transactionReceipt: receipt, contractAddress: log.address, decodedResult: evData)
151-
}).filter { (res:EventParserResultProtocol?) -> Bool in
152-
return res != nil && res?.eventName == eventName
153-
}
154-
155-
if (filter != nil) {
156-
// TODO NYI
157-
allEvents = decodedLogs
158-
} else {
159-
allEvents = decodedLogs
160-
}
125+
guard let allEvents = parseReceiptForLogs(receipt: receipt, contract: contract, eventName: eventName, filter: filter) else {return self.processError(Web3Error.dataError)}
161126
return self.processSuccess(allEvents as AnyObject)
162127
case .failure(let error):
163128
return self.processError(error)
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
//
2+
// EventFiltering.swift
3+
// web3swift
4+
//
5+
// Created by Alexander Vlasov on 11.05.2018.
6+
// Copyright © 2018 Bankex Foundation. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
12+
internal func filterLogs(decodedLogs: [EventParserResultProtocol], eventFilter: EventFilter) -> [EventParserResultProtocol] {
13+
let filteredLogs = decodedLogs.filter { (result) -> Bool in
14+
if eventFilter.addresses == nil {
15+
return true
16+
} else {
17+
if eventFilter.addresses!.contains(result.contractAddress) {
18+
return true
19+
} else {
20+
return false
21+
}
22+
}
23+
}.filter { (result) -> Bool in
24+
if eventFilter.parameterFilters == nil {
25+
return true
26+
} else {
27+
let keys = result.decodedResult.keys.filter({ (key) -> Bool in
28+
if let _ = UInt64(key) {
29+
return true
30+
}
31+
return false
32+
})
33+
if keys.count < eventFilter.parameterFilters!.count {
34+
return false
35+
}
36+
for i in 0 ..< eventFilter.parameterFilters!.count {
37+
let allowedValues = eventFilter.parameterFilters![i]
38+
let actualValue = result.decodedResult["\(i)"]
39+
if actualValue == nil {
40+
return false
41+
}
42+
if allowedValues == nil {
43+
continue
44+
}
45+
var inAllowed = false
46+
for value in allowedValues! {
47+
if value.isEqualTo(actualValue! as AnyObject) {
48+
inAllowed = true
49+
break
50+
}
51+
}
52+
if !inAllowed {
53+
return false
54+
}
55+
}
56+
return true
57+
}
58+
}
59+
return filteredLogs
60+
}
61+
62+
internal func encodeTopicToGetLogs(contract: ContractV2, eventName: String?, filter: EventFilter) -> EventFilterParameters? {
63+
var eventTopic: Data? = nil
64+
var event: ABIv2.Element.Event? = nil
65+
if eventName != nil {
66+
guard let ev = contract.events[eventName!] else {return nil}
67+
event = ev
68+
eventTopic = ev.topic
69+
}
70+
var topics = [[String?]?]()
71+
if eventTopic != nil {
72+
topics.append([eventTopic!.toHexString().addHexPrefix()])
73+
} else {
74+
topics.append(nil as [String?]?)
75+
}
76+
if filter.parameterFilters != nil {
77+
if event == nil {return nil}
78+
var lastNonemptyFilter = 0
79+
for i in 0 ..< filter.parameterFilters!.count {
80+
let filterValue = filter.parameterFilters![i]
81+
if filterValue != nil {
82+
lastNonemptyFilter = i
83+
}
84+
}
85+
if lastNonemptyFilter != 0 {
86+
guard lastNonemptyFilter <= event!.inputs.count else {return nil}
87+
for i in 0 ... lastNonemptyFilter {
88+
let filterValues = filter.parameterFilters![i]
89+
let input = event!.inputs[i]
90+
if filterValues != nil && !input.indexed {return nil}
91+
if filterValues == nil {
92+
topics.append(nil as [String?]?)
93+
continue
94+
}
95+
var encodings = [String]()
96+
for val in filterValues! {
97+
guard let enc = val.eventFilterEncoded() else {return nil}
98+
encodings.append(enc)
99+
}
100+
topics.append(encodings)
101+
}
102+
}
103+
}
104+
var preEncoding = filter.rpcPreEncode()
105+
preEncoding.topics = topics
106+
return preEncoding
107+
}
108+
109+
internal func parseReceiptForLogs(receipt: TransactionReceipt, contract: ContractProtocol, eventName: String, filter: EventFilter?) -> [EventParserResultProtocol]? {
110+
guard let bloom = receipt.logsBloom else {return nil}
111+
if contract.address != nil {
112+
let addressPresent = bloom.test(topic: contract.address!.addressData)
113+
if (addressPresent != true) {
114+
return [EventParserResultProtocol]()
115+
}
116+
}
117+
if filter != nil, let filterAddresses = filter?.addresses {
118+
var oneIsPresent = false
119+
for addr in filterAddresses {
120+
let addressPresent = bloom.test(topic: addr.addressData)
121+
if (addressPresent == true) {
122+
oneIsPresent = true
123+
break
124+
}
125+
}
126+
if (oneIsPresent != true) {
127+
return [EventParserResultProtocol]()
128+
}
129+
}
130+
guard let eventOfSuchTypeIsPresent = contract.testBloomForEventPrecence(eventName: eventName, bloom: bloom) else {return nil}
131+
if (!eventOfSuchTypeIsPresent) {
132+
return [EventParserResultProtocol]()
133+
}
134+
var allLogs = receipt.logs
135+
if (contract.address != nil) {
136+
allLogs = receipt.logs.filter({ (log) -> Bool in
137+
log.address == contract.address
138+
})
139+
}
140+
let decodedLogs = allLogs.compactMap({ (log) -> EventParserResultProtocol? in
141+
let (n, d) = contract.parseEvent(log)
142+
guard let evName = n, let evData = d else {return nil}
143+
return EventParserResult(eventName: evName, transactionReceipt: receipt, contractAddress: log.address, decodedResult: evData)
144+
}).filter { (res:EventParserResultProtocol?) -> Bool in
145+
return res != nil && res?.eventName == eventName
146+
}
147+
var allResults = [EventParserResultProtocol]()
148+
if (filter != nil) {
149+
let eventFilter = filter!
150+
let filteredLogs = filterLogs(decodedLogs: decodedLogs, eventFilter: eventFilter)
151+
allResults = filteredLogs
152+
} else {
153+
allResults = decodedLogs
154+
}
155+
return allResults
156+
}

web3swift/KeystoreManager/Classes/KeystoreManager.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public class KeystoreManager: AbstractKeystore {
2828
}
2929
}
3030
}
31+
for keystore in _plainKeystores {
32+
guard let key = keystore.addresses?.first else {continue}
33+
if key.isValid {
34+
toReturn.append(key)
35+
}
36+
}
3137
return toReturn
3238
}
3339
}
@@ -67,11 +73,18 @@ public class KeystoreManager: AbstractKeystore {
6773
}
6874
}
6975
}
76+
for keystore in _plainKeystores {
77+
guard let key = keystore.addresses?.first else {continue}
78+
if key == address && key.isValid {
79+
return keystore as AbstractKeystore?
80+
}
81+
}
7082
return nil
7183
}
7284

7385
var _keystores:[EthereumKeystoreV3] = [EthereumKeystoreV3]()
7486
var _bip32keystores: [BIP32Keystore] = [BIP32Keystore]()
87+
var _plainKeystores: [PlainKeystore] = [PlainKeystore]()
7588

7689
public var keystores:[EthereumKeystoreV3] {
7790
get {
@@ -85,6 +98,12 @@ public class KeystoreManager: AbstractKeystore {
8598
}
8699
}
87100

101+
public var plainKeystores:[PlainKeystore] {
102+
get {
103+
return self._plainKeystores
104+
}
105+
}
106+
88107
public init(_ keystores: [EthereumKeystoreV3]) {
89108
self.isHDKeystore = false
90109
self._keystores = keystores
@@ -97,6 +116,12 @@ public class KeystoreManager: AbstractKeystore {
97116
self.path = "bip32"
98117
}
99118

119+
public init(_ keystores: [PlainKeystore]) {
120+
self.isHDKeystore = false
121+
self._plainKeystores = keystores
122+
self.path="plain"
123+
}
124+
100125
private init?(_ path: String, scanForHDwallets: Bool = false, suffix: String? = nil) throws {
101126
if (scanForHDwallets) {
102127
self.isHDKeystore = true

0 commit comments

Comments
 (0)