You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Substrate的项目中,使用polkadot.js开发的Node.js应用无法修改链上存储的问题求助

Troubleshooting: Your Polkadot.js App Not Modifying Substrate Chain Storage

Let’s break down why your Node.js app isn’t updating the Substrate chain storage and fix it step by step. I’ve gone through your code and spotted several key issues that are causing the problem:

1. You’re Not Actually Sending Transactions to the Chain

In your initial code, you only created transaction objects like api.tx.carpooling.addNewCab() but never signed and submitted them to the chain. Transactions won’t be processed until you call signAndSend() with a valid account. Even your updated code has execution order issues that break the workflow.

2. Async Code Execution Order Is Wrong

In your updated code, you’re trying to call bookRide() right after starting the addNewCab() promise. This means you’re attempting to book a driver that hasn’t been added to the chain yet—triggering the DriverDoesNotExist error and failing the transaction.

3. Frontend Type Definitions Don’t Match the Chain’s Struct

Your chain’s SDriver struct includes a destination field, but your frontend DriverOf type definition is missing it. This causes encoding errors when sending transactions, so the node can’t parse your data correctly.

4. The getDriver RPC Method Isn’t Implemented On-Chain

You defined api.rpc.carpooling.getDriver() in your frontend, but there’s no corresponding RPC endpoint in your pallet. That’s why you’re getting None—the method doesn’t actually fetch any data from storage.


Step-by-Step Fixes

Fix 1: Align Frontend Types with the Chain

Update your types configuration to match the SDriver struct exactly. Note that Polkadot.js uses arrays to represent tuples (not parentheses like Rust):

types: {
  DriverOf: {
    id: 'u32',
    car_no: 'Hash',
    location: ['u32', 'u32'],
    price: 'u32',
    destination: ['u32', 'u32'], // Add the missing destination field
  },
  CustomerOf: {
    id: 'u32',
    name: 'Hash',
    location: ['u32', 'u32'],
  },
}

Fix 2: Fix Async Execution Order & Properly Send Transactions

Wrap the bookRide call inside the addNewCab success callback to ensure the driver exists before booking. Also, add proper transaction status and error handling:

// Add keyring setup at the top of your main function
const { Keyring } = require('@polkadot/keyring');
const keyring = new Keyring({ type: 'sr25519' });
const alice = keyring.addFromUri('//Alice'); // Use a valid funded account

// ...

try {
  const cabNo = 'UP76 E 8550';
  const output = digestMessage(cabNo);
  
  output.then(async (hash) => {
    // 1. First, add the driver
    const addDriverTx = api.tx.carpooling.addNewCab(12, {
      id: 12,
      car_no: hash,
      location: [10, 20],
      price: 50,
      destination: [30, 40]
    });

    // Send the add driver transaction and wait for confirmation
    await addDriverTx.signAndSend(alice, ({ status, events, dispatchError }) => {
      if (dispatchError) {
        handleTxError(dispatchError);
        return;
      }

      if (status.isInBlock) {
        console.log('Add driver tx included in block');
        // Check for success event (make sure your pallet emits this!)
        events.forEach(({ event }) => {
          if (event.section === 'carpooling' && event.method === 'DriverAdded') {
            console.log('Driver added successfully!');
            // 2. Now book the ride since the driver exists
            bookRide(api, alice, 12, 99);
          }
        });
      } else if (status.isFinalized) {
        console.log('Add driver tx finalized');
      }
    });
  }).catch(e => console.log('Error processing cab number:', e));
} catch (error) {
  console.log('Main error:', error);
}

// Helper function to handle transaction errors
function handleTxError(dispatchError) {
  if (dispatchError.isModule) {
    const decoded = api.registry.findMetaError(dispatchError.asModule);
    const { section, name, documentation } = decoded;
    console.error(`Tx failed: ${section}.${name} — ${documentation.join(' ')}`);
  } else {
    console.error(`Tx failed: ${dispatchError.toString()}`);
  }
}

// Helper function to book a ride
async function bookRide(api, account, driverId, customerId) {
  const bookRideTx = api.tx.carpooling.bookRide(driverId, customerId);
  
  await bookRideTx.signAndSend(account, ({ status, events, dispatchError }) => {
    if (dispatchError) {
      handleTxError(dispatchError);
      return;
    }

    if (status.isInBlock) {
      console.log('Book ride tx included in block');
      events.forEach(({ event }) => {
        if (event.section === 'carpooling' && event.method === 'CabBooked') {
          console.log('Cab booked successfully!');
          // Query the storage directly to confirm the update
          queryBooking(api, driverId);
        }
      });
    } else if (status.isFinalized) {
      console.log('Book ride tx finalized');
    }
  });
}

// Helper function to query booking storage
async function queryBooking(api, driverId) {
  // Query the pallet's storage directly instead of relying on unimplemented RPC
  const bookedCustomer = await api.query.carpooling.booking(driverId);
  console.log(`Booked customer for driver ${driverId}: ${bookedCustomer.toString()}`);
}

Fix 3: Implement the getDriver RPC Endpoint (If Needed)

If you want to use api.rpc.carpooling.getDriver(), add this RPC implementation to your pallet:

#[pallet::rpc]
pub trait Rpc<T: Config> {
    #[rpc(name = "carpooling_getDriver")]
    fn get_driver(&self, driver_id: u32) -> Result<Option<SDriver<T::Hash>>, DispatchError>;
}

impl<T: Config> Rpc<T> for Pallet<T> {
    fn get_driver(&self, driver_id: u32) -> Result<Option<SDriver<T::Hash>>, DispatchError> {
        // Fetch the driver from storage
        let driver = <Driver<T>>::get(&driver_id);
        Ok(driver)
    }
}

Debugging Tips

  • Check Node Logs: Run your Substrate node with ./target/release/node-template --dev -lruntime=debug to see detailed transaction errors.
  • Test with Polkadot.js Apps: First confirm your pallet works via the local Apps interface (http://localhost:8000) to rule out chain-side issues.
  • Verify Account Balance: Make sure the account you’re using (Alice) has enough balance to pay transaction fees.

内容的提问来源于stack exchange,提问作者Aman Verma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 06:27:37