#failed to convert ScVal to host value

13 messages · Page 1 of 1 (latest)

trim charm
#

I have an issue with invoking a function that uses struct as a parameter.

Before my struct looked like this:

pub struct Proposal { pub end_time: u64, pub url: String, }

On client side I would build the struct and invoke the function like this:

`const proposal = SorobanClient.xdr.ScVal.scvMap([
new SorobanClient.xdr.ScMapEntry({
key: SorobanClient.xdr.ScVal.scvSymbol("end_time"),
val: SorobanClient.nativeToScVal(input.deadline, { type: 'u64' })
}),
new SorobanClient.xdr.ScMapEntry({
key: SorobanClient.xdr.ScVal.scvSymbol("url"),
val: SorobanClient.nativeToScVal(input.proposalUrl)
// val: SorobanClient.nativeToScVal("www.epic.com", { type: 'string' })
}),
])

        const creator = new SorobanClient.Address(
            input.publicKey
        ).toScAddress();
        console.log('proposal: ', proposal)
        const transaction_object = new SorobanClient.TransactionBuilder(
            account,
            {
            fee,
            networkPassphrase: SorobanClient.Networks.FUTURENET,
            }
        )
            .addOperation(
            // An operation to call increment on the contract
            contract.call(
                "create_proposal",
                SorobanClient.xdr.ScVal.scvAddress(creator),
                proposal
            ))
            .setTimeout(30)
            .build();`

This worked very well when invoking it. Since then I added one more value into Proposal struct so now it looks like this:

pub struct Proposal { pub end_time: u64, pub url: String, pub min_quorum: i128, }

So client is slightly different when I construct the proposal, but invocation stays the same:

#

const proposal = SorobanClient.xdr.ScVal.scvMap([ new SorobanClient.xdr.ScMapEntry({ key: SorobanClient.xdr.ScVal.scvSymbol("end_time"), val: SorobanClient.nativeToScVal(input.deadline, { type: 'u64' }) }), new SorobanClient.xdr.ScMapEntry({ key: SorobanClient.xdr.ScVal.scvSymbol("url"), val: SorobanClient.nativeToScVal(input.proposalUrl) }), new SorobanClient.xdr.ScMapEntry({ key: SorobanClient.xdr.ScVal.scvSymbol("min_quorum"), val: SorobanClient.nativeToScVal(input.minimumParticipation, { type: 'i128 }) }) ])

But this causes the error:

#

simulation_res: { _parsed: true, id: undefined, latestLedger: '303932', events: [ ChildStruct { _attributes: [Object] } ], error: 'host invocation failed\n' + '\n' + 'Caused by:\n' + ' HostError: Error(Value, InternalError)\n' + ' \n' + ' Event log (newest first):\n' + ' 0: [Diagnostic Event] topics:[error, Error(Value, InternalError)], data:"failed to convert ScVal to host value"\n' + ' \n' + ' Backtrace (newest first):\n' + ' 0: <core::iter::adapters:🗺️:Map<I,F> as core::iter::traits::iterator::Iterator>::try_fold\n' + ' 1: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter\n' + ' 2: soroban_env_host::host::metered_clone::MeteredIterator::metered_collect\n' + ' 3: soroban_env_host::host::frame::<impl soroban_env_host::host::Host>::invoke_function\n' + ' 4: preflight::preflight::preflight_invoke_hf_op\n' + ' 5: preflight::preflight_invoke_hf_op::{{closure}}\n' + ' 6: core::ops::function::FnOnce::call_once{{vtable.shim}}\n' + ' 7: preflight::catch_preflight_panic\n' + ' 8: _cgo_0b49d6ed4a0b_Cfunc_preflight_invoke_hf_op\n' + ' at tmp/go-build/cgo-gcc-prolog:103:11\n' + ' 9: runtime.asmcgocall\n' + ' at ./runtime/asm_amd64.s:848\n' + ' \n' + ' ' }

#

I tried to change i128 to u64 for min_quorum, but the same error happens. I don't really understand why it does it, since even when using same two types how is it that it has a problem to convert ScVal to host value?

kind halo
#

Seems strange for sure. Have you tried using the generated TS binding for your contract?

keen sundial
#

Just to share the solution here too: the error is the order of the values, Maps in soroban are ordered vector so the order of the values matter, once the order of the values are correct it will work

#
import * as SorobanClient from 'soroban-client';

const run = async (): Promise<void> => {
  const server = new SorobanClient.Server(
    'https://rpc-futurenet.stellar.org:443',
  );

  const proposal = SorobanClient.xdr.ScVal.scvMap([
    new SorobanClient.xdr.ScMapEntry({
      key: SorobanClient.xdr.ScVal.scvSymbol('end_time'),
      val: SorobanClient.nativeToScVal(52, { type: 'u64' }),
    }),
    new SorobanClient.xdr.ScMapEntry({
      key: SorobanClient.xdr.ScVal.scvSymbol('min_quo'),
      val: SorobanClient.nativeToScVal(52, { type: 'u64' }),
    }),
    new SorobanClient.xdr.ScMapEntry({
      key: SorobanClient.xdr.ScVal.scvSymbol('url'),
      val: SorobanClient.nativeToScVal('https://testdomain.com'),
    }),
  ]);

  const account = await server.getAccount(
    'GCMZIXQ5VKJKS4UANE6NJTLOSDRUF7ZABDBYD67I7KIKOSNEGD2KSDYJ',
  );
  const contract = new SorobanClient.Contract(
    'CALZI243S25GAEIGBNVU433VL4TCCXCBIY5AC33KS65DNEG7U3QWGKFD',
  );

  const transaction_object = new SorobanClient.TransactionBuilder(account, {
    fee: '100000',
    networkPassphrase: SorobanClient.Networks.FUTURENET,
  })
    .addOperation(
      contract.call(
        'create_proposal',
        new SorobanClient.Address(account.accountId()).toScVal(),
        proposal,
      ),
    )
    .setTimeout(30)
    .build();

  transaction_object.sign(
    SorobanClient.Keypair.fromSecret(
      'SCE6OIVWK2O3CEGQM6QZFH7FCAGHIHPBCGF7P43W72XJFTH2KWUV3H7N',
    ),
  );

  const prepared = await server.prepareTransaction(
    transaction_object,
    SorobanClient.Networks.FUTURENET,
  );

  prepared.sign(
    SorobanClient.Keypair.fromSecret(
      'SCE6OIVWK2O3CEGQM6QZFH7FCAGHIHPBCGF7P43W72XJFTH2KWUV3H7N',
    ),
  );

  const r = await server.sendTransaction(prepared);

  console.log(r);
};

run().catch(console.error);

In this example the futurenet contract is called successfully

kind halo
woven drift
#

Ok, that explains an error we were having too, sorry I missed #805. Q: Where can we find the correct order for params/maps? @keen sundial

keen sundial
woven drift
#

Ah, I think I see the issue now. When keys are Symbols, they need to be in .sort() order. And #805 deals with keys that are not Symbols and futzes up the sort

trim charm
#

Super late response, was in a midst of moving to another country.
Thanks a lot for the response. This works now.

I was not sure what you meant by ordered exactly. First I thought is refers to types, but then I realized you meant ordered alphabetically by keys, not value types.

@keen sundial please let me know if that is correct assessment or if I'm wrong in that.