Skip to content

Commit

Permalink
Merge pull request #817 from BoltzExchange/rsk-fixes
Browse files Browse the repository at this point in the history
RSK fixes
  • Loading branch information
michael1011 authored Feb 11, 2025
2 parents 5771b32 + 17bfad0 commit e76e74c
Show file tree
Hide file tree
Showing 13 changed files with 117 additions and 82 deletions.
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

0 comments on commit e76e74c

Please sign in to comment.