Migrate identity (identity.changeOwnerKey())

arf désolé tu as répondu pendant que j’éditais mpon message avec exactement ce correctif, mais l’erreur persiste…


J’espère que le soucis ne viens pas de ma fonction de signature qui est un peu tricky à cause du binding JS:

Future<String> signMessage(
      Uint8List message, String address, String password) async {
    final params = SignAsExtensionParam();
    params.msgType = "pub(bytes.sign)";
    params.request = {
      "address": address,
      "data": message,
    };

    final res = await sdk.api.keyring.signAsExtension(password, params);
    return res?.signature ?? '';
  }

J’ai pu vérifier que cela fonctionne très bien pour des messages de type String grâce à l’ui polakdot.js, mais depuis que j’ai changé pour des messages de type Uint8List, je ne sais pas si l’api derrière le traite comme une string ou pas, c’est le soucis des type dynamic induis par le binding JS…

Du coup lorsque je vérifie la signature du message Uint8List depuis l’ui polkadot.js, il me dit que ce n’est pas bon mais je ne sais pas si c’est dû au fait que l’ui n’attends que des messages de type String.

1 Like

Dans ta dernière version du message, le préfixe et IdtyIndex sont enfin corrects, par contre le genesis hash ne correspond pas à celui de la gdev, si tu teste sur une blockchain locale peut tu indiquer le genesis hash hexa fourni par polkadot js dans settings → metadata ?

Aussi, je ne sais pas quel est censé être l’ancienne clé, peut tu fournir une représentation ss58 ou hexa de l’ancienne clé ? Il me faut ces éléments pour essayer de générer le message de mon côté et voir quelles sont les diff :slight_smile:

Voilà plus de détail:

fromAddress: 5GAT6CJW8yVKwUuQc7sM5Kk9GZVTpbZYk9PfjNXtvnNgAJZ1
fromPubkey: DCovzCEnQm9GUWe6mr8u42JR1JAuoj3HbQUGdCkfTzSr
destAddress: 5D2HHRj6zCEL9iY3CBpKy1mBMtpXUJCFDNvevBqVQAWdzqSS
genesisHashString: 0x07c112ff6ab9d7d0d531ebe59f98b35318b2813b1655577380819d38d6182d99

prefix: [105, 99, 111, 107]
genesisHash: [7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153]
idtyIndex: [21, 0, 0, 0]
oldPubkey: [181, 82, 178, 99, 198, 4, 156, 190, 78, 35, 102, 137, 255, 7, 162, 31, 16, 79, 255, 132, 130, 237, 230, 222, 176, 88, 245, 217, 237, 78, 196, 239]

messageToSign: [105, 99, 111, 107, 48, 55, 99, 49, 49, 50, 102, 102, 54, 97, 98, 57, 100, 55, 100, 48, 100, 53, 51, 49, 101, 98, 101, 53, 57, 102, 57, 56, 98, 51, 53, 51, 49, 56, 98, 50, 56, 49, 51, 98, 49, 54, 53, 53, 53, 55, 55, 51, 56, 48, 56, 49, 57, 100, 51, 56, 100, 54, 49, 56, 50, 100, 57, 57, 21, 0, 0, 0, 181, 82, 178, 99, 198, 4, 156, 190, 78, 35, 102, 137, 255, 7, 162, 31, 16, 79, 255, 132, 130, 237, 230, 222, 176, 88, 245, 217, 237, 78, 196, 239]
newKeySig: 0x42a6ba600f7ddac10dbd3a6ff1dc6f7c5c1afa6e0855cbf56b0e2e4c6908681f926414ae6268768daee93a4f7a818ff5611daba6e6c7f2dbf34ee9de5395598d

Je suis sur la GDev, pas en local.
Je viens de remarquer que je ne transformais pas correctement l’hexa du genesisHash en binary, j’ai donc indiqué ce qui me semble être la bonne valeur de genesisHash (mais le problème persiste…)

fromPubkey est l’ancienne pubkey en base58 correspondant à l’ancienne adresse ss58 fromAddress
oldPubkey est fromPubkey en binary.

Je récupère le genesisHash avec le call api.genesisHash.toHex() comme indiqué dans la doc polkadot.js, et je constate que c’est le même hash que via les metadata de polkadot.js UI.

Oui mais ensuite il faut convertir l’hexadécimal en binaire, ce qui donne ceci pour le genesis hash de la ĞDev:
EDIT: C’est le format binaire qu’on veut ici, donc toHex() ne sert à rien, utilise directement api.genesisHash.toU8a().

Ce qui doit te donner ça:

[128, 7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153]

J’ai généré moi-même le message à partir de tes données, et voici le message que j’obtiens:

[105, 99, 111, 107, 128, 7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153, 21, 0, 0, 0, 0, 0, 0, 0, 181, 82, 178, 99, 198, 4, 156, 190, 78, 35, 102, 137, 255, 7, 162, 31, 16, 79, 255, 132, 130, 237, 230, 222, 176, 88, 245, 217, 237, 78, 196, 239]

Seul le genesis hash diffère, le reste est bien identique à ton message.

1 Like

C’est ce que je voulais faire au début, mais pour une raison que j’ignore, lorsque j’essaie de juste récupérer cette valeur U8a depuis le binding javascript, Dart lève une erreur FormatException (FormatException: Unexpected end of input (at character 1), alors que je veux juste retourner la valeur de api.genesisHash.toU8a() via une sortie dynamic. Le problème ne se pose pas en hexa, donc je passe en hexa car plus simple pour traverser les contraintes du binding.

Je ne comprends pas d’où sort ce 128 au début de cette chaine, c’est la seule différence avec ma sortie, mais j’ai beau retourner dans tous les sens, je n’ai jamais ce byte en début de chaine…

J’enlève évidement le 0x de début de string hexa sans quoi la conversion est impossible (comme partout ailleurs pour mes transformation hexa en dart).

Je continue de creuser mais je ne comprends pas.


Par désespoir je me suis rabattu sur python pour comparer, et j’ai bien la même chose qu’en dart, je ne sais pas d’où vient ton byte 128:

hex_string = "07c112ff6ab9d7d0d531ebe59f98b35318b2813b1655577380819d38d6182d99"
tata = bytearray.fromhex(hex_string)
print(list(tata))

[7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153]

Moi non plus, c’est le code rust que j’ai écrit à l’arrache en 5 min pour générer le message qui contenait une erreur :sweat_smile:

Voici le message corrigé:

[105, 99, 111, 107, 7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153, 21, 0, 0, 0, 0, 0, 0, 0, 181, 82, 178, 99, 198, 4, 156, 190, 78, 35, 102, 137, 255, 7, 162, 31, 16, 79, 255, 132, 130, 237, 230, 222, 176, 88, 245, 217, 237, 78, 196, 239]

À tu bien exactement ce message ? Peut tu coller en réponse la dernière version de ton message ?

Oui:

[105, 99, 111, 107, 7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153, 21, 0, 0, 0, 181, 82, 178, 99, 198, 4, 156, 190, 78, 35, 102, 137, 255, 7, 162, 31, 16, 79, 255, 132, 130, 237, 230, 222, 176, 88, 245, 217, 237, 78, 196, 239]

La différence:
Chez moi idtyIndex = [21, 0, 0, 0]
Chez toi = [21, 0, 0, 0, 0, 0, 0, 0]

Ca me semble être la seule différence.

Et c’est ta version qui est la bonne, j’ai encore corrigé mon code, et copié/collé la dernière version de ton message dans un assert_eq, j’ai bien exactement le même message maintenant :slight_smile:

Donc ça devrait fonctionner, si tu as toujours la même erreur, c’est que tu ne génères pas la signature correctement.

1 Like

bonbonbon j’y suis presque, on avance!

Y a il un moyen pour moi de vérifier la signature via polkadot js ?

Cela fonctionne pour un message de type String signé par mon code, mais pas pour un Uint8List.
Est-ce que c’est censé fonctionner pour un Uint8List graphiquement ici ?

Non, polkadot js ne peut vérifier que les signatures émises via la lib polkadot/api, car ça ajoute des wrapping bytes, je suis d’ailleurs persuadé que c’est la cause de ton problème.

Pour ne pas avoir les wraping bytes, il te faut descendre plus bas niveau en js, et utiliser directement la fonction sr25519Sign du paquet npm @polkadot/util-crypto.

Pour vérifier, tu peux check la signature avec un bout de code python, je peux aussi le faire avec un bout de code rust, si tu me fournis pubkey et sig.

1 Like

Je vais tenter une question bête, mais ne serait-il pas possible de changer côté duniter la vérification de la signature du message en hexa plutôt que Uint8Array pour cet extrinsic ?

En hexa ce même message donne

0x69636f6b07c112ff6ab9d7d0d531ebe59f98b35318b2813b1655577380819d38d6182d9915000000b552b263c6049cbe4e236689ff07a21f104fff8482ede6deb058f5d9ed4ec4ef

Non pas possible, le runtime wasm doit être léger et rapide, il contient les SCALE codec nais c’est tout, il ne contient rien pour gérer ou parser les chaînes de caractères, et ne le peut pas, car c’est du no_std.

En plus ça ne résoudrait en rien ton problème, puisque c’est un souci de signature, pas de génération du message.

Faut pas te décourager @poka, tu as déjà énormément avancé, c’est normal que tu galères surtout que tu dois composer avec une couche javascript que tu ne maîtrises pas bien.

Fais une pause :slight_smile:

3 Likes

Après quelques précieuses indications d’elois et une bonne nuit de sommeil, j’ai pu mettre à jours mon fork de polkawallet_sdk pour permettre la signature unwrap du message Uint8List:

Et cela a fonctionné ! L’identité zombie (initialement sur l’adresse corresponsant à Cesium(test,test)) a été migré vers mon adresse 5D2HHRj6zCEL9iY3CBpKy1mBMtpXUJCFDNvevBqVQAWdzqSS (dérivation de mon coffre gecko) !! :slight_smile:

Par contre l’indexer de @cgeek n’a pas compris ce qu’il s’est passé lol, c’est normal ce cas d’usage n’était pas encore prévue.

4 Likes

@ManUtopiK @cgeek , il faut que l’indexeur écoute l’event Identity.IdtyChangedOwnerKey, cet event contient 2 paramètres: le IdtyIndex et la nouvelle adresse.

Je vous ai créé une issue:

https://git.duniter.org/manutopik/duniter-indexer/-/issues/12

4 Likes

Tiens, en regardant ton code qui fait le unwrap() je vois que juste avant tu fais :

if (!keyPair.isLocked) {
        keyPair.lock();
      }

Pourquoi as tu besoin de Locker, juste avant le sign() ?
C’est plutôt le contraire ?

Ce n’est pas mon code, c’est le package polkawallet_sdk, je n’ai fait que changer wrap to unwrap pour régler le problème de signature que j’avais.

Je ne sais pas à quoi correspond keyPair.lock(), je ne m’en sert nul part dans mon code.
C’est une interface JS, je n’ai pas été voir à quoi ça correspond. Je suis d’accords que c’est étrange de voir lock et non unlock ici, mais bon ça fonctionne j’en demande pas plus pour cette partie pour le moment ^^

Je n’arrive plus à migrer d’identité sur le nouveau runtime 700. Je test uniquement sur mon noeud de dev local, car tester la gdev aujourd’hui à m’a permis de me rendre compte que je n’étais plus membre de la Ğ1 au moment du lancement pour non renouvellement de mon adhésion …

Voici l’erreur que j’obtiens:

Uncaught Error: createType(Call):: Call: failed decoding identity.changeOwnerKey:: Struct: failed on args: {"new_key":"AccountId32","new_key_sig":"{\"_enum\":{\"Ed25519\":\"SpCoreEd25519Signature\",\"Sr25519\":\"SpCoreSr25519Signature\",\"Ecdsa\":\"SpCoreEcdsaSignature\"}}"}:: Struct: failed on new_key_sig: {"_enum":{"Ed25519":"SpCoreEd25519Signature","Sr25519":"SpCoreSr25519Signature","Ecdsa":"SpCoreEcdsaSignature"}}:: Unable to create Enum via index 212, in Ed25519, Sr25519, Ecdsa

Est-ce que vous pouvez me confirmer qu’il s’agit bien d’une erreur de signature (new_key_sig) invalide ?
Si c’est le cas, le message d’erreur a été modifié depuis la dernière fois (et tant mieux).

Vous n’avez pas changer quoi que ce soit à ce niveau ? Toujours le même préfix icok par exemple (je n’ai pas encore été vérifier dans le code) ?

Arrivez-vous à effectuer une migration d’identité avec d’autres clients avec d’autres clients que Gecko ? Ou arrivez-vous à le faire avec Gecko sur la gdev (ou terminez-vous en timeout) ?


edit: Je viens de tester sur l’image du runtime 300 (debug-sha-4d5e08be), et je confirme que la migration d’identité fonctionne avec gecko sur ce runtime, il a donc eu un changement depuis côté Duniter.

1 Like

Oui, j’ai changé le nom de la struct “payload”, mais ça devrait pas avoir changé le message à soumettre :thinking:

Il faut que j’implémente la migration d’identité dans Ğcli, je vais essayer de le faire vite avant de devenir forgeron et je te dis ce que je vois.

2 Likes

Pour info, en python, on passe de ça :

params = {"new_key": new_keypair.ss58_address, "new_key_sig": signature_bytes}

à ça :

# newKey: AccountId32, newKeySig: SpRuntimeMultiSignature
params = {"new_key": new_keypair.ss58_address, "new_key_sig": {"Sr25519": signature_bytes}}
2 Likes

Ah zut, j’avais oublié de tenir au courant. Je l’ai bien implémenté dans Ğcli en permettant aussi les clés ed25519 générées “méthode Cesium” (c’est comme ça que j’ai fait pour migrer mon identité forgeron) et ça ressemble à ça :

/// change owner key
pub async fn change_owner_key(
	data: &Data,
	address: AccountId,
	keypair: KeyPair,
) -> Result<(), subxt::Error> {
	let (_payload, signature) = generate_chok_payload(data, address.clone(), keypair);

	// this is a hack, see
	// https://substrate.stackexchange.com/questions/10309/how-to-use-core-crypto-types-instead-of-runtime-types
	let signature = match signature {
		Signature::Sr25519(signature) => MultiSignature::Sr25519(
			runtime::runtime_types::sp_core::sr25519::Signature(signature.0),
		),
		Signature::Nacl(signature) => MultiSignature::Ed25519(
			runtime::runtime_types::sp_core::ed25519::Signature(signature.try_into().unwrap()),
		),
	};

	submit_call_and_look_event::<
		runtime::identity::events::IdtyChangedOwnerKey,
		Payload<runtime::identity::calls::types::ChangeOwnerKey>,
	>(
		data,
		&runtime::tx()
			.identity()
			.change_owner_key(address, signature),
	)
	.await
}

Merci @vit pour le ping ^^