Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encodePackage 添加 initScriptFuntion 提交交易报错 #42

Closed
zhanghongfei opened this issue Mar 11, 2022 · 13 comments
Closed

encodePackage 添加 initScriptFuntion 提交交易报错 #42

zhanghongfei opened this issue Mar 11, 2022 · 13 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@zhanghongfei
Copy link
Contributor

starcoin.js 版本 1.9.0

TestToken.move

module TestAddress::TestToken {
    use StarcoinFramework::Token;

    struct USD has copy, drop, store {}

    public(script) fun init(account: signer) {
        Token::register_token<USD>(&account, 9);
    }
}

deploy 脚本

const fs = require('fs');
const {
    utils,
    providers,
} = require('@starcoin/starcoin');

const Address = "部署地址";
const PK = "私钥";

async function index() {

    const provider = new providers.WebsocketProvider("ws://127.0.0.1:9870");
    const chainId = 254;
    const senderSequenceNumber = await provider.getSequenceNumber(Address);
    const nowSeconds = await provider.getNowSeconds();

    const transactionPayload = utils.tx.encodePackage(
        Address,
        [ fs.readFileSync(`storage/0x${Address}/modules/TestToken.mv`) ],
        {   // 这里添加初始化操作
            functionId: `${Address}::TestToken::init`,
            tyArgs: utils.tx.encodeStructTypeTags([]),
            args: [],
        },
    );
    const rawUserTransaction = utils.tx.generateRawUserTransaction(
        Address,
        transactionPayload,
        10000000,   //maxGasAmount
        1,          // gasUnitPrice
        senderSequenceNumber,
        nowSeconds + 43200,
        chainId,
    );
    const signedUserTransactionHex = await utils.tx.signRawUserTransaction(
        PK,
        rawUserTransaction,
    );
    //  以上都可以顺利执行下去

    const txn = await provider.sendTransaction(signedUserTransactionHex);
    const txnInfo = await txn.wait(1);
    console.log(txnInfo);
    provider.destroy()
}
index()

在 provider.sendTransaction 时报错

/test/node_modules/@starcoin/starcoin/dist/starcoin.js:2255
        throw new Error("Unknown variant index for TypeTag: " + index);
              ^

Error: Unknown variant index for TypeTag: 3961
    at Function.deserialize (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:2255:15)
    at Function.deserializeVectorTypeTag (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:2713:25)
    at Function.deserialize (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:1654:27)
    at Function.deserializeOptionScriptFunction (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:2615:29)
    at Function.deserialize (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:1493:31)
    at Function.load (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:2144:25)
    at Function.deserialize (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:2088:49)
    at Function.deserialize (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:1528:38)
    at Function.deserialize (/test/node_modules/@starcoin/starcoin/dist/starcoin.js:1705:38)
    at /test/node_modules/@starcoin/starcoin/dist/starcoin.js:3089:34
@jolestar
Copy link
Member

是不是 tyArgs: utils.tx.encodeStructTypeTags([]) 这里有问题?

@zhanghongfei
Copy link
Contributor Author

utils.tx.encodeStructTypeTags([]) 这里是没问题的,只有在 sendTransaction 时 deserialize 才会有问题

@jolestar
Copy link
Member

utils.tx.encodeStructTypeTags([]) 这里是没问题的,只有在 sendTransaction 时 deserialize 才会有问题

sendTransaction 为什么需要 deserialize? 解析返回值么?可以帮忙再具体诊断一下。另外你本地的 starcoin 版本是?

@zhanghongfei
Copy link
Contributor Author

zhanghongfei commented Mar 14, 2022

starcoin 1.10.0-rc.2

我排查了下, 大概问题是这样的

starcoin_types.Package 打包 init_script 的类型应该是: ScriptFunction

代码中

