Перейти к основному содержимому

Редакционная доработка ещё намеренно не завершена

Этот раздел скрыт из основной навигации. Перевод и редакторская полировка намеренно не считаются обязательными, пока раздел не станет публичным.

Справочник

This page provides a comprehensive mental model for understanding NEAR's async execution, practical debugging руководства, and quick справочник materials.

The Five-Level Асинхронная Model

This mental model crystallizes everything about NEAR's asynchronous execution.

Level 1: Контракт VM (Promise Creation)

When your контракта runs, you create promises - declarations of future work:

// This doesn't call now - it declares intent
let promise = env::promise_create("other.near", "method", args, 0, gas);
// promise is just an index (0, 1, 2...)

Promises are declarative, not imperative. You're not calling - you're scheduling.

Level 2: Conversion (Promise → Квитанция)

When your function returns, the runtime converts promises to квитанции:

// Your code ends, runtime takes over:
for promise in promises {
let receipt = ReceiptManager::convert(promise);
outgoing_receipts.push(receipt);
}

ReceiptManager handles:

  • Assigning unique receipt_ids
  • Setting up data dependencies
  • Distributing газ based on weights

Level 3: Сеть Routing (Квитанция Distribution)

Receipts route to their receiver's shard:

Receipt { receiver_id: "alice.near" }
→ Lookup: account_id_to_shard_id("alice.near")
→ Route to shard 2

Routing is deterministic - every node computes the same destination.

Level 4: Execution (Квитанция Processing)

On the receiving shard, квитанции execute when ready:

fn process_receipt(receipt: ActionReceipt) {
// Wait for all dependencies
for data_id in receipt.input_data_ids {
if !data_exists(data_id) {
store_as_delayed(receipt);
return;
}
}

// All ready - execute!
let results = execute_actions(receipt.actions);

// Send results to dependents
for receiver in receipt.output_data_receivers {
create_data_receipt(receiver, results);
}
}

Level 5: Data Flow (Callbacks)

Results flow back as DataReceipts:

ActionReceipt A executes
↓ produces result
DataReceipt D (data_id: X, data: "hello")
↓ routes to callback location
ActionReceipt B (input_data_ids: [X])
↓ now has its dependency
B executes with PromiseResult::Successful("hello")

Why NEAR is Асинхронная

Sharding makes sync impossible.

Consider a sync вызов:

Shard 0: Contract A calls Contract B
Shard 0: WAIT for result...
Shard 1: B hasn't heard of this call yet (different block!)

You can't wait for another shard - it's not processing your запрос yet!

The solution: Отправка a message, continue with your work, process the reply later.

Асинхронная vs Sync: Mental Comparison

Ethereum (Sync)

A.call() {
let result = B.call(); // Blocks until B returns
process(result);
}
PropertyDescription
ExecutionSingle thread
Вызов modelStack-based
ResultsImmediate
ScalabilityLimited

NEAR (Асинхронная)

A.call() {
let promise = B.promise_call(); // Schedules, doesn't wait
promise.then(A.callback); // Callback for later
}

A.callback() {
let result = get_promise_result(); // Result available now
process(result);
}
PropertyDescription
ExecutionMultiple concurrent
Вызов modelКвитанция-based messages
ResultsDelayed
ScalabilityHorizontal

The Mail System Analogy

Think of NEAR as a distributed mail system:

NEAR ConceptMail Analogy
ТранзакцииDropping a letter at the post office
ReceiptsMail being routed through sorting centers
ShardsDifferent postal districts
DataReceiptsReply letters
Callbacks"Please reply to this address"
Delayed квитанцииMail waiting for a related package

You never "вызов" another контракта. You отправка them a letter and ask them to отправка one back. Everything is asynchronous because the mail system doesn't teleport.


Practical Справочник

curl Examples

Submit Транзакция (Асинхронная)

# Submit and get hash immediately
curl -X POST https://rpc.mainnet.fastnear.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "broadcast_tx_async",
"params": ["BASE64_ENCODED_SIGNED_TX"]
}'

