polkadot-js / api

Promise and RxJS APIs around Polkadot and Substrate based chains via RPC calls. It is dynamically generated based on what the Substrate runtime provides in terms of metadata.
Apache License 2.0
1.07k stars 350 forks source link

Can't create 'MultiSignature' type in addSignature #2258

Closed hanwencheng closed 4 years ago

hanwencheng commented 4 years ago

Use the following code to inject signature:

    const signature = registry.createType('Sr25519Signature', signatureRaw);
        //signature is a length 64 u8 array
    unsignedTx.addSignature(signer, signature, u8aPayload);

ends with the error

error is Error: createType(MultiSignature):: Unable to create Enum via index 82, in Ed25519, Sr25519, Ecdsa

which caused by the createType function here, I guess the Enum type 'MultiSignature' cannot be direct created.

jacogr commented 4 years ago

64-bytes is not a valid MultiSignature. That is 65 bytes in length -

hanwencheng commented 4 years ago

I use Keyring for testing with a prefixed bytes, but it turns out to be a bad proof.

e,.g

//This function get the 65 bytes signature with first byte as indicator
function prefixSignature (signatureRaw: ArrayLike<number>): Uint8Array {
    const u8aSignature = Uint8Array.from(signatureRaw);
    const u8aHeader = new Uint8Array([1]);
    const signature = new Uint8Array(65);
    signature.set(u8aHeader);
    signature.set(u8aSignature, 1);
    return signature;
}

const suri = 'ability cave solid soccer gloom thought response hard around minor want welcome//kusama';
const keyring = new Keyring({ss58Format: 42, type: 'sr25519'});
const signer:KeyringPair = keyring.addFromUri(suri, undefined, 'sr25519');
console.assert(senderAddress === signer.address, 'address should be the same ');

const payload:SignerPayload = registry.createType('SignerPayload', payloadRaw, { version: payloadRaw.version });
const signatureRaw = signer.sign(hexToU8a(payload.toRaw().data));

//if prefix the u8a then it is a bad proof after sending
const isBadproof = signer.verify(hexToU8a(payload.toRaw().data), prefixSignature(signatureRaw));

//if not prefixed then can't add signature
unsignedTx.addSignature(senderAddress, signatureRaw, payload.toPayload());

unsignedTx.send();

And the Signing with Keypair here is aligned with test code in SingleAccountSigner as well as the add signature process in signViaSigner.

So I am not sure what is the correct way to add the prefix.

jacogr commented 4 years ago

If you sign via the keyring, pass the withType: true option and it generates a MultiSignature.

jacogr commented 4 years ago

Here is an example of that - https://github.com/polkadot-js/api/blob/master/packages/types/src/extrinsic/v4/ExtrinsicPayload.ts#L87

(So you can also just skip creating a signer payload, pass the data as received into creating an ExtrinsicPayload and call sign on it - like here where it gets a SignerPayload and signs it just using the exposed helper on ExtrinsicPayload, https://github.com/polkadot-js/extension/blob/master/packages/extension-base/src/background/RequestExtrinsicSign.ts#L18)

polkadot-js-bot commented 3 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue if you think you have a related problem or query.