MaksutEdistyneet maksut

Lykätty suoritus

Jokainen Solana-transaktio sisältää viimeaikaisen lohkohashin – viittauksen viimeaikaiseen verkon tilaan, joka todistaa transaktion luodun "nyt". Verkko hylkää kaikki transaktiot, joiden lohkohash on vanhempi kuin ~150 lohkoa (~60–90 sekuntia), estäen uudelleentoistohyökkäykset ja vanhentuneet lähetykset. Tämä toimii täydellisesti reaaliaikaisissa maksuissa. Mutta se rikkoo työnkulut, jotka tarvitsevat väliä allekirjoituksen ja lähetyksen välillä, kuten:

SkenaarioMiksi tavalliset transaktiot epäonnistuvat
Treasury-toiminnotTalousjohtaja Tokiossa allekirjoittaa, controller New Yorkissa hyväksyy – 90 sekuntia ei riitä
Compliance-työnkulutTransaktiot vaativat juridisen/compliance-tarkastuksen ennen suoritusta
Cold storage -allekirjoitusIlmaväliset koneet vaativat allekirjoitettujen transaktioiden manuaalisen siirron
Eräkäsittelyn valmisteluValmistele palkanlaskenta tai maksut työaikana, suorita yöllä
Multi-sig-koordinointiUseita hyväksyjiä eri aikavyöhykkeillä
Ajoitetut maksutAjoita maksut suoritettavaksi tulevana päivänä

Perinteisessä rahoituksessa allekirjoitettu shekki ei vanhene 90 sekunnissa. Tiettyjen lohkoketjuoperaatioiden ei pitäisi sekään. Kestävät noncet ratkaisevat tämän korvaamalla viimeaikaisen lohkohashin tallennetulla, pysyvällä arvolla, joka etenee vain kun käytät sitä – antaen sinulle transaktioita, jotka pysyvät voimassa kunnes olet valmis lähettämään ne.

Miten se toimii

Viimeaikaisen lohkohajautuksen sijaan (voimassa ~150 lohkoa) käytät nonce-tiliä, erityistä tiliä, joka tallentaa ainutlaatuisen arvon, jota voidaan käyttää lohkohajautuksen sijasta. Jokaisen tätä noncea käyttävän transaktion on "edistettävä" sitä ensimmäisenä käskynä. Jokaista nonce-arvoa voidaan käyttää vain yhdelle transaktiolle.

Durable Nonce
Standard Blockhash

Nonce-tili maksaa ~0.0015 SOL vuokravapautusta varten. Yksi nonce-tili = yksi odottava transaktio kerrallaan. Rinnakkaisiin työnkulkuihin luo useita nonce-tilejä.

Nonce-tilin luominen

Nonce-tilin luominen vaatii kaksi käskyä yhdessä transaktiossa:

  1. Luo tili käyttäen getCreateAccountInstruction System Programista
  2. Alusta se nonceksi käyttäen getInitializeNonceAccountInstruction

Luo avainpari

Luo uusi avainpari käytettäväksi nonce-tilin osoitteena ja laske vaadittu tila ja vuokra.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();

Luo tilin käsky

Luo tili, jonka omistaa System Program, riittävällä määrällä lamporteja vuokravapautusta varten.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();
const createNonceAccountIx = getCreateAccountInstruction({
payer: sender,
newAccount: nonceKeypair,
lamports: nonceRent,
space: nonceSpace,
programAddress: SYSTEM_PROGRAM_ADDRESS
});

Alusta nonce-käsky

Alusta tili nonce-tiliksi asettaen valtuutus, joka voi edistää sitä.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();
const createNonceAccountIx = getCreateAccountInstruction({
payer: sender,
newAccount: nonceKeypair,
lamports: nonceRent,
space: nonceSpace,
programAddress: SYSTEM_PROGRAM_ADDRESS
});
const initNonceIx = getInitializeNonceAccountInstruction({
nonceAccount: nonceKeypair.address,
nonceAuthority: sender.address
});

Rakenna transaktio

Rakenna transaktio molemmilla käskyillä.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();
const createNonceAccountIx = getCreateAccountInstruction({
payer: sender,
newAccount: nonceKeypair,
lamports: nonceRent,
space: nonceSpace,
programAddress: SYSTEM_PROGRAM_ADDRESS
});
const initNonceIx = getInitializeNonceAccountInstruction({
nonceAccount: nonceKeypair.address,
nonceAuthority: sender.address
});
const { value: blockhash } = await rpc.getLatestBlockhash().send();
const createNonceTx = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
(tx) =>
appendTransactionMessageInstructions(
[createNonceAccountIx, initNonceIx],
tx
)
);

Allekirjoita ja lähetä

Allekirjoita ja lähetä transaktio nonce-tilin luomiseksi ja alustamiseksi.

Luo avainpari