# Response:
# {"jsonrpc":"2.0","id":"1","result":"6zgh2u9DqHHiXzdy9ouTP7oGky2T4nugqzqt9wJZwNFm"}

Submit Транзакция (Wait for Final)

curl -X POST https://rpc.mainnet.fastnear.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "broadcast_tx_commit",
"params": ["BASE64_ENCODED_TX"]
}'

Check Транзакция Статус

curl -X POST https://rpc.mainnet.fastnear.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "tx",
"params": {
"tx_hash": "6zgh2u9DqHHiXzdy9ouTP7oGky2T4nugqzqt9wJZwNFm",
"sender_account_id": "sender.testnet",
"wait_until": "FINAL"
}
}'

Просмотр доступ Key (for nonce)

curl -X POST https://rpc.mainnet.fastnear.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "query",
"params": {
"request_type": "view_access_key",
"finality": "final",
"account_id": "sender.testnet",
"public_key": "ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847"
}
}'

# Response includes:
# "nonce": 12345, <- Use nonce + 1 for next transaction

Get Recent Блок Hash

curl -X POST https://rpc.mainnet.fastnear.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "block",
"params": {
"finality": "final"
}
}'

# Use result.header.hash as block_hash in transaction

Debugging Guide

Транзакция Debugging Flowchart

1. Did the RPC accept it?

├─► NO: Immediate error returned
│ → Check: Invalid JSON, decode failure, validation error

└─► YES: Continue to step 2

2. Did it reach the mempool?
│ (broadcast_tx_async returns hash)

├─► NO: Forwarding failed
│ → Check: No route to validators, network issues

└─► YES: Continue to step 3

3. Did it get included in a chunk?
│ (tx status shows INCLUDED or beyond)

├─► NO: Dropped from mempool
│ → Check: Expired, superseded by higher nonce, insufficient balance

└─► YES: Continue to step 4

4. Did the initial receipt succeed?
│ (Check transaction_outcome.status)

├─► NO: First action(s) failed
│ → Check: status.Failure for error type

└─► YES (SuccessReceiptId): Continue to step 5

5. Did all receipts complete successfully?
│ (Walk receipts_outcome array)

├─► NO: Some receipt failed
│ → Find the failing receipt_id, check its status

└─► YES: Transaction fully succeeded

Common Error Messages

Invalid Nonce

{
"error": {
"InvalidTransaction": {
"InvalidNonce": {
"tx_nonce": 5,
"ak_nonce": 10
}
}
}
}

Cause: Транзакция nonce (5) is not greater than доступа ключ nonce (10)

Fix: Запрос view_access_key and use nonce + 1

Expired Транзакция

{
"error": {
"InvalidTransaction": {
"Expired": null
}
}
}

Cause: The block_hash references a блока that's too old (~24 hours)

Fix: Get a fresh блока hash and re-sign the транзакции

Not Enough Balance

{
"error": {
"InvalidTransaction": {
"NotEnoughBalance": {
"signer_id": "alice.near",
"balance": "1000000000000000000000000",
"cost": "5000000000000000000000000"
}
}
}
}

Cause: Аккаунт doesn't have enough NEAR for газ + deposits

Fix: Add more NEAR to the аккаунта or reduce транзакции size

Invalid Signature

{
"error": {
"InvalidTransaction": {
"InvalidSignature": null
}
}
}

Cause: Signature doesn't match the транзакции and public ключ

Fix:

  • Verify signing ключ matches the public ключ in транзакции
  • Ensure транзакции is serialized with Borsh before signing
  • Check you're signing the SHA-256 hash of the Borsh bytes

доступ Key Not Found

{
"error": {
"InvalidTransaction": {
"InvalidAccessKeyError": {
"AccessKeyNotFound": {
"account_id": "alice.near",
"public_key": "ed25519:..."
}
}
}
}
}

Cause: The public ключ isn't registered on the аккаунта

Fix: Use a ключ that exists on the аккаунта

Debugging Tips

1. Check Транзакция Статус

Always check full статус after submission:

const result = await provider.txStatus(txHash, accountId);
console.log(JSON.stringify(result, null, 2));

2. Examine Receipts

If the транзакции succeeded but the action failed, check квитанция outcomes:

for (const outcome of result.receipts_outcome) {
console.log('Receipt:', outcome.id);
console.log('Status:', outcome.outcome.status);
console.log('Logs:', outcome.outcome.logs);
}

3. Use Explorer

NEAR Explorer provides detailed транзакции visualization:

4. Common Gotchas

GotchaDescription
Nonce race conditionsWhen sending multiple транзакции quickly, ensure nonces are sequential
Газ estimationFunction calls may need more газ than expected for complex operations
Cross-shard delaysТранзакции to аккаунтов on other shards take an extra блока
Финальность"Included" doesn't mean "final" - wait for финальность for important operations
Callback failuresEven if main вызов succeeds, callback might fail - check all квитанция outcomes

Data Structure Справочник

Core Types

// 32-byte hash
pub struct CryptoHash(pub [u8; 32]);

// Variable-length account name (2-64 bytes)
pub struct AccountId(String);

// Wrapper type around u128 for balances (in yoctoNEAR)
pub type Balance = near_token::NearToken; // internally u128

// 64-bit unsigned integer for gas
pub type Gas = u64;

// 64-bit unsigned integer for nonces
pub type Nonce = u64;

// Block height
pub type BlockHeight = u64;

// Shard identifier
pub type ShardId = u64;

Key Types

pub enum PublicKey {
ED25519(ED25519PublicKey), // 32 bytes
SECP256K1(Secp256K1PublicKey), // 64 bytes
}

pub enum Signature {
ED25519(ed25519_dalek::Signature), // 64 bytes
SECP256K1(Secp256K1Signature), // 65 bytes
}

Транзакция Types

pub struct SignedTransaction {
pub transaction: Transaction,
pub signature: Signature,
hash: CryptoHash, // Computed
size: u64, // Computed
}

pub enum Transaction {
V0(TransactionV0),
V1(TransactionV1),
}

Encoding Справочник

EncodingUse CaseEfficient For
Base58Human-readable identifiers (hashes, ключи)Short data
Base64Транзакция payloads (binary data)Large data
BorshCanonical serialization (signing, storage)All structured data

Glossary

TermDefinition
доступ KeyA public ключ registered on an аккаунта with specific permissions (full доступа or function вызов only)
ActionA primitive operation within a транзакции (transfer, function вызов, etc.)
БлокA collection of chunks at a specific height
BorshBinary Object Representation Serializer for Hashing - NEAR's canonical serialization format
ChunkA unit of состояние transition for a single shard
EpochA period of ~12 hours during which the валидатора set is fixed
ФинальностьThe guarantee that a блока will not be reverted. NEAR has ~2 second финальность
ГазThe unit of computation cost. Газ price varies with сеть demand
MempoolWhere valid транзакции wait for inclusion in a блока
NonceA number that must increase with each транзакции from an доступа ключ
КвитанцияAn internal message created during транзакции execution, used for cross-shard communication
ShardA partition of the состояние. Each аккаунта belongs to exactly one shard
ValidatorA node that participates in consensus and блока production
yoctoNEARThe smallest unit of NEAR (10^-24 NEAR)

Key Principles to Remember

  1. Promises are declarative: You schedule work, not execute it
  2. Receipts are the unit of execution: Not транзакции
  3. Callbacks are mandatory: For any cross-контракта result
  4. Dependencies are explicit: input_data_ids and output_data_receivers
  5. Order is causal, not global: A→B guaranteed, A vs C across shards is not
  6. Газ prepaid, refunds later: Not immediate balance changes
  7. Финальность takes time: Multiple блоки for complex flows