export function encodePackage(
  moduleAddress: string,
  moduleCodes: HexString[],
  initScriptFunction?: { functionId: FunctionId; tyArgs: TypeTag[]; args: bytes[] }
): starcoin_types.TransactionPayloadVariantPackage {
  const modules = moduleCodes.map((m) => new starcoin_types.Module(arrayify(m)));
  let scriptFunction = null;
  if (!!initScriptFunction) {
    scriptFunction = encodeScriptFunction(initScriptFunction.functionId, initScriptFunction.tyArgs, initScriptFunction.args);
  }

这里的 scriptFunction = encodeScriptFunction() 返回的是 starcoin_types.TransactionPayloadVariantScriptFunction

然后 发送交易时解析包 Package.deserialize 是按照 deserializeOptionScriptFunction 去操作的

所以是 类型不一致造成的问题

我本地将 encodePackage 中的 encodeScriptFunction 返回值修改成 ScriptFunction 就可以跑通了

@jolestar
Copy link
Member

那就是 js sdk 的 bug 了, encodeScriptFunction 这个方法别的地方用么?是否方便提交个 pr 修复一下这个 bug。

@zhanghongfei
Copy link
Contributor Author

这个方法其他地方有用,不能直接修改,我改一版提个 pr 吧 ~

@wk3368
Copy link
Collaborator

wk3368 commented May 12, 2022

在本地尝试浮现你的bug,发现两个问题:

  1. 你的deploy 脚本里面

[ fs.readFileSync(storage/0x${Address}/modules/TestToken.mv) ],

这个参数的类型是HexString[], 而fs.readFileSync()返回的类型是Buffer, 所以不知道你这个demo是怎么跑通的。

我的test case是这样的:

test('encodePackage', async () => {
  const Address = "部署地址";
  const PK = "私钥";
  const buffer = fs.readFileSync(
    path.join(__dirname, "data", "TestToken.mv")
  );
  // const fileData = buffer.toString()
  const fileBytes = new Uint8Array(buffer)
  const fileHex = hexlify(fileBytes)

  const transactionPayload = encodePackage(
    Address,
    [fileHex],
    {   // 这里添加初始化操作
      functionId: `${ Address }::TestToken::init`,
      tyArgs: encodeStructTypeTags([]),
      args: [],
    },
  );

  const nodeUrl = 'https://barnard-seed.starcoin.org'

  const provider = new JsonRpcProvider(nodeUrl);

  const senderSequenceNumber = await provider.getSequenceNumber(Address)
  const chainId = 251;
  const nowSeconds = await provider.getNowSeconds();

  console.log({ senderSequenceNumber, nowSeconds })
  const rawUserTransaction = generateRawUserTransaction(
    Address,
    transactionPayload,
    10000000,   //maxGasAmount
    1,          // gasUnitPrice
    senderSequenceNumber,
    nowSeconds + 43200,
    chainId,
  );

  console.log({ rawUserTransaction })

  const signedUserTransactionHex = await signRawUserTransaction(
    PK,
    rawUserTransaction,
  );
  console.log({ signedUserTransactionHex })

  const txn = await provider.sendTransaction(signedUserTransactionHex);

  const txnInfo = await txn.wait(1);

  console.log(txnInfo);

}, 120000);

  1. 按照你#43的pr修改内容,我在本地测试的报错是:
processing response error (body="{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-49998,\"message\":\"Transaction error (Call txn err: Transaction execution error (Execution error: status BAD_MAGIC of type Deserialization)..)\",\"data\":\"MiscellaneousError\"},\"id\":47}\n", error={"code":-49998,"data":"MiscellaneousError"}, requestBody="{\"method\":\"txpool.submit_hex_transaction\",\"params\":[\"0xeb9a0d1628fddba79b932ced2623b1a4250000000000000001eb9a0d1628fddba79b932ced2623b1a401d3016d6f64756c652054657374416464726573733a3a54657374546f6b656e207b0a202020207573652053746172636f696e4672616d65776f726b3a3a546f6b656e3b0a0a20202020737472756374205553442068617320636f70792c2064726f702c2073746f7265207b7d0a0a202020207075626c696328736372697074292066756e20696e6974286163636f756e743a207369676e657229207b0a2020202020202020546f6b656e3a3a72656769737465725f746f6b656e3c5553443e28266163636f756e742c2039293b0a202020207d0a7d01eb9a0d1628fddba79b932ced2623b1a40954657374546f6b656e04696e69740000809698000000000001000000000000000d3078313a3a5354433a3a53544339ab7d6200000000fb0020a972a04aefbace3686e1889c47976ca664ad9f9384293c6b291811fc2870e2ba4038922582e05db9fd1751cb514b3885abe308e3dfe57aaf395f4b1ace86bd6c635ef090352a3c9ed412af6ce1323ea3bf22db26ddd208e8ec19a788ed5f69ad0d\"],\"id\":47,\"jsonrpc\":\"2.0\"}", requestMethod="POST", url="https://barnard-seed.starcoin.org", code=SERVER_ERROR, version=web/5.1.0)

      at Logger.Object.<anonymous>.Logger.makeError (node_modules/@ethersproject/logger/src.ts/index.ts:205:28)
      at Logger.Object.<anonymous>.Logger.throwError (node_modules/@ethersproject/logger/src.ts/index.ts:217:20)
      at node_modules/@ethersproject/web/src.ts/index.ts:284:28
      at step (node_modules/@ethersproject/web/lib/index.js:33:23)
      at Object.next (node_modules/@ethersproject/web/lib/index.js:14:53)
      at fulfilled (node_modules/@ethersproject/web/lib/index.js:5:58)

不知道这个服务端报错是什么原因?
@jolestar

@jolestar
Copy link
Member

processing response error (body="{"jsonrpc":"2.0","error":{"code":-49998,"message":"Transaction error (Call txn err: Transaction execution error (Execution error: status BAD_MAGIC of type Deserialization)..)","data":"MiscellaneousError"},"id":47}\n", error={"code":-49998,"data":"MiscellaneousError"}, requestBody="{"method":"txpool.submit_hex_transaction","params":["0xeb9a0d1628fddba79b932ced2623b1a4250000000000000001eb9a0d1628fddba79b932ced2623b1a401d3016d6f64756c652054657374416464726573733a3a54657374546f6b656e207b0a202020207573652053746172636f696e4672616d65776f726b3a3a546f6b656e3b0a0a20202020737472756374205553442068617320636f70792c2064726f702c2073746f7265207b7d0a0a202020207075626c696328736372697074292066756e20696e6974286163636f756e743a207369676e657229207b0a2020202020202020546f6b656e3a3a72656769737465725f746f6b656e3c5553443e28266163636f756e742c2039293b0a202020207d0a7d01eb9a0d1628fddba79b932ced2623b1a40954657374546f6b656e04696e69740000809698000000000001000000000000000d3078313a3a5354433a3a53544339ab7d6200000000fb0020a972a04aefbace3686e1889c47976ca664ad9f9384293c6b291811fc2870e2ba4038922582e05db9fd1751cb514b3885abe308e3dfe57aaf395f4b1ace86bd6c635ef090352a3c9ed412af6ce1323ea3bf22db26ddd208e8ec19a788ed5f69ad0d"],"id":47,"jsonrpc":"2.0"}", requestMethod="POST", url="https://barnard-seed.starcoin.org", code=SERVER_ERROR, version=web/5.1.0)

序列化错误。你可以试试在 js 中,能不能把 transaction hex 再反解析出来

@zhanghongfei
Copy link
Contributor Author

@wk3368 以下是我在本地的测试情况

第一个问题

为了便于观察首先,我在 node_modules/@starcoin/starcoin/dist/starcoin.js 中增加两行log ,如图:
Screen Shot 2022-05-16 at 09 41 37

一个是 log 输入情况
另一个是 log 将输入 map 之后的结果

  1. 使用 [ fs.readFileSync(storage/0x${Address}/modules/TestToken.mv) ], 作为输入的 log 结果输出:
[
  <Buffer a1 1c eb 0b 04 00 00 00 0a 01 00 06 02 06 0a 03 10 46 04 56 0a 05 60 3a 07 9a 01 89 01 08 a3 02 20 06 c3 02 03 0a c6 02 05 0c cb 02 7d 00 00 01 01 01 ... 452 more bytes>
]
[
  Module {
    code: Uint8Array(502) [
      161,  28, 235,  11,  4,  0,   0,  0,  10, 1,   0,  6,
        2,   6,  10,   3, 16, 70,   4, 86,  10, 5,  96, 58,
        7, 154,   1, 137,  1,  8, 163,  2,  32, 6, 195,  2,
        3,  10, 198,   2,  5, 12, 203,  2, 125, 0,   0,  1,
        1,   1,   2,   0,  0,  7,   0,  2,   2, 4,   1,  0,
        1,   0,   3,   0,  1,  0,   0,  4,   2, 1,   0,  0,
        5,   1,   3,   0,  0,  6,   1,  3,   0, 0,   7,  1,
        3,   0,   0,   8,  1,  3,   0,  0,   9, 1,   3,  0,
        0,  10,   1,   3,
      ... 402 more items
    ]
  }
]
{
  state_root_hash: '0xcebb7ba1d2c9f73d4883a2cf63e4ad0cdecbb99c8f0a52dfe28a58d6b64dab1f',
  event_root_hash: '0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000',
  gas_used: 7800,
  status: 'Executed',
  txn_events: null,
  block_hash: '0x57a60c1ff9565b2be5c11c6c59e129b81e9e3914cfa09437e5775139f55e7939',
  block_number: 73,
  transaction_hash: '0x071e8ee7be4e9a13d77d7a4bf695ffd61350c8eceed8b937b47ab4e85536b203',
  transaction_index: 1,
  confirmations: 1
}
  1. 按照你上述的操作,将 fileHex 作为输入,结果是这样的
[
  '0xa11ceb0b040000000a01000602060a03104604560a05603a079a01890108a3022006c302030ac602050ccb027d000001010102000007000202040100010003000100000402010000050103000006010300000701030000080103000009010300000a010300020c06010104010d07010104020408090104010e0a010104010f0c010104080509050a050b050c05010c00030c0504010202060c0b0101080001080002060c0201060c02060c04010b0101090002060c0b01010900010b0101080002050b0101090003555344074163636f756e7405546f6b656e04696e6974046d696e7406746573745f6106746573745f6206746573745f6306746573745f6406746573745f6506746573745f660b64756d6d795f6669656c640e72656769737465725f746f6b656e0f646f5f6163636570745f746f6b656e0f6465706f7369745f746f5f73656c66076465706f736974605f54be15004c4c25a535f3281a5dbf000000000000000000000000000000010201090002010b0100020000040f0e000c010a01070038000a0138010a013200a0724e18090000000000000000000038020c020b010b02380302010200000b080e000a0238020c030a010b0338040202010000010231010203010000010231020204010000010231030205010000010231040206010000010231050207010000010231060200'
]
[
  Module {
    code: Uint8Array(502) [
      161,  28, 235,  11,  4,  0,   0,  0,  10, 1,   0,  6,
        2,   6,  10,   3, 16, 70,   4, 86,  10, 5,  96, 58,
        7, 154,   1, 137,  1,  8, 163,  2,  32, 6, 195,  2,
        3,  10, 198,   2,  5, 12, 203,  2, 125, 0,   0,  1,
        1,   1,   2,   0,  0,  7,   0,  2,   2, 4,   1,  0,
        1,   0,   3,   0,  1,  0,   0,  4,   2, 1,   0,  0,
        5,   1,   3,   0,  0,  6,   1,  3,   0, 0,   7,  1,
        3,   0,   0,   8,  1,  3,   0,  0,   9, 1,   3,  0,
        0,  10,   1,   3,
      ... 402 more items
    ]
  }
]
{
  state_root_hash: '0x2c999f05e56ce69f10982b71e6eb69b8642c372085e626b58786b5d6004db06f',
  event_root_hash: '0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000',
  gas_used: 7800,
  status: 'Executed',
  txn_events: null,
  block_hash: '0x441d6369f1b3ddbcadc669b7e933e9e8c0e1e209a6f09891012994ec571b3e79',
  block_number: 72,
  transaction_hash: '0x172c26ccff82805c6bc980643cf5d72f2a4259a8c552ea248b26487d50a09572',
  transaction_index: 1,
  confirmations: 1
}

可以看到,不管输入如何,在经过

const modules = moduleCodes.map((m) => new starcoin_types.Module(arrayify(m)));

之后,得到的结果是一致的,所以我们能一直部署成功吧。

第二个问题

utils.tx.encodeScriptFunction

export function encodeScriptFunction(functionId: FunctionId,
  tyArgs: TypeTag[],
  args: bytes[]): starcoin_types.TransactionPayloadVariantScriptFunction {
  const funcId = parseFunctionId(functionId);
  const scriptFunction = new starcoin_types.ScriptFunction(
    new starcoin_types.ModuleId(addressToSCS(funcId.address), new starcoin_types.Identifier(funcId.module)),
    new starcoin_types.Identifier(funcId.functionName),
    tyArgs.map((t) => typeTagToSCS(t)),
    args
  );
  return new starcoin_types.TransactionPayloadVariantScriptFunction(scriptFunction);

这里返回的是. TransactionPayloadVariantScriptFunction

starcoin_types.Package 这里

export class Package {

  constructor(public package_address: AccountAddress, public modules: Seq<Module>, public init_script: Optional<ScriptFunction>) {
  }

这里的 init_script 需要的是 ScriptFunction

@wk3368
Copy link
Collaborator

wk3368 commented May 16, 2022

  1. TestToken.mv
    我用mpm生成TestToken.mv , 按照你的步骤,生成 signedUserTransactionHex, 然后通过contract.dry_run_raw,返回报错
{
    "jsonrpc": "2.0",
    "error": {
        "code": -32602,
        "message": "Invalid params: DeserializationError."
    },
    "id": 200
}

你提供一下你用的address和pk?
然后告诉我你的mpm的版本是多少?

我在本地生成一下这个TestToken.mv

我先跟你比对这个 TestToken.mv 的 fileHex 是否一样吧。

@wk3368
Copy link
Collaborator

wk3368 commented May 16, 2022

加了一个test case:

test('encodePackage', async () => {
  const address = '0xedb4a7199ae49f76991614CF4C39c585'
  const privateKey = '0a4a0fe4985df2590ac59c208775f36438a47193ce6eeb197964d8a8f8a6a1f9'
  const buffer = fs.readFileSync(
    path.join(__dirname, "data", "TestToken.mv")
  );
  const fileBytes = new Uint8Array(buffer)
  const fileHex = hexlify(fileBytes)
  const transactionPayload = encodePackage(
    address,
    [fileHex],
    {
      functionId: `${ address }::TestToken::init`,
      tyArgs: encodeStructTypeTags([]),
      args: [],
    },
  );


  const nodeUrl = 'https://barnard-seed.starcoin.org'

  const provider = new JsonRpcProvider(nodeUrl);

  const senderSequenceNumber = await provider.getSequenceNumber(address)
  const chainId = 251;
  const nowSeconds = await provider.getNowSeconds();

  console.log({ senderSequenceNumber, nowSeconds })
  const rawUserTransaction = generateRawUserTransaction(
    address,
    transactionPayload,
    10000000,   //maxGasAmount
    1,          // gasUnitPrice
    senderSequenceNumber,
    nowSeconds + 43200,
    chainId,
  );

  console.log({ rawUserTransaction })

  const signedUserTransactionHex = await signRawUserTransaction(
    privateKey,
    rawUserTransaction,
  );
  console.log({ signedUserTransactionHex })

  const txn = await provider.sendTransaction(signedUserTransactionHex);

  const txnInfo = await txn.wait(1);

  console.log(txnInfo);

  expect(txnInfo.status).toBe('Executed');
}, 60000);

@wk3368
Copy link
Collaborator

wk3368 commented May 16, 2022

第一个问题

我知道这个区别是怎么回事了,你是直接应用的dist的js,所以是没有类型检查的
我是直接在源码的ts里面写test case,所以这个函数是有类型检查的

export function encodePackage(
  moduleAddress: string,
  moduleCodes: HexString[],
  initScriptFunction?: { functionId: FunctionId; tyArgs: TypeTag[]; args: bytes[] }
): starcoin_types.TransactionPayloadVariantPackage

@wk3368 wk3368 closed this as completed May 16, 2022
@wk3368
Copy link
Collaborator

wk3368 commented May 16, 2022

fixed in 8866795#diff-f8acdc63c182d7b401f4b31352ffdb2adac0684cf0bcf93a8d36c7adfbbe6943R690

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants