Skip to content

Commit

Permalink
use dart for getBootstapper, remainingNewbieTicketsPerReputable a…
Browse files Browse the repository at this point in the history
…nd `remainingNewbieTicketsPerBootstrapper` (#1566)

* [substrate_api/encointer_api] use polkadart to get bootstrappers

* [substrate_api/encointer_api] use dart for getting the remaining newbie tickets per reputable.

* [substrate_api/encointer_api] get remaining bootstrapper newbie tickets in dart

* fmt

* [JS] remove obsolete get participant reputation

* fmt

* [ew_keyring] fix use polkadart_keyring from our fork.

* use dependency overrides in app to fix pub get
  • Loading branch information
clangenb authored Nov 21, 2023
1 parent 08942bb commit 8ee1f4c
Show file tree
Hide file tree
Showing 14 changed files with 150 additions and 184 deletions.
26 changes: 0 additions & 26 deletions app/js_service_encointer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,6 @@ JS in the webView.
In the [settings.js](src/service/settings.js) we initialize the window fields, e.g. `window.chain`, this will make the chain
module available as top-level entrypoint from dart. All the module functions exported in the `export default` section of the JS-file can be called from the dart side.

### Example getter
JS-part

```js

export async function getBootstrappers (cid) {
// all the types passed from dart to JS are just a json map.
// It is good practive to first create a type in with the
// input value.
const cidT = api.createType('CommunityIdentifier', cid);

// The polkadot-js/api automatically creates getters based on the encointer-node metadata, and make it queryable
// like: api.query.<module-name>.<storage-name>()
// This example queries a map because the storage is declared as such, thus the function takes one argument.
// See rust declaration: https://github.com/encointer/pallets/blob/3fc6c4fcef549d32e0ed7beb73ac940b43b25af3/communities/src/lib.rs#L395
return await api.query.encointerCommunities.bootstrappers(cidT);
}
```

Dart part
```dart
// parse the dynamic type into a List<String>
final bootstrappers =
await jsApi.evalJavascript('encointer.getBootstrappers($cid)').then((bs) => List<String>.from(bs as Iterable));
```

### Caveats
* Always double check how you are passing the values from dart to JS. As JS does simply parse strings, many things can go wrong.
* JS does not know types, but polkadot-js/api helps us with `api.createType` for complex types. Trying to transform a function arg into a type will uncover errors early.
Expand Down
53 changes: 0 additions & 53 deletions app/js_service_encointer/src/service/encointer.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,55 +138,6 @@ export async function subscribeBusinessRegistry (msgChannel, cid) {
}).then((unsub) => unsubscribe(unsub, msgChannel));
}

export async function getParticipantReputation (cid, cIndex, address) {
const cidT = api.createType('CommunityIdentifier', cid);
send('js-getParticipantReputation', `Getting participant reputation for Cid: ${communityIdentifierToString(cidT)}, cIndex: ${cIndex} and address: ${address}`);
const reputation = await api.query.encointerCeremonies.participantReputation([cid, cIndex], address);
send('js-getParticipantReputation', `Participant reputation: ${reputation}`);
return reputation;
}

export async function getBootstrappers (cid) {
const cidT = api.createType('CommunityIdentifier', cid);

return await api.query.encointerCommunities.bootstrappers(cidT);
}

export async function remainingNewbieTicketsReputable (cid, ceremonyIndex, address) {
const cidT = api.createType('CommunityIdentifier', cid);
window.send('js-remainingNewbieTickets-reputable', `cid: ${communityIdentifierToString(cidT)} ${address}`);
window.send('js-remainingNewbieTickets-reputable', `cIndex: ${ceremonyIndex}`);
window.send('js-remainingNewbieTickets-reputable', `address: ${address}`);

// Wrapping it in a promise all speeds up the process as we can await multiple futures at the same time.
const [burnedTickets, ticketsPerReputation] = await Promise.all([
api.query.encointerCeremonies.burnedReputableNewbieTickets([cid, ceremonyIndex], address),
api.query.encointerCeremonies.endorsementTicketsPerReputable(),
]).catch((e) => console.log(`js-remainingNewbieTickets-reputable error ${e}`));

window.send('js-remainingNewbieTickets-reputable', `ticketsPerReputation ${ticketsPerReputation}`);
window.send('js-remainingNewbieTickets-reputable', `burnedTickets ${burnedTickets}`);

return ticketsPerReputation - burnedTickets;
}

export async function remainingNewbieTicketsBootstrapper (cid, address) {
const cidT = api.createType('CommunityIdentifier', cid);
window.send('js-remainingNewbieTickets-bootstrapper', `cid: ${communityIdentifierToString(cidT)}`);
window.send('js-remainingNewbieTickets-bootstrapper', `address: ${address}`);

// Wrapping it in a promise all speeds up the process as we can await multiple futures at the same time.
const [burnedTickets, ticketsPerBootstrapper] = await Promise.all([
api.query.encointerCeremonies.burnedBootstrapperNewbieTickets(cid, address),
api.query.encointerCeremonies.endorsementTicketsPerBootstrapper(),
]).catch((e) => console.log(`js-remainingNewbieTickets-bootstrapper error ${e}`));

window.send('js-remainingNewbieTickets-bootstrapper', `ticketsPerBootstrapper ${ticketsPerBootstrapper}`);
window.send('js-remainingNewbieTickets-bootstrapper', `burnedTickets ${burnedTickets}`);

return ticketsPerBootstrapper- burnedTickets;
}

export async function getDemurrage (cid) {
const cidT = api.createType('CommunityIdentifier', cid);

Expand Down Expand Up @@ -357,8 +308,6 @@ export async function sendNextPhaseTx() {
}

export default {
getParticipantReputation,
getBootstrappers,
subscribeCurrentPhase,
subscribeBalance,
subscribeCommunityIdentifiers,
Expand All @@ -370,8 +319,6 @@ export default {
getBalance,
sendNextPhaseTx,
reapVoucher,
remainingNewbieTicketsReputable,
remainingNewbieTicketsBootstrapper,
getAllFaucetAccounts,
getFaucetFor,
getAllFaucetsWithAccount,
Expand Down
36 changes: 1 addition & 35 deletions app/js_service_encointer/test/service/encointer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import '../../src';
import encointer, {
getProofOfAttendance,
_getProofOfAttendance, reapVoucher, encointerTransfer, getBalance, hasPendingIssuance, remainingNewbieTicketsReputable
_getProofOfAttendance, reapVoucher, encointerTransfer, getBalance, hasPendingIssuance
} from '../../src/service/encointer';
import { cryptoWaitReady, signatureVerify } from '@polkadot/util-crypto';
import { localDevNetwork } from '../testUtils/networks';
Expand All @@ -23,26 +23,6 @@ describe('encointer', () => {
keyring = new Keyring({ type: 'sr25519' });
}, 90000);

describe('getParticipantReputation', () => {
it('should return promise', async () => {
await cryptoWaitReady();
const cid = communityIdentifierFromString(api.registry, 'gbsuv7YXq9G');
const attendee = keyring.addFromUri('//Bob', { name: 'Bob default' }).address;
const result = await encointer.getParticipantReputation(cid, 1, attendee);
expect(result.isUnverified).toBeTruthy();
});
});

describe('getParticipantReputation2', () => {
it('should return promise', async () => {
await cryptoWaitReady();
const cid = communityIdentifierFromString(api.registry, 'gbsuv7YXq9G');
// const attendee = keyring.addFromUri('//Bob', { name: 'Bob default' }).address;
const result = await encointer.getParticipantReputation(cid, 3, '0xf4577adda8c5bda374fb86d42aed35eb171a949c7b52202806cd137795d5567a');
expect(result.isUnverified).toBeTruthy();
});
});

describe('getProofOfAttendance', () => {
it('should be defined', () => {
expect(encointer.getProofOfAttendance).toBeDefined();
Expand Down Expand Up @@ -127,20 +107,6 @@ describe('encointer', () => {
});
});

// Note: this needs the bootstrapping script, but we have this in the CI now.
describe('remainingReputableNewbieTickets', () => {
it('returns tickets per reputation after bootstrapping ceremony', async () => {
const alice = keyring.addFromUri('//Alice', { name: 'Alice default' });
const cid = communityIdentifierFromString(api.registry, "sqm1v79dF6b");

const ticketsPerReputation = await api.query.encointerCeremonies.endorsementTicketsPerReputable();

expect(
await remainingNewbieTicketsReputable(cid, 2, alice.publicKey)
).toBe(ticketsPerReputation.toNumber());
});
});

// Note: this needs the bootstrapping script, but we have this in the CI now.
describe('reap voucher', () => {
it('removes all the balance from voucher', async () => {
Expand Down
69 changes: 36 additions & 33 deletions app/lib/service/substrate_api/encointer/encointer_api.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'dart:convert';
import 'dart:math';

import 'package:convert/convert.dart' show hex;

import 'package:encointer_wallet/config/consts.dart';
import 'package:encointer_wallet/mocks/mock_bazaar_data.dart';
Expand Down Expand Up @@ -30,6 +33,7 @@ import 'package:ew_substrate_fixed/substrate_fixed.dart';
// disambiguate global imports of encointer types. We can remove this
// once we got rid of our manual type definitions.
import 'package:ew_polkadart/encointer_types.dart' as et;
import 'package:flutter/foundation.dart';

/// Api to interface with the `js_encointer_service.js`
///
Expand Down Expand Up @@ -426,15 +430,13 @@ class EncointerApi {

if (cid == null) return;

// Todo: Use polkadart base codec for List<int> -> String
// final bootstrappersBytes = await _encointerKusama.query.encointerCommunities.bootstrappers(et.CommunityIdentifier(
// geohash: cid.geohash,
// digest: cid.digest,
// ));
final bootstrappersBytes = await encointerKusama.query.encointerCommunities.bootstrappers(et.CommunityIdentifier(
geohash: cid.geohash,
digest: cid.digest,
));

final bootstrappers = await jsApi
.evalJavascript<List<dynamic>>('encointer.getBootstrappers($cid)')
.then((list) => list.cast<String>());
final bootstrappers =
bootstrappersBytes.map((p) => AddressUtils.pubKeyToAddress(p, prefix: store.settings.endpoint.ss58!)).toList();

Log.d('api: bootstrappers $bootstrappers', 'EncointerApi');
if (store.encointer.community != null) {
Expand Down Expand Up @@ -479,22 +481,20 @@ class EncointerApi {
final cid = store.encointer.chosenCid;
final cIndex = store.encointer.currentCeremonyIndex;

if (cid == null) return 0;
if (cIndex == null) return 0;
if (reputations.isEmpty) return 0;

try {
// Todo: fix addressStr -> List<int>
// final [burned, ticketsPerReputable] = await Future.wait([
// _encointerKusama.query.encointerCeremonies
// .burnedReputableNewbieTickets([et.CommunityIdentifier(geohash: cid.geohash, digest: cid.digest), cIndex], address),
// _encointerKusama.query.encointerCeremonies.endorsementTicketsPerReputable()
// ]);
// return ticketsPerReputable - burned;

final remainingTickets = await jsApi.evalJavascript<int>(
'encointer.remainingNewbieTicketsReputable(${jsonEncode(cid)}, "$cIndex","$address")',
);
Log.d('EncointerApi', 'numberOfNewbieTickets: $remainingTickets');
return remainingTickets;
final [burned, ticketsPerReputable] = await Future.wait([
encointerKusama.query.encointerCeremonies.burnedReputableNewbieTickets(
Tuple2(et.CommunityIdentifier(geohash: cid.geohash, digest: cid.digest), cIndex),
AddressUtils.addressToPubKey(address).toList(),
),
encointerKusama.query.encointerCeremonies.endorsementTicketsPerReputable()
]);
Log.p('NewbieTickets: ticketPerReputable: $ticketsPerReputable, burned: $burned');
return ticketsPerReputable - burned;
} catch (e, s) {
Log.e('EncointerApi', '$e', s);
}
Expand All @@ -508,19 +508,22 @@ class EncointerApi {
if (cid == null) return 0;

try {
// Todo: fix addressStr -> List<int>
// final [burned, ticketsPerBootstrapper] = await Future.wait([
// _encointerKusama.query.encointerCeremonies
// .burnedBootstrapperNewbieTickets(et.CommunityIdentifier(geohash: cid.geohash, digest: cid.digest), address),
// _encointerKusama.query.encointerCeremonies.endorsementTicketsPerBootstrapper()
// ]);
// return ticketsPerBootstrapper - burned;

final numberOfTickets = await jsApi.evalJavascript<int>(
'encointer.remainingNewbieTicketsBootstrapper(${jsonEncode(cid)},"$address")',
final burned = await encointerKusama.query.encointerCeremonies.burnedBootstrapperNewbieTickets(
et.CommunityIdentifier(geohash: cid.geohash, digest: cid.digest),
AddressUtils.addressToPubKey(address).toList(),
);
Log.d('Encointer Api', 'numberOfBootstrapperTickets: $numberOfTickets');
return numberOfTickets;

// Nasty hack because of https://github.com/leonardocustodio/polkadart/issues/373
final ticketsPerBootstrapperKey =
Uint8List.fromList(hex.decode('a7d291a8132b2cc65c41da45f4de76795c03954ec993845da1c7ff36c91390da'));
final ticketsPerBootstrapperBytes = await encointerKusama.rpc.state.getStorage(ticketsPerBootstrapperKey);
final ticketsPerBootstrapper =
ticketsPerBootstrapperBytes != null ? U8Codec.codec.decode(ByteInput(ticketsPerBootstrapperBytes)) : 0;

Log.p('NewbieTickets: ticketsPerBootstrapper: $ticketsPerBootstrapper, burned: $burned');

// could be negative in case the `ticketsPerBootstrapper` has been decreased over time.
return max(ticketsPerBootstrapper - burned, 0);
} catch (e, s) {
Log.e('Encointer Api', '$e', s);
}
Expand Down
37 changes: 20 additions & 17 deletions app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1290,29 +1290,31 @@ packages:
source: hosted
version: "3.7.3"
polkadart:
dependency: transitive
dependency: "direct overridden"
description:
path: "packages/polkadart"
ref: main
resolved-ref: "8b9122d01d6aab515e2279f68697161c32df1f0f"
resolved-ref: "0295b130ae5f6542d58f3f8e1945f3042591139f"
url: "https://github.com/encointer/polkadart"
source: git
version: "0.2.2"
version: "0.2.3"
polkadart_keyring:
dependency: transitive
description:
name: polkadart_keyring
sha256: ba568c22f3ff2a77c35fe0d53845212c1a433f99645e286550d1889dbb437d3c
url: "https://pub.dev"
source: hosted
path: "packages/polkadart_keyring"
ref: main
resolved-ref: "0295b130ae5f6542d58f3f8e1945f3042591139f"
url: "https://github.com/encointer/polkadart"
source: git
version: "0.2.1"
polkadart_scale_codec:
dependency: transitive
dependency: "direct overridden"
description:
name: polkadart_scale_codec
sha256: "75289b2f53c6cf997dd68945d959fee596c1e47bba3dedba22a6e95646df893c"
url: "https://pub.dev"
source: hosted
path: "packages/polkadart_scale_codec"
ref: main
resolved-ref: "0295b130ae5f6542d58f3f8e1945f3042591139f"
url: "https://github.com/encointer/polkadart"
source: git
version: "1.1.2"
polylabel:
dependency: transitive
Expand Down Expand Up @@ -1680,12 +1682,13 @@ packages:
source: hosted
version: "0.2.0"
substrate_metadata:
dependency: transitive
dependency: "direct overridden"
description:
name: substrate_metadata
sha256: "48c96aed0ef8f38dd99e80e592c7774c30fc13a80d62a5f777b56b22801c3fa0"
url: "https://pub.dev"
source: hosted
path: "packages/substrate_metadata"
ref: main
resolved-ref: "0295b130ae5f6542d58f3f8e1945f3042591139f"
url: "https://github.com/encointer/polkadart"
source: git
version: "1.1.2"
sync_http:
dependency: transitive
Expand Down
22 changes: 22 additions & 0 deletions app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,28 @@ dev_dependencies:
very_good_analysis: ^5.1.0
rxdart: ^0.27.7

dependency_overrides:
polkadart:
# path: ../../../polkadart/packages/polkadart
git:
url: https://github.com/encointer/polkadart
ref: main
path: packages/polkadart

polkadart_scale_codec:
# path: ../../../polkadart/packages/polkadart_scale_codec
git:
url: https://github.com/encointer/polkadart
ref: main
path: packages/polkadart_scale_codec

substrate_metadata:
# path: ../../../polkadart/packages/substrate_metadata
git:
url: https://github.com/encointer/polkadart
ref: main
path: packages/substrate_metadata

flutter_icons:
android: "launcher_icon"
ios: true
Expand Down
17 changes: 16 additions & 1 deletion app/pubspec_overrides.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# melos_managed_dependency_overrides: ew_http,ew_storage,ew_polkadart,ew_substrate_fixed,ew_keyring
# melos_managed_dependency_overrides: ew_http,ew_storage,ew_polkadart,ew_substrate_fixed,ew_keyring,polkadart,polkadart_scale_codec,substrate_metadata
dependency_overrides:
ew_http:
path: ../packages/ew_http
Expand All @@ -12,3 +12,18 @@ dependency_overrides:
path: ../packages/ew_substrate_fixed
ew_test_keys:
path: ../packages/ew_test_keys
polkadart:
git:
url: https://github.com/encointer/polkadart
ref: main
path: packages/polkadart
polkadart_scale_codec:
git:
url: https://github.com/encointer/polkadart
ref: main
path: packages/polkadart_scale_codec
substrate_metadata:
git:
url: https://github.com/encointer/polkadart
ref: main
path: packages/substrate_metadata
Loading

0 comments on commit 8ee1f4c

Please sign in to comment.