Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSK fixes #817

Merged
merged 4 commits into from
Feb 11, 2025
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
4 changes: 2 additions & 2 deletions docker/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Image:

BITCOIN_VERSION = "28.1"
LITECOIN_VERSION = "0.21.4"
ELEMENTS_VERSION = "23.2.5"
ELEMENTS_VERSION = "23.2.6"
GETH_VERSION = "1.14.12"

C_LIGHTNING_VERSION = "24.11.1"
Expand Down Expand Up @@ -108,7 +108,7 @@ class Image:
],
),
"regtest": Image(
tag="4.6.4",
tag="4.6.5",
arguments=[
UBUNTU_VERSION,
BITCOIN_BUILD_ARG,
Expand Down
2 changes: 1 addition & 1 deletion docker/regtest/startRegtest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ docker run \
-p 9735:9735 \
-p 9293:9293 \
-p 9292:9292 \
boltz/regtest:4.6.4
boltz/regtest:4.6.5

docker exec regtest bash -c "cp /root/.lightning/regtest/*.pem /root/.lightning/regtest/certs"
docker exec regtest chmod -R 777 /root/.lightning/regtest/certs
Expand Down
2 changes: 0 additions & 2 deletions lib/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ type EthereumConfig = RskConfig & {
type ApiConfig = {
host: string;
port: number;
cors?: string | string[];
};

type GrpcConfig = {
Expand Down Expand Up @@ -269,7 +268,6 @@ class Config {
api: {
host: '127.0.0.1',
port: 9001,
cors: '*',
},

grpc: {
Expand Down
12 changes: 0 additions & 12 deletions lib/api/Api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import cors from 'cors';
import express, { Application, NextFunction, Request, Response } from 'express';
import { ApiConfig } from '../Config';
import Logger from '../Logger';
Expand All @@ -22,17 +21,6 @@ class Api {
this.app = express();
this.app.set('trust proxy', 'loopback');

if (config.cors === undefined || config.cors.length !== 0) {
this.app.use(
cors({
origin: config.cors || '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
preflightContinue: false,
optionsSuccessStatus: 204,
}),
);
}

this.app.use(
express.json({
verify(req, _, buf: Buffer, encoding: string) {
Expand Down
12 changes: 12 additions & 0 deletions lib/db/repositories/PendingEthereumTransactionRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ class PendingEthereumTransactionRepository {
return PendingEthereumTransaction.findAll();
};

public static getHighestNonce = async (): Promise<number | undefined> => {
const nonce = await PendingEthereumTransaction.max<
number,
PendingEthereumTransaction
>('nonce');
if (nonce === null || nonce === undefined) {
return undefined;
}

return nonce + 1;
};

public static addTransaction = (
hash: string,
nonce: number,
Expand Down
16 changes: 14 additions & 2 deletions lib/wallet/ethereum/InjectedProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,23 @@ class InjectedProvider implements Provider {
return this.forwardMethodNullable('getTransaction', transactionHash);
};

public getTransactionCount = (
public getTransactionCount = async (
addressOrName: string,
blockTag?: BlockTag,
): Promise<number> => {
return this.forwardMethod('getTransactionCount', addressOrName, blockTag);
{
const highestNonce =
await PendingEthereumTransactionRepository.getHighestNonce();
if (highestNonce !== undefined) {
return highestNonce;
}
}

return await this.forwardMethod(
'getTransactionCount',
addressOrName,
blockTag,
);
};

public getTransactionReceipt = (
Expand Down
63 changes: 17 additions & 46 deletions lib/wallet/ethereum/contracts/ContractEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ type Events = {
};

class ContractEventHandler extends TypedEventEmitter<Events> {
// Check for missed claims every 10 minutes
private static readonly claimCheckInterval = 1_000 * 60 * 10;
// Check for missed events every 5 minutes
private static readonly missedEventsCheckInterval = 1_000 * 60 * 5;

private version!: bigint;

Expand All @@ -63,8 +63,8 @@ class ContractEventHandler extends TypedEventEmitter<Events> {

private networkDetails!: NetworkDetails;

private lastClaimCheck = 0;
private lastClaimCheckInterval: NodeJS.Timeout | undefined;
private rescanLastHeight = 0;
private rescanInterval: NodeJS.Timeout | undefined;

constructor(private readonly logger: Logger) {
super();
Expand All @@ -83,27 +83,27 @@ class ContractEventHandler extends TypedEventEmitter<Events> {
this.networkDetails = networkDetails;

this.logger.verbose(
`Starting ${this.networkDetails.name} contract event subscriptions`,
`Starting ${this.networkDetails.name} contracts v${version} event subscriptions`,
);

await this.subscribeContractEvents();

this.lastClaimCheck = await provider.getBlockNumber();
this.lastClaimCheckInterval = setInterval(async () => {
this.rescanLastHeight = await provider.getBlockNumber();
this.rescanInterval = setInterval(async () => {
try {
await this.checkMissedClaims(provider);
await this.checkMissedEvents(provider);
} catch (error) {
this.logger.error(
`Error checking missed claims ${this.networkDetails.name}: ${formatError(error)}`,
`Error checking for missed events of ${this.networkDetails.name} contracts v${version}: ${formatError(error)}`,
);
}
}, ContractEventHandler.claimCheckInterval);
}, ContractEventHandler.missedEventsCheckInterval);
};

public destroy = () => {
if (this.lastClaimCheckInterval) {
clearInterval(this.lastClaimCheckInterval);
this.lastClaimCheckInterval = undefined;
if (this.rescanInterval) {
clearInterval(this.rescanInterval);
this.rescanInterval = undefined;
}
};

Expand Down Expand Up @@ -269,42 +269,13 @@ class ContractEventHandler extends TypedEventEmitter<Events> {
);
};

private checkMissedClaims = async (provider: Provider) => {
private checkMissedEvents = async (provider: Provider) => {
this.logger.debug(
`Checking for missed claims ${this.networkDetails.name} from block ${this.lastClaimCheck}`,
`Checking for missed events of ${this.networkDetails.name} contracts v${this.version} from block ${this.rescanLastHeight}`,
);

const currentHeight = await provider.getBlockNumber();
const [etherClaims, erc20Claims] = await Promise.all([
this.etherSwap.queryFilter(
this.etherSwap.filters.Claim(),
this.lastClaimCheck,
),
this.erc20Swap.queryFilter(
this.erc20Swap.filters.Claim(),
this.lastClaimCheck,
),
]);

this.lastClaimCheck = currentHeight;

for (const claim of etherClaims) {
this.emit('eth.claim', {
version: this.version,
transactionHash: claim.transactionHash,
preimageHash: parseBuffer(claim.topics[1]),
preimage: parseBuffer(claim.args!.preimage),
});
}

for (const claim of erc20Claims) {
this.emit('erc20.claim', {
version: this.version,
transactionHash: claim.transactionHash,
preimageHash: parseBuffer(claim.topics[1]),
preimage: parseBuffer(claim.args!.preimage),
});
}
await this.rescan(this.rescanLastHeight);
this.rescanLastHeight = currentHeight;
};
}

Expand Down
13 changes: 1 addition & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@
"bolt11": "^1.4.1",
"boltz-core": "^2.2.1",
"colors": "^1.4.0",
"cors": "^2.8.5",
"ecpair": "^2.1.0",
"ethers": "^6.13.5",
"express": "^4.21.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Logger from '../../../../lib/Logger';
import Database from '../../../../lib/db/Database';
import PendingEthereumTransaction from '../../../../lib/db/models/PendingEthereumTransaction';
import PendingEthereumTransactionRepository from '../../../../lib/db/repositories/PendingEthereumTransactionRepository';

describe('PendingEthereumTransactionRepository', () => {
let database: Database;

beforeAll(async () => {
database = new Database(Logger.disabledLogger, Database.memoryDatabase);
await database.init();
});

beforeEach(async () => {
await PendingEthereumTransaction.truncate();
});

afterAll(async () => {
await database.close();
});

describe('getHighestNonce', () => {
test('should get highest nonce when there are no pending transactions', async () => {
await expect(
PendingEthereumTransactionRepository.getHighestNonce(),
).resolves.toEqual(undefined);
});

test('should get highest nonce when there are pending transactions', async () => {
await PendingEthereumTransactionRepository.addTransaction('txHash', 20);

await expect(
PendingEthereumTransactionRepository.getHighestNonce(),
).resolves.toEqual(21);
});
});
});
1 change: 1 addition & 0 deletions test/integration/wallet/ethereum/EthereumManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jest.mock(
() => ({
getTransactions: jest.fn().mockResolvedValue([]),
addTransaction: jest.fn().mockResolvedValue(null),
getHighestNonce: jest.fn().mockResolvedValue(undefined),
}),
);
jest.mock('../../../../lib/db/repositories/ChainTipRepository');
Expand Down
28 changes: 28 additions & 0 deletions test/integration/wallet/ethereum/InjectedProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jest.mock(
'../../../../lib/db/repositories/PendingEthereumTransactionRepository',
() => ({
addTransaction: jest.fn().mockResolvedValue(null),
getHighestNonce: jest.fn().mockResolvedValue(undefined),
}),
);

Expand Down Expand Up @@ -54,6 +55,33 @@ describe('InjectedProvider', () => {
).resolves.toEqual(null);
});

describe('getTransactionCount', () => {
const address = '0x0000000000000000000000000000000000000000';

afterAll(() => {
PendingEthereumTransactionRepository.getHighestNonce = jest
.fn()
.mockResolvedValue(undefined);
});

test('should get transaction count from provider when there are no pending transactions', async () => {
PendingEthereumTransactionRepository.getHighestNonce = jest
.fn()
.mockResolvedValue(undefined);
await expect(provider.getTransactionCount(address)).resolves.toEqual(0);
});

test('should get transaction count from db when there are pending transactions', async () => {
const highestNonce = 10;
PendingEthereumTransactionRepository.getHighestNonce = jest
.fn()
.mockResolvedValue(highestNonce);
await expect(provider.getTransactionCount(address)).resolves.toEqual(
highestNonce,
);
});
});

test('should save broadcast transactions to database', async () => {
const setup = await getSigner();
await fundSignerWallet(setup.signer, setup.etherBase);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,8 @@ describe('ContractEventHandler', () => {
await Promise.all([lockupPromise, claimPromise, refundPromise]);
});

test('should check missed claims', async () => {
contractEventHandler['lastClaimCheck'] =
test('should check for missed events', async () => {
contractEventHandler['rescanLastHeight'] =
await setup.provider.getBlockNumber();

const preimage = randomBytes(32);
Expand Down Expand Up @@ -408,10 +408,10 @@ describe('ContractEventHandler', () => {
});
});

await contractEventHandler['checkMissedClaims'](setup.provider);
await contractEventHandler['checkMissedEvents'](setup.provider);
await claimPromise;

expect(contractEventHandler['lastClaimCheck']).toEqual(
expect(contractEventHandler['rescanLastHeight']).toEqual(
await setup.provider.getBlockNumber(),
);
});
Expand Down
Loading