diff --git a/Sources/Core/Transaction/EthereumTransaction.swift b/Sources/Core/Transaction/EthereumTransaction.swift index c44bcc4a..d78bdc08 100644 --- a/Sources/Core/Transaction/EthereumTransaction.swift +++ b/Sources/Core/Transaction/EthereumTransaction.swift @@ -577,10 +577,10 @@ extension EthereumSignedTransaction: RLPItemConvertible { accessList: accessList, transactionType: .eip1559 ) + } else { + // Unsupported transaction types + throw Error.rlpItemInvalid } - - // Unsupported transaction types - throw Error.rlpItemInvalid } public func rlp() -> RLPItem { diff --git a/Tests/Web3Tests/TransactionTests/TransactionTests.swift b/Tests/Web3Tests/TransactionTests/TransactionTests.swift index da45f6c1..3988a143 100644 --- a/Tests/Web3Tests/TransactionTests/TransactionTests.swift +++ b/Tests/Web3Tests/TransactionTests/TransactionTests.swift @@ -125,6 +125,82 @@ class TransactionTests: QuickSpec { expect(extendedSignature!.verifySignature()) == true } } + context("Init from RLP Item") { + let p = try? EthereumPrivateKey( + hexPrivateKey: "0x94eca03b4541a0eb0d173e321b6f960d08cfe4c5a75fa00ebe0a3d283c609c3a" + ) + let t = p?.address + + guard let to = t, let privateKey = p else { + return + } + + // Legacy Tx + + let tx = EthereumTransaction(nonce: 0, gasPrice: EthereumQuantity(quantity: 21.gwei), gasLimit: 21000, to: to, value: EthereumQuantity(quantity: 1.eth)) + + // Sign transaction with private key + let newTx = try? tx.sign(with: privateKey, chainId: 3) + it("should not be nil") { + expect(newTx).toNot(beNil()) + } + let rlpEncoder = RLPEncoder() + let rlpEncodedBasicTxBytes = try? rlpEncoder.encode(newTx!.rlp()) + let rlpDecoder = RLPDecoder() + let rlpEncodedBasicTx = try? rlpDecoder.decode(rlpEncodedBasicTxBytes!) + + let expectedSignedBasicTx = try? EthereumSignedTransaction(rlp: rlpEncodedBasicTx!) + + let expectedTransaction = "0xf86c808504e3b2920082520894867aeeeed428ed9ba7f97fc7e16f16dfcf02f375880de0b6b3a76400008029a099060c9146c68716da3a79533866dc941a03b171911d675f518c97a73882f7a6a0019167adb26b602501c954e7793e798407836f524b9778f5be6ebece5fc998c6" + + it("should produce the expected transaction") { + expect(try? expectedSignedBasicTx!.rawTransaction().bytes.hexString(prefix: true)) == expectedTransaction + } + + // Modern Tx + + let extendedTx = try! EthereumTransaction( + nonce: 0, + gasPrice: EthereumQuantity(quantity: 21.gwei), + maxFeePerGas: EthereumQuantity(quantity: 21.gwei), + maxPriorityFeePerGas: EthereumQuantity(quantity: 1.gwei), + gasLimit: 21000, + to: to, + value: EthereumQuantity(quantity: 1.eth), + data: EthereumData("0x02f8730180843b9aca008504e3b2920082".hexBytes()), + accessList: [ + try! EthereumAddress(hex: "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", eip55: false): [ + EthereumData(ethereumValue: "0x0000000000000000000000000000000000000000000000000000000000000003"), + EthereumData(ethereumValue: "0x0000000000000000000000000000000000000000000000000000000000000007") + ], + try! EthereumAddress(hex: "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", eip55: false): [], + ], + transactionType: .eip1559 + ) + let extendedSignature = try? extendedTx.sign(with: privateKey, chainId: 3) + + let rlpEncodedTxBytes = try? rlpEncoder.encode(extendedSignature!.rlp()) + let rlpEncodedTx = try? rlpDecoder.decode(rlpEncodedTxBytes!) + + let expectedSignedTx = try? EthereumSignedTransaction(rlp: rlpEncodedTx!) + + let expectedExtendedTx = "0x02f8f70380843b9aca008504e3b2920082520894867aeeeed428ed9ba7f97fc7e16f16dfcf02f375880de0b6b3a76400009102f8730180843b9aca008504e3b2920082f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697baef842a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000007d694bb9bc244d798123fde783fcc1c72d3bb8c189413c080a0e0cd5f5e03d10e3d792fb652f6d1ea470cb6cdf745462980dff1652904cc4ed5a06f8b372427d15b68158597cd547c0f77165563da6a0b954d575920888edaf36c" + + it("should produce the expected transaction") { + expect(try? expectedSignedTx!.rawTransaction().bytes.hexString(prefix: true)) == expectedExtendedTx + } + + it("should be a valid tx") { + expect(expectedSignedTx!.verifySignature()) == true + } + + // Invalid RLP Item + + let nonTxRlpItem: RLPItem = [] + it("should throw on invalid RLP Items") { + expect(try EthereumSignedTransaction(rlp: nonTxRlpItem)).to(throwError()) + } + } } } } diff --git a/Tests/Web3Tests/Web3Tests/Web3EventsTests.swift b/Tests/Web3Tests/Web3Tests/Web3EventsTests.swift index a41fdb2d..14d6a3bb 100644 --- a/Tests/Web3Tests/Web3Tests/Web3EventsTests.swift +++ b/Tests/Web3Tests/Web3Tests/Web3EventsTests.swift @@ -6,6 +6,7 @@ import PromiseKit #if canImport(Web3PromiseKit) @testable import Web3PromiseKit #endif +import NIOConcurrencyHelpers class Web3EventsTests: QuickSpec { @@ -42,14 +43,14 @@ class Web3EventsTests: QuickSpec { it("should subscribe and unsubscribe to new heads") { waitUntil(timeout: .seconds(30)) { done in var subId = "" - var cancelled = false + var cancelled = NIOLockedValueBox(false) try! web3Ws.eth.subscribeToNewHeads(subscribed: { response in expect(response.result).toNot(beNil()) subId = response.result ?? "" }, onEvent: { newHead in guard let _ = newHead.result else { - if cancelled { + if cancelled.withLockedValue({ $0 }) { switch (newHead.error as? Web3Response.Error) { case .subscriptionCancelled(_): // Expected @@ -64,9 +65,11 @@ class Web3EventsTests: QuickSpec { } // Tests done. Test unsubscribe. - if !cancelled { - cancelled = true - + if !cancelled.withLockedValue({ + let old = $0 + $0 = true + return old + }) { try! web3Ws.eth.unsubscribe(subscriptionId: subId, completion: { unsubscribed in expect(unsubscribed).to(beTrue()) @@ -82,14 +85,14 @@ class Web3EventsTests: QuickSpec { it("should subscribe and unsubscribe to new pending transactions") { waitUntil(timeout: .seconds(5)) { done in var subId = "" - var cancelled = false + var cancelled = NIOLockedValueBox(false) try! web3Ws.eth.subscribeToNewPendingTransactions(subscribed: { response in expect(response.result).toNot(beNil()) subId = response.result ?? "" }, onEvent: { hash in guard let hashValue = hash.result else { - if cancelled { + if cancelled.withLockedValue({ $0 }) { switch (hash.error as? Web3Response.Error) { case .subscriptionCancelled(_): // Expected @@ -106,9 +109,11 @@ class Web3EventsTests: QuickSpec { expect(hashValue.bytes.count).to(equal(32)) // Tests done. Test unsubscribe. - if !cancelled { - cancelled = true - + if !cancelled.withLockedValue({ + let old = $0 + $0 = true + return old + }) { try! web3Ws.eth.unsubscribe(subscriptionId: subId, completion: { unsubscribed in expect(unsubscribed).to(beTrue()) @@ -124,14 +129,14 @@ class Web3EventsTests: QuickSpec { it("should subscribe and unsubscribe to all logs") { waitUntil(timeout: .seconds(60)) { done in var subId = "" - var cancelled = false + var cancelled = NIOLockedValueBox(false) try! web3Ws.eth.subscribeToLogs(subscribed: { response in expect(response.result).toNot(beNil()) subId = response.result ?? "" }, onEvent: { log in guard let _ = log.result else { - if cancelled { + if cancelled.withLockedValue({ $0 }) { switch (log.error as? Web3Response.Error) { case .subscriptionCancelled(_): // Expected @@ -146,9 +151,11 @@ class Web3EventsTests: QuickSpec { } // Tests done. Test unsubscribe. - if !cancelled { - cancelled = true - + if !cancelled.withLockedValue({ + let old = $0 + $0 = true + return old + }) { try! web3Ws.eth.unsubscribe(subscriptionId: subId, completion: { unsubscribed in expect(unsubscribed).to(beTrue()) @@ -165,7 +172,7 @@ class Web3EventsTests: QuickSpec { // We test USDT transfers as they happen basically every block waitUntil(timeout: .seconds(60)) { done in var subId = "" - var cancelled = false + var cancelled = NIOLockedValueBox(false) try! web3Ws.eth.subscribeToLogs( addresses: [EthereumAddress(hex: "0xdAC17F958D2ee523a2206206994597C13D831ec7", eip55: false )], topics: [[EthereumData(ethereumValue: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")]], @@ -176,7 +183,7 @@ class Web3EventsTests: QuickSpec { }, onEvent: { log in guard let topicValue = log.result else { - if cancelled { + if cancelled.withLockedValue({ $0 }) { switch (log.error as? Web3Response.Error) { case .subscriptionCancelled(_): // Expected @@ -193,9 +200,11 @@ class Web3EventsTests: QuickSpec { expect(topicValue.topics.first?.hex()).to(equal("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")) // Tests done. Test unsubscribe. - if !cancelled { - cancelled = true - + if !cancelled.withLockedValue({ + let old = $0 + $0 = true + return old + }) { try! web3Ws.eth.unsubscribe(subscriptionId: subId, completion: { unsubscribed in expect(unsubscribed).to(beTrue()) diff --git a/Tests/Web3Tests/Web3Tests/Web3HttpTests.swift b/Tests/Web3Tests/Web3Tests/Web3HttpTests.swift index 10e4e156..441e5931 100644 --- a/Tests/Web3Tests/Web3Tests/Web3HttpTests.swift +++ b/Tests/Web3Tests/Web3Tests/Web3HttpTests.swift @@ -16,8 +16,8 @@ import PromiseKit class Web3HttpTests: QuickSpec { - let infuraUrl = "https://mainnet.infura.io/v3/362c324f295a4032b2fe87d910aaa33a" - let infuraWsUrl = "wss://mainnet.infura.io/ws/v3/362c324f295a4032b2fe87d910aaa33a" + let infuraUrl = "https://mainnet.infura.io/v3/0058461a5a1e47d3992ac9470168bcc3" + let infuraWsUrl = "wss://mainnet.infura.io/ws/v3/0058461a5a1e47d3992ac9470168bcc3" override func spec() { describe("http rpc requests") { @@ -202,47 +202,7 @@ class Web3HttpTests: QuickSpec { } } - context("eth mining") { - - waitUntil(timeout: .seconds(2)) { done in - web3.eth.mining { response in - it("should be status ok") { - expect(response.status.isSuccess) == true - } - it("should not be nil") { - expect(response.result).toNot(beNil()) - } - it("should be a bool response") { - // Infura won't mine at any time or something's gonna be wrong... - expect(response.result) == false - } - - // Tests done - done() - } - } - } - - context("eth hashrate") { - - waitUntil(timeout: .seconds(2)) { done in - web3.eth.hashrate { response in - it("should be status ok") { - expect(response.status.isSuccess) == true - } - it("should not be nil") { - expect(response.result).toNot(beNil()) - } - it("should be a quantity response") { - // Infura won't mine at any time or something's gonna be wrong... - expect(response.result?.quantity) == 0 - } - - // Tests done - done() - } - } - } + context("eth gas price") { @@ -535,9 +495,9 @@ class Web3HttpTests: QuickSpec { }.then { call in web3.eth.estimateGas(call: call) }.done { quantity in - let expectedQuantity: EthereumQuantity = try .string("0x56d4") + let expectedQuantity: EthereumQuantity = try .string("0x46d4") it("should be the expected quantity") { - expect(quantity) == expectedQuantity + expect(quantity.quantity).to(beGreaterThan(expectedQuantity.quantity)) } done() }.catch { error in