Luo uusi avainpari käytettäväksi nonce-tilin osoitteena ja laske vaadittu tila ja vuokra.

Luo tilin käsky

Luo tili, jonka omistaa System Program, riittävällä määrällä lamporteja vuokravapautusta varten.

Alusta nonce-käsky

Alusta tili nonce-tiliksi asettaen valtuutus, joka voi edistää sitä.

Rakenna transaktio

Rakenna transaktio molemmilla käskyillä.

Allekirjoita ja lähetä

Allekirjoita ja lähetä transaktio nonce-tilin luomiseksi ja alustamiseksi.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();

Lykätyn transaktion rakentaminen

Viimeaikaisen lohkohashin sijaan käytä nonce-tilin blockhash-arvoa transaktion elinaikana.

Hae nonce

Hae data nonce-tililtä. Käytä nonce-tilin blockhash-arvoa transaktion elinaikana.

Example Nonce Account Data
{
version: 1,
state: 1,
authority: 'HgjaL8artMtmntaQDVM2UBk3gppsYYERS4PkUhiaLZD1',
blockhash: '5U7seXqfgZx1uh5DFhdH1vyBhr7XGRrKxBAnJJTbbUa',
lamportsPerSignature: 5000n
}

Luo siirtokäsky

Luo käsky maksuasi varten. Tämä esimerkki näyttää token-siirron.

Rakenna transaktio kestävällä noncella

Käytä setTransactionMessageLifetimeUsingDurableNonce-metodia, joka asettaa noncen lohkohashiksi ja lisää automaattisesti nonce-edistyskäskyn alkuun.

Allekirjoita transaktio

Allekirjoita transaktio. Se käyttää nyt kestävää noncea tavallisen lohkohashin sijaan.

Hae nonce

Hae data nonce-tililtä. Käytä nonce-tilin blockhash-arvoa transaktion elinaikana.

Example Nonce Account Data
{
version: 1,
state: 1,
authority: 'HgjaL8artMtmntaQDVM2UBk3gppsYYERS4PkUhiaLZD1',
blockhash: '5U7seXqfgZx1uh5DFhdH1vyBhr7XGRrKxBAnJJTbbUa',
lamportsPerSignature: 5000n
}

Luo siirtokäsky

Luo käsky maksuasi varten. Tämä esimerkki näyttää token-siirron.

Rakenna transaktio kestävällä noncella

Käytä setTransactionMessageLifetimeUsingDurableNonce-metodia, joka asettaa noncen lohkohashiksi ja lisää automaattisesti nonce-edistyskäskyn alkuun.

Allekirjoita transaktio

Allekirjoita transaktio. Se käyttää nyt kestävää noncea tavallisen lohkohashin sijaan.

Build Deferred Transaction
const { data: nonceData } = await fetchNonce(rpc, nonceKeypair.address);

Tallenna tai lähetä transaktio

Allekirjoituksen jälkeen koodaa transaktio tallennusta varten. Kun olet valmis, lähetä se verkkoon.

Koodaa tallennusta varten

Koodaa allekirjoitettu transaktio base64-muotoon. Tallenna tämä arvo tietokantaasi.

Lähetä transaktio

Lähetä allekirjoitettu transaktio, kun olet valmis. Transaktio pysyy voimassa, kunnes nonce edistetään.

Koodaa tallennusta varten

Koodaa allekirjoitettu transaktio base64-muotoon. Tallenna tämä arvo tietokantaasi.

Lähetä transaktio

Lähetä allekirjoitettu transaktio, kun olet valmis. Transaktio pysyy voimassa, kunnes nonce edistetään.

Store and Execute
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
const base64EncodedTransaction =
getBase64EncodedWireTransaction(signedTransaction);
// Store base64EncodedTransaction in your database

Demo

Demo
// Generate keypairs for sender and recipient
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
console.log("Sender Address:", sender.address);
console.log("Recipient Address:", recipient.address);
// Demo Setup: Create RPC connection, mint, and token accounts
const { rpc, rpcSubscriptions, mint } = await demoSetup(sender, recipient);
// =============================================================================
// Step 1: Create a Nonce Account
// =============================================================================
const nonceKeypair = await generateKeyPairSigner();
console.log("\nNonce Account Address:", nonceKeypair.address);
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();
// Instruction to create new account for the nonce
const createNonceAccountIx = getCreateAccountInstruction({
payer: sender,
newAccount: nonceKeypair,
lamports: nonceRent,
space: nonceSpace,
programAddress: SYSTEM_PROGRAM_ADDRESS
});
// Instruction to initialize the nonce account
const initNonceIx = getInitializeNonceAccountInstruction({
nonceAccount: nonceKeypair.address,
nonceAuthority: sender.address
});
// Build and send nonce account creation transaction
const { value: blockhash } = await rpc.getLatestBlockhash().send();
const createNonceTx = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
(tx) =>
appendTransactionMessageInstructions(
[createNonceAccountIx, initNonceIx],
tx
)
);
const signedCreateNonceTx =
await signTransactionMessageWithSigners(createNonceTx);
assertIsTransactionWithBlockhashLifetime(signedCreateNonceTx);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedCreateNonceTx,
{ commitment: "confirmed" }
);
console.log("Nonce Account created.");
// =============================================================================
// Step 2: Token Payment with Durable Nonce
// =============================================================================
// Fetch current nonce value from the nonce account
const { data: nonceData } = await fetchNonce(rpc, nonceKeypair.address);
console.log("Nonce Account data:", nonceData);
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipientAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
console.log("\nMint Address:", mint.address);
console.log("Sender Token Account:", senderAta);
console.log("Recipient Token Account:", recipientAta);
const transferInstruction = getTransferInstruction({
source: senderAta,
destination: recipientAta,
authority: sender.address,
amount: 250_000n // 0.25 tokens
});
// Create transaction message using durable nonce lifetime
// setTransactionMessageLifetimeUsingDurableNonce automatically prepends
// the AdvanceNonceAccount instruction
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) =>
setTransactionMessageLifetimeUsingDurableNonce(
{
nonce: nonceData.blockhash as string as Nonce,
nonceAccountAddress: nonceKeypair.address,
nonceAuthorityAddress: nonceData.authority
},
tx
),
(tx) => appendTransactionMessageInstructions([transferInstruction], tx)
);
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
assertIsTransactionWithDurableNonceLifetime(signedTransaction);
const transactionSignature = getSignatureFromTransaction(signedTransaction);
// Encode the transaction to base64, optionally save and send at a later time
const base64EncodedTransaction =
getBase64EncodedWireTransaction(signedTransaction);
console.log("\nBase64 Encoded Transaction:", base64EncodedTransaction);
// Send the encoded transaction, blockhash does not expire
await rpc
.sendTransaction(base64EncodedTransaction, {
encoding: "base64",
skipPreflight: true
})
.send();
console.log("\n=== Token Payment with Durable Nonce Complete ===");
console.log("Transaction Signature:", transactionSignature);
// =============================================================================
// Demo Setup Helper Function
// =============================================================================
Console
Click to execute the code.

Mitätöi odottava transaktio

Jokaista nonce-tiliä blockhash voidaan käyttää vain kerran. Mitätöidäksesi odottavan transaktion tai valmistellaksesi nonce-tilin uudelleenkäyttöä varten, edistä sitä manuaalisesti:

import { getAdvanceNonceAccountInstruction } from "@solana-program/system";
// Submit this instruction (with a regular blockhash) to invalidate any pending transaction
getAdvanceNonceAccountInstruction({
nonceAccount: nonceAddress,
nonceAuthority
});

Tämä luo uuden nonce-arvon, mikä tekee kaikista vanhalla arvolla allekirjoitetuista transaktioista pysyvästi virheellisiä.

Moniosapuolinen hyväksyntätyönkulku

Deserialisoi transaktio lisätäksesi ylimääräisiä allekirjoituksia, ja serialisoi sitten uudelleen tallennusta tai lähettämistä varten:

import {
getBase64Decoder,
getTransactionDecoder,
getBase64EncodedWireTransaction,
partiallySignTransaction
} from "@solana/kit";
// Deserialize the stored transaction
const txBytes = getBase64Decoder().decode(serializedString);
const partiallySignedTx = getTransactionDecoder().decode(txBytes);
// Each approver adds their signature
const fullySignedTx = await partiallySignTransaction(
[newSigner],
partiallySignedTx
);
// Serialize again for storage or submission
const serialized = getBase64EncodedWireTransaction(fullySignedTx);

Transaktio voidaan serialisoida, tallentaa ja välittää hyväksyjien välillä. Kun kaikki vaaditut allekirjoitukset on kerätty, lähetä verkkoon.

Tuotantoympäristön huomioitavaa

Nonce-tilin hallinta:

  • Luo joukko nonce-tilejä rinnakkaista transaktiovalmistelua varten
  • Seuraa, mitkä noncet ovat "käytössä" (niillä on odottavia allekirjoitettuja transaktioita)
  • Toteuta noncen kierrätys sen jälkeen, kun transaktiot on lähetetty tai hylätty

Turvallisuus:

  • Nonce-valtuutus määrittää, voidaanko transaktiot mitätöidä. Harkitse nonce-valtuutuksen erottamista transaktioiden allekirjoittajista lisävalvontaa ja tehtävien erottelua varten
  • Kuka tahansa, jolla on sarjallistetut transaktiotavut, voi lähettää sen verkkoon

Aiheeseen liittyvät resurssit

Is this page helpful?

Sisällysluettelo

Muokkaa sivua

Hallinnoi

© 2026 Solana Foundation.
Kaikki oikeudet pidätetään.
Yhdistä