Skip to content
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
5 changes: 5 additions & 0 deletions src/config/btc.sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ REQUEST_TIMEOUT = 30000 # Request timeout in milliseconds
MAX_REQUESTS_PER_SECOND = 50 # Rate limit: max requests per second per client
MAX_SUBSCRIPTIONS = 10 # Maximum subscriptions per client (blocks, epochs)

[API.MEMPOOL]
MAX_ADDRESSES = 20 # Maximum number of addresses per query
DEFAULT_LIMIT = 25 # Default number of transactions returned
MAX_LIMIT = 100 # Maximum number of transactions a client can request

[DATABASE]
HOST = "127.0.0.1" # Database host
PORT = 25485
Expand Down
115 changes: 115 additions & 0 deletions src/protocols/OPNetAPIProtocol.proto
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,7 @@ message SubmitEpochResponse {
enum SubscriptionTypeEnum {
BLOCKS = 0;
EPOCHS = 1;
MEMPOOL = 2;
}

message SubscribeBlocksRequest {
Expand Down Expand Up @@ -645,3 +646,117 @@ message NewEpochNotification {
string epochNumber = 2;
string epochHash = 3;
}

// ============================================================================
// Mempool Methods
// ============================================================================

// Request: retrieve aggregate mempool statistics (no parameters required).
message GetMempoolInfoRequest {
uint32 requestId = 1;
}

// Response: aggregate mempool statistics.
message GetMempoolInfoResponse {
// Total number of pending transactions in the mempool.
uint32 count = 1;
// Number of pending OPNet-specific transactions.
uint32 opnetCount = 2;
// Total byte size of the mempool.
uint64 size = 3;
}

// Request: fetch a single pending mempool transaction by hash.
message GetPendingTransactionRequest {
uint32 requestId = 1;
// The 64-character hex transaction hash.
string hash = 2;
}

// A single transaction output as exposed by the mempool API.
message MempoolTransactionOutput {
// Destination address, or empty for unspendable outputs.
string address = 1;
// The vout index within the transaction.
uint32 outputIndex = 2;
// Output value in satoshis (decimal string).
string value = 3;
// Hex-encoded scriptPubKey.
string scriptPubKey = 4;
}

// A single transaction input as exposed by the mempool API.
message MempoolTransactionInput {
// The txid of the referenced output.
string transactionId = 1;
// The vout index of the referenced output.
uint32 outputIndex = 2;
}

// Full representation of a pending mempool transaction.
message PendingTransactionResponse {
// Internal transaction identifier (txid).
string id = 1;
// ISO-8601 timestamp of when the transaction was first seen.
string firstSeen = 2;
// Block height at which the transaction was observed (0x-prefixed hex).
string blockHeight = 3;
// Theoretical gas limit for OPNet execution (0x-prefixed hex).
string theoreticalGasLimit = 4;
// Priority fee attached to the transaction (0x-prefixed hex).
string priorityFee = 5;
// Whether this transaction targets an OPNet contract.
bool isOPNet = 6;
// Whether the transaction was submitted as a PSBT.
bool psbt = 7;
// The transaction inputs.
repeated MempoolTransactionInput inputs = 8;
// The transaction outputs.
repeated MempoolTransactionOutput outputs = 9;
// The full raw transaction as a hex string.
string raw = 10;
}

// Request: fetch the latest pending transactions with optional address filter.
message GetLatestPendingTransactionsRequest {
uint32 requestId = 1;
// A single address to auto-resolve into all derived wallet address types.
string address = 2;
// Explicit list of addresses to filter by.
repeated string addresses = 3;
// Maximum number of transactions to return.
uint32 limit = 4;
}

// Response: list of latest pending mempool transactions.
message LatestPendingTransactionsResponse {
// The matching pending transactions.
repeated PendingTransactionResponse transactions = 1;
}

// Mempool Subscription

// Request: subscribe to new mempool transaction notifications.
message SubscribeMempoolRequest {
uint32 requestId = 1;
}

// Response: mempool subscription confirmation.
message SubscribeMempoolResponse {
// Server-assigned subscription identifier.
uint32 subscriptionId = 1;
// The subscription type (MEMPOOL).
SubscriptionTypeEnum type = 2;
}

// Server push: a new transaction entered the mempool.
message NewMempoolTransactionNotification {
// The subscription identifier this notification belongs to.
uint32 subscriptionId = 1;
// The txid of the new mempool transaction.
string txId = 2;
// Whether this transaction targets an OPNet contract.
bool isOPNet = 3;
// Unix timestamp in milliseconds when the transaction was observed.
uint64 timestamp = 4;
}
5 changes: 5 additions & 0 deletions src/src/api/enums/Routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export enum Routes {
SUBMIT_EPOCH = 'epoch/submit',
EPOCH_TEMPLATE = 'epoch/template',

/** Mempool */
MEMPOOL_INFO = 'mempool/info',
MEMPOOL_TRANSACTION = 'mempool/transaction',
MEMPOOL_TRANSACTIONS = 'mempool/transactions',

/** Other */
PROTOBUF_SCHEMA = 'protobuf/schema',
PROTOBUF_API_SCHEMA = 'protobuf/api-schema',
Expand Down
5 changes: 5 additions & 0 deletions src/src/api/json-rpc/routes/JSONRpcRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ export const JSONRpcRouteMethods: JSONRpcRoute = {
[JSONRpcMethods.GET_EPOCH_BY_HASH]: Routes.EPOCH_BY_HASH,
[JSONRpcMethods.GET_EPOCH_TEMPLATE]: Routes.EPOCH_TEMPLATE,
[JSONRpcMethods.SUBMIT_EPOCH]: Routes.SUBMIT_EPOCH,

/** Mempool */
[JSONRpcMethods.GET_MEMPOOL_INFO]: Routes.MEMPOOL_INFO,
[JSONRpcMethods.GET_PENDING_TRANSACTION]: Routes.MEMPOOL_TRANSACTION,
[JSONRpcMethods.GET_LATEST_PENDING_TRANSACTIONS]: Routes.MEMPOOL_TRANSACTIONS,
};
9 changes: 9 additions & 0 deletions src/src/api/json-rpc/types/enums/JSONRpcMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ export enum JSONRpcMethods {
GET_EPOCH_TEMPLATE = 'btc_getEpochTemplate',
SUBMIT_EPOCH = 'btc_submitEpoch',

/** Mempool */

/** Retrieve aggregate mempool statistics (count, OPNet count, byte size). */
GET_MEMPOOL_INFO = 'btc_getMempoolInfo',
/** Fetch a single pending mempool transaction by its hash. */
GET_PENDING_TRANSACTION = 'btc_getPendingTransaction',
/** Fetch the latest pending mempool transactions, optionally filtered by address(es). */
GET_LATEST_PENDING_TRANSACTIONS = 'btc_getLatestPendingTransactions',

/** Simulation */
CALL = 'btc_call',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { JSONRpcMethods } from '../../../enums/JSONRpcMethods.js';
import { JSONRpcParams } from '../../JSONRpcParams.js';

/** Object-form parameters for {@link JSONRpcMethods.GET_LATEST_PENDING_TRANSACTIONS}. */
export interface GetLatestPendingTransactionsParamsAsObject
extends JSONRpcParams<JSONRpcMethods.GET_LATEST_PENDING_TRANSACTIONS> {
/** A single address to auto-resolve into all derived wallet address types. */
readonly address?: string;
/** Explicit list of addresses to filter mempool transactions by. */
readonly addresses?: string[];
/** Maximum number of transactions to return. Clamped to `Config.API.MEMPOOL.MAX_LIMIT`. */
readonly limit?: number;
}

/** Array-form parameters: `[address?, addresses?, limit?]`. */
export type GetLatestPendingTransactionsParamsAsArray = [string?, string[]?, number?];

/** Accepted parameter shapes for `btc_getLatestPendingTransactions`. */
export type GetLatestPendingTransactionsParams =
| GetLatestPendingTransactionsParamsAsObject
| GetLatestPendingTransactionsParamsAsArray;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { JSONRpcMethods } from '../../../enums/JSONRpcMethods.js';
import { JSONRpcParams } from '../../JSONRpcParams.js';

/** Object-form parameters for {@link JSONRpcMethods.GET_MEMPOOL_INFO} (none required). */
export interface GetMempoolInfoParamsAsObject
extends JSONRpcParams<JSONRpcMethods.GET_MEMPOOL_INFO> {}

/** Array-form parameters (empty). */
export type GetMempoolInfoParamsAsArray = [];

/** Accepted parameter shapes for `btc_getMempoolInfo`. */
export type GetMempoolInfoParams = GetMempoolInfoParamsAsObject | GetMempoolInfoParamsAsArray;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { JSONRpcMethods } from '../../../enums/JSONRpcMethods.js';
import { JSONRpcParams } from '../../JSONRpcParams.js';

/** Object-form parameters for {@link JSONRpcMethods.GET_PENDING_TRANSACTION}. */
export interface GetPendingTransactionParamsAsObject
extends JSONRpcParams<JSONRpcMethods.GET_PENDING_TRANSACTION> {
/** The 64-character hex transaction hash. */
readonly hash: string;
}

/** Array-form parameters: `[hash]`. */
export type GetPendingTransactionParamsAsArray = [string];

/** Accepted parameter shapes for `btc_getPendingTransaction`. */
export type GetPendingTransactionParams =
| GetPendingTransactionParamsAsObject
| GetPendingTransactionParamsAsArray;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { JSONRpcMethods } from '../../../enums/JSONRpcMethods.js';
import { JSONRpc2ResultData } from '../../JSONRpc2ResultData.js';
import { MempoolTransactionData } from './MempoolTransactionData.js';

/** Payload shape for the `btc_getLatestPendingTransactions` result. */
export interface GetLatestPendingTransactionsResultData {
/** The list of pending mempool transactions matching the query. */
readonly transactions: MempoolTransactionData[];
}

/** Result type for the `btc_getLatestPendingTransactions` JSON-RPC method. */
export type GetLatestPendingTransactionsResult =
JSONRpc2ResultData<JSONRpcMethods.GET_LATEST_PENDING_TRANSACTIONS> &
GetLatestPendingTransactionsResultData;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { JSONRpcMethods } from '../../../enums/JSONRpcMethods.js';
import { JSONRpc2ResultData } from '../../JSONRpc2ResultData.js';

/** Core mempool statistics returned by `btc_getMempoolInfo`. */
export interface MempoolInfoData {
/** Total number of pending transactions in the mempool. */
readonly count: number;
/** Number of pending OPNet-specific transactions in the mempool. */
readonly opnetCount: number;
/** Total byte size of the mempool. */
readonly size: number;
}

/** Result type for the `btc_getMempoolInfo` JSON-RPC method. */
export type GetMempoolInfoResult = JSONRpc2ResultData<JSONRpcMethods.GET_MEMPOOL_INFO> &
MempoolInfoData;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { JSONRpcMethods } from '../../../enums/JSONRpcMethods.js';
import { JSONRpc2ResultData } from '../../JSONRpc2ResultData.js';
import { MempoolTransactionData } from './MempoolTransactionData.js';

/** Result type for the `btc_getPendingTransaction` JSON-RPC method. */
export type GetPendingTransactionResult =
JSONRpc2ResultData<JSONRpcMethods.GET_PENDING_TRANSACTION> & MempoolTransactionData;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/** A single transaction input as exposed by the mempool API. */
export interface MempoolTransactionInput {
/** The txid of the referenced output. */
readonly transactionId: string;
/** The vout index of the referenced output. */
readonly outputIndex: number;
}

/** A single transaction output as exposed by the mempool API. */
export interface MempoolTransactionOutput {
/** The destination address, or `null` for unspendable outputs. */
readonly address: string | null;
/** The vout index within the transaction. */
readonly outputIndex: number;
/** The output value in satoshis (decimal string). */
readonly value: string;
/** The hex-encoded scriptPubKey. */
readonly scriptPubKey: string;
}

/** Full representation of a pending mempool transaction returned by the API. */
export interface MempoolTransactionData {
/** Internal transaction identifier (txid). */
readonly id: string;
/** ISO-8601 timestamp of when the transaction was first seen. */
readonly firstSeen: string;
/** Block height at which the transaction was observed (`0x`-prefixed hex). */
readonly blockHeight: string;
/** Theoretical gas limit for OPNet execution (`0x`-prefixed hex). */
readonly theoreticalGasLimit: string;
/** Priority fee attached to the transaction (`0x`-prefixed hex). */
readonly priorityFee: string;
/** Whether this transaction targets an OPNet contract. */
readonly isOPNet: boolean;
/** Whether the transaction was submitted as a PSBT. */
readonly psbt: boolean;
/** The transaction inputs. */
readonly inputs: MempoolTransactionInput[];
/** The transaction outputs. */
readonly outputs: MempoolTransactionOutput[];
/** The full raw transaction as a hex string. */
readonly raw: string;
}
8 changes: 8 additions & 0 deletions src/src/api/routes/DefinedRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import { EpochByHash } from './api/v1/epochs/EpochByHash.js';
import { SubmitEpochRoute } from './api/v1/epochs/SubmitEpochRoute.js';
import { GetEpochTemplateRoute } from './api/v1/epochs/GetEpochTemplateRoute.js';
import { BlockByChecksum } from './api/v1/block/BlockByChecksum.js';
import { GetMempoolInfo } from './api/v1/mempool/GetMempoolInfo.js';
import { GetPendingTransaction } from './api/v1/mempool/GetPendingTransaction.js';
import { GetLatestPendingTransactions } from './api/v1/mempool/GetLatestPendingTransactions.js';

export const DefinedRoutes: {
[key in Routes]: Route<key, JSONRpcMethods, object | string | undefined>;
Expand Down Expand Up @@ -67,6 +70,11 @@ export const DefinedRoutes: {
[Routes.BROADCAST_TRANSACTION]: new BroadcastTransaction(),
[Routes.TRANSACTION_PREIMAGE]: new GetPreimage(),

/** Mempool */
[Routes.MEMPOOL_INFO]: new GetMempoolInfo(),
[Routes.MEMPOOL_TRANSACTION]: new GetPendingTransaction(),
[Routes.MEMPOOL_TRANSACTIONS]: new GetLatestPendingTransactions(),

/** Others */
[Routes.PROTOBUF_SCHEMA]: new ProtobufSchema(),
[Routes.PROTOBUF_API_SCHEMA]: new ProtobufAPISchema(),
Expand Down
Loading