Shred Delivery and Sender are now live! Get earliest access to raw Solana data and optimized transaction sending. Learn about Shred Delivery | Learn about Sender
Shred Delivery and Sender are now live! Get earliest access to raw Solana data and optimized transaction sending. Learn about Shred Delivery | Learn about Sender
探索 Solana DAS API 的高效分页机制。页面分页、游标分页和键集分页用于大数据集的性能优化。
id
: 按资产 ID 的二进制排序(默认)。created
: 按资产创建日期排序。recent_action
: 按资产最后更新日期排序(不推荐)。none
: 不对数据进行排序(不推荐)。示例
const url = `https://mainnet.helius-rpc.com/?api-key=<api_key>`
const example = async () => {
let page = 1;
let items = [];
while (true) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'searchAssets',
params: {
grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
page: page,
limit: 1000,
sortBy: { sortBy: 'id', sortDirection: 'asc' },
},
}),
});
const { result } = await response.json();
if (result.items.length == 0) {
console.log('No items remaining');
break;
} else {
console.log(`Processing results from page ${page}`);
items.push(...result.items);
page += 1;
}
}
console.log(`Got ${items.length} total items`);
};
example();
id
排序时支持。示例
const url = `https://mainnet.helius-rpc.com/?api-key=<api_key>`
const example = async () => {
let items = [];
let cursor;
while (true) {
let params = {
grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
limit: 1000,
sortBy: { sortBy: 'id', sortDirection: 'asc' },
} as any;
if (cursor != undefined) {
params.cursor = cursor;
}
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'searchAssets',
params: params,
}),
});
const { result } = await response.json();
if (result.items.length == 0) {
console.log('No items remaining');
break;
} else {
console.log(`Processing results for cursor ${cursor}`);
cursor = result.cursor;
items.push(...result.items);
}
}
console.log(`Got ${items.length} total items`);
};
example();
before
和/或after
。查询本质上与“获取所有在X之后但在Y之前的资产”相同。您可以通过更新每次调用的before或after参数来遍历数据集。
示例
const url = `https://mainnet.helius-rpc.com/?api-key=<api_key>`
const example = async () => {
// Two NFTs from the Tensorian collection.
// The "start" item has a lower asset ID (in binary) than the "end" item.
// We will traverse in ascending order.
let start = '6CeKtAYX5USSvPCQicwFsvN4jQSHNxQuFrX2bimWrNey';
let end = 'CzTP4fUbdfgKzwE6T94hsYV7NWf1SzuCCsmJ6RP1xsDw';
let sortDirection = 'asc';
let after = start;
let before = end;
let items = [];
while (true) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'searchAssets',
params: {
grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
limit: 1000,
after: after,
before: before,
sortBy: { sortBy: 'id', sortDirection: sortDirection },
},
}),
});
const { result } = await response.json();
if (result.items.length == 0) {
console.log('No items remaining');
break;
} else {
console.log(`Processing results with (after: ${after}, before: ${before})`);
after = result.items[result.items.length - 1].id;
items.push(...result.items);
}
}
console.log(`Got ${items.length} total items`);
};
example();
示例
import base58 from 'bs58';
const url = `https://mainnet.helius-rpc.com/?api-key=<api_key>`
const main = async () => {
let numParitions = 8;
let partitons = partitionAddressRange(numParitions);
let promises = [];
for (const [i, partition] of partitons.entries()) {
let [s, e] = partition;
let start = bs58.encode(s);
let end = bs58.encode(e);
console.log(`Parition: ${i}, Start: ${start}, End: ${end}`);
let promise: Promise<number> = new Promise(async (resolve, reject) => {
let current = start;
let totalForPartition = 0;
while (true) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'searchAssets',
params: {
grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
limit: 1000,
after: current,
before: end,
sortBy: { sortBy: 'id', sortDirection: 'asc' },
},
}),
});
const { result } = await response.json();
totalForPartition += result.items.length;
console.log(`Found ${totalForPartition} total items in parition ${i}`);
if (result.items.length == 0) {
break;
} else {
current = result.items[result.items.length - 1].id;
}
}
resolve(totalForPartition);
});
promises.push(promise);
}
let results = await Promise.all(promises);
let total = results.reduce((a, b) => a + b, 0);
console.log(`Got ${total} total items`);
};
// Function to convert a BigInt to a byte array
function bigIntToByteArray(bigInt: bigint): Uint8Array {
const bytes = [];
let remainder = bigInt;
while (remainder > 0n) {
// use 0n for bigint literal
bytes.unshift(Number(remainder & 0xffn));
remainder >>= 8n;
}
while (bytes.length < 32) bytes.unshift(0); // pad with zeros to get 32 bytes
return new Uint8Array(bytes);
}
function partitionAddressRange(numPartitions: number) {
let N = BigInt(numPartitions);
// Largest and smallest Solana addresses in integer form.
// Solana addresses are 32 byte arrays.
const start = 0n;
const end = 2n ** 256n - 1n;
// Calculate the number of partitions and partition size
const range = end - start;
const partitionSize = range / N;
// Calculate partition ranges
const partitions: Uint8Array[][] = [];
for (let i = 0n; i < N; i++) {
const s = start + i * partitionSize;
const e = i === N - 1n ? end : s + partitionSize;
partitions.push([bigIntToByteArray(s), bigIntToByteArray(e)]);
}
return partitions;
}
main();