Skip to content
This repository has been archived by the owner on Jul 23, 2024. It is now read-only.

Fixed race condition issue through copying a parameter #571

Merged
merged 4 commits into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "caver-js",
"version": "1.6.6",
"version": "1.6.7",
"description": "caver-js is a JavaScript API library that allows developers to interact with a Klaytn node",
"main": "index.js",
"types": "types/index.d.ts",
Expand Down
6 changes: 5 additions & 1 deletion packages/caver-core-subscriptions/src/subscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,14 @@ Subscription.prototype.subscribe = function() {
isFinite(payload.params[1].fromBlock)
) {
// send the subscription request

// copy the params to avoid race-condition with deletion below this block
const blockParams = { ...payload.params[1] }

this.options.requestManager.send(
{
method: 'klay_getLogs',
params: [payload.params[1]],
params: [blockParams],
},
function(err, logs) {
if (!err) {
Expand Down
77 changes: 63 additions & 14 deletions test/subscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const caver = new Caver(websocketURL)
let senderPrvKey
let senderAddress
let receiver
let contractAddress
let contractAbi

// If you are using websocket provider, subscribe the 'newBlockHeaders' event through the subscriptions object after sending the transaction.
// When receiving the 'newBlockHeaders' event, it queries the transaction receipt.
Expand All @@ -42,19 +44,41 @@ let receiver
// -> [request] klay_getTransactionReceipt
// -> [response] receipt

before(() => {
senderPrvKey =
process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
? `0x${process.env.privateKey}`
: process.env.privateKey
async function prepareContractTesting() {
const kip7 = await caver.kct.kip7.deploy(
{
name: 'Jamie',
symbol: 'JME',
decimals: 18,
initialSupply: '1000000000000',
},
senderAddress
)
contractAddress = kip7.options.address
contractAbi = kip7.options.jsonInterface

senderAddress = caver.klay.accounts.wallet.add(senderPrvKey).address
return kip7.transfer(receiver.address, 1000, { from: senderAddress })
}

receiver = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
})
describe('subscription should work well with websocket connection', () => {
before(function(done) {
this.timeout(200000)

senderPrvKey =
process.env.privateKey && String(process.env.privateKey).indexOf('0x') === -1
? `0x${process.env.privateKey}`
: process.env.privateKey

senderAddress = caver.klay.accounts.wallet.add(senderPrvKey).address
caver.wallet.add(caver.wallet.keyring.createFromPrivateKey(senderPrvKey))

describe('get transaction', () => {
it('CAVERJS-UNIT-ETC-094: getTransaction should return information of transaction.', async () => {
receiver = caver.klay.accounts.wallet.add(caver.klay.accounts.create())
caver.wallet.add(caver.wallet.keyring.createFromPrivateKey(receiver.privateKey))

prepareContractTesting().then(() => done())
})

it('CAVERJS-UNIT-ETC-094: sendTransaction should return a transaction receipt.', async () => {
const txObj = {
from: senderAddress,
to: receiver.address,
Expand Down Expand Up @@ -83,17 +107,42 @@ describe('get transaction', () => {
expect(receipt.typeInt).not.to.undefined
expect(receipt.value).not.to.undefined
}).timeout(10000)
})

describe('Subscribe test throught contract event', () => {
it('CAVERJS-UNIT-ETC-262: should emit subscription id when subscription is created', done => {
caver.wallet.add(caver.wallet.keyring.createFromPrivateKey(senderPrvKey)).address
caver.kct.kip17.deploy({ name: 'Jasmine', symbol: 'JAS' }, senderAddress).then(deployed => {
deployed.events.MinterAdded({}).on('connected', subscriptionId => {
expect(subscriptionId).not.to.be.undefined
caver.currentProvider.connection.close()
done()
})
})
}).timeout(30000)

// Regression test for a race-condition where a fresh caver instance
// subscribing to past events would have its call parameters deleted while it
// made initial Websocket handshake and return an incorrect response.
it('CAVERJS-UNIT-ETC-398: should immediately listen for events in the past', async () => {
const freshCaver = new Caver(websocketURL)
const contract = freshCaver.contract.create(contractAbi, contractAddress)

let counter = 0
const latestBlock = await caver.rpc.klay.getBlockNumber()
caver.currentProvider.connection.close()

await new Promise(resolve => {
contract.events
.allEvents({
fromBlock: 0,
})
.on('data', function(event) {
counter++
expect(event.blockNumber < latestBlock).to.be.true

if (counter === 2) {
this.removeAllListeners()
freshCaver.currentProvider.connection.close()
resolve()
}
})
})
}).timeout(30000)
})