Versions de WotWizard

Une version majeure de WotWizard utilisant graphQL va bientôt être publiée. En attendant, voici déjà le schéma graphQL du serveur (commentaires souhaités):

# WotWizard GraphQL TypeSystem

type Query {
	
	"'identities' lists all identities whose status is 'status' and whose uids is between 'start' (included) and 'end' (excluded), in increasing order and sorted by 'sortedBy'; if 'start' is absent or null, the list starts at the beginning, and stops at the end if 'end' is absent or null"
	identities (status: Identity_Status! = MEMBER, sortedBy: Identity_Order, start: String, end: String): [Identity!]!
	
	"idSearch displays the list of identities whose pseudos or public keys begin with 'with.hint' and whose status is in 'with.status_list'."
	idSearch (with: IdSearchInput): IdSearchOutput!
	
	"Threshold for numbers of sent and received certifications to become sentry"
	sentryTreshold: Int!
	
	"List of sentries, sorted by increasing uids"
	sentries: [Identity!]!
	
	"Present block"
	now: Block!

	"wotWizardListFile displays the WotWizard file"
	wwFile: File!
	
	"wwResult displays the content of the WotWizard window"
	wwResult: WWResult!
	
	"'memEnds' displays the list of members who are about to loose their memberships, in the order of event dates (bct); 'startFromNow' gives the period before the beginning of the list (0 if absent or null) , and 'period' gives the period covered by the list (infinite if absent or null)"
	memEnds (startFromNow: Int64, period: Int64): [Identity!]!
	
	"'missEnds' displays the list of identities who are MISSING and about to be revoked, in the order of event dates (bct); 'startFromNow' gives the period before the beginning of the list (0 if absent or null) , and 'period' gives the period covered by the list (infinite if absent or null)"
	missEnds (startFromNow: Int64, period: Int64): [Identity!]!
	
	"'certEnds' displays the list of identities who are MEMBER or (possibly) MISSING and about to loose their 'ParameterName.sigQty'th oldest certification, in the order of event dates (bct); 'startFromNow' gives the period before the beginning of the list (0 if absent or null) , and 'period' gives the period covered by the list (infinite if absent or null)"
	certEnds (startFromNow: Int64, period: Int64, missingIncluded: Boolean = true): [Identity!]!
	
	"membersCount displays the number of active members, sorted by dates (utc0) of events (in or out the wot)"
	membersCount (start: Int64, end: Int64): [Event!]!
	
	"membersFlux displays the flux of active members by <timeUnit (s)>"
	membersFlux (start: Int64, end: Int64, timeUnit: Int64 = 2629800): [FluxEvent!]!
	
	"membersFluxPM displays the flux of active members by <timeUnit (s)> and by member"
	membersFluxPM (start: Int64, end: Int64, timeUnit: Int64 = 2629800): [FluxEvent!]!
	
	"fECount displays the number of first entries into the wot, sorted by dates (utc0) of events (entries)"
	fECount (start: Int64, end: Int64): [Event!]!
	
	"fEFlux displays the flux of first entries by <timeUnit (s)>"
	fEFlux (start: Int64, end: Int64, timeUnit: Int64 = 2629800): [FluxEvent!]!
	
	"fEFluxPM displays the flux of first entries by <timeUnit (s)> and by member"
	fEFluxPM (start: Int64, end: Int64, timeUnit: Int64 = 2629800): [FluxEvent!]!
	
	"lossCount displays the number of members exiting the wot, minus the number of reentries (losses), sorted by dates (utc0) of events (in or out the wot)"
	lossCount (start: Int64, end: Int64): [Event!]!
	
	"lossFlux displays the flux of losses by <timeUnit (s)>"
	lossFlux (start: Int64, end: Int64, timeUnit: Int64 = 2629800): [FluxEvent!]!
	
	"lossFluxPM displays the flux of losses by <timeUnit (s)> and by member"
	lossFluxPM (start: Int64, end: Int64, timeUnit: Int64 = 2629800): [FluxEvent!]!
	
	"'allParameters' displays all parameters of the money"
	allParameters: [Parameter!]!
	
	"'parameter' displays the parameter of the money whose name is 'name''"
	parameter (name: ParameterName): Parameter

} #Query

type Mutation {
	
	"'nowStop' erases the subscription for 'Subscription.nowStart'; do nothing if the subscription is not already installed"
	nowStop: Void
	
	"'wwServerStop' erases the subscription for 'Subscription.wwServerStart'; do nothing if the subscription is not already installed"
	wwServerStop: Void
	
	"'memEndsStop' erases the subscription for 'Subscription.memEndsStart'; do nothing if the subscription is not already installed"
	memEndsStop: Void
	
	"'missEndsStop' erases the subscription for 'Subscription.missEndsStart'; do nothing if the subscription is not already installed"
	missEndsStop: Void
	
	"'certEndsStop' erases the subscription for 'Subscription.certEndsStart'; do nothing if the subscription is not already installed"
	certEndsStop: Void
	
	"changeDifferParams modifies two parameters of the differentiation process used in 'Query.membersFlux', 'Query.membersFluxPM', 'Query.fEFlux', 'Query.fEFluxPM', 'Query.lossFlux' and 'Query.lossFluxPM': 'pointsNb', the number of points over which the filter (Savitzky–Golay filter) is calculated, and 'degree',  the degree of the used polynomial (usually 2 or 4); do not change a parameter if absent or null. It returns the previous values of these two parameters."
	changeDifferParams (pointsNb: Int, degree: Int): DifferParams!

} #Mutation

type Subscription {
	
	"'nowStart' installs or modifies a subscription for the update of 'Query.now' at every new block"
	nowStart: Block!
	
	"'wwServerStart' installs or modifies a subscription for the update of 'Query.wwResult' at every new block"
	wwServerStart: WWResult!
	
	"'memEndsStart' installs or modifies a subscription for the update of 'Query.memEnds' at every new block"
	memEndsStart (startFromNow: Int64, period: Int64): [Identity!]!
	
	"'missEndsStart' installs or modifies a subscription for the update of 'Query.missEnds' at every new block"
	missEndsStart (startFromNow: Int64, period: Int64): [Identity!]!
	
	"'certEndsStart' installs or modifies a subscription for the update of 'Query.certEnds' at every new block"
	certEndsStart (startFromNow: Int64, period: Int64, missingIncluded: Boolean = true): [Identity!]!

} #Subscription

"Differentiation filter parameters"
type DifferParams {

	"Number of points used by the filter"
	pointsNb: Int!
	
	"Degree of polynomial used by the filter"
	degree: Int!
	
} #DifferParams

"WoT identity"
type Identity {
	
	"Public key"
	pubkey: Pubkey!
	
	"Pseudo"
	uid: String!
	
	"Hash"
	hash: Hash!
	
	"Status: REVOKED, MISSING, MEMBER or NEWCOMER"
	status: Identity_Status!
	
	"Identity waiting for new membership (MISSING, MEMBER or NEWCOMER; false for REVOKED)"
	membership_pending: Boolean!
	
	"Block of new membership application; null if not membership_pending"
	membership_pending_block: Block
	
	"Limit date of new membership application; null if not membership_pending"
	membership_pending_limitDate: Int64
	
	"Block where the identity is written (entry into the web of trust)"
	id_written_block: Block
	
	"Block of last membership application (joiners, actives, leavers), null for NEWCOMER"
	lastApplication: Block
	
	"Limit date of the membership application; null for REVOKED"
	limitDate: Int64
	
	"Member is leaving? null for REVOKED or NEWCOMER"
	isLeaving: Boolean
	
	"Is a sentry? null if not MEMBER"
	sentry: Boolean
	
	"Active received certifications, sorted by increasing pubkeys"
	received_certifications: Received_Certifications!
	
	"Active sent certifications, sorted by increasing pubkeys"
	sent_certifications: [Certification!]!
	
	"All certifiers, old or present (void for REVOKED)"
	all_certifiers: [Identity!]
	
	"All certified identities, old or present (void for REVOKED)"
	all_certified: [Identity!]
	
	"State of the identity's distance rule"
	distance: Distance!
	
	"Identity's quality (percent)"
	quality: Float!
	
	"Identity's degree of centrality (percent)"
	centrality: Float!
	
	"History of identity's entries into and exits out of the WoT"
	history: [HistoryEvent!]!
	
	"Minimum date of next sent certification; null if not MEMBER"
	minDate: Int64
	
	"Minimum date of next sent certification is passed; null if not MEMBER"
	minDatePassed: Boolean

} #Identity

"Status of an identity in WoT"
enum Identity_Status {
	
	"The identity has been revoked"
	REVOKED
	
	"The identity is no more member but not revoked yet"
	MISSING
	
	"The identity is a member of the WoT"
	MEMBER
	
	"Newcomer waiting for membership"
	NEWCOMER

} #Identity_Status

"Sorting order"
enum Identity_Order {
	
	"Sorting by uid"
	UID
	
	"Sorting by pubkey"
	PUBKEY

} #Identity_Order

"Used by 'Query.idSearch'"
input IdSearchInput {
	
	"Prefix of searched keys (uid or pubkey)"
	hint: String! = ""
	
	"List of searched statuses"
	status_list: [Identity_Status!]
	
} #IdSearchInput

"Result of 'Query.idSearch'"
type IdSearchOutput {
	
	"Number of REVOKED identities corresponding to 'IdSearchInput.hint'"
	revokedNb: Int!
	
	"Number of MISSING identities corresponding to 'IdSearchInput.hint'"
	missingNb: Int!
	
	"Number of MEMBER identities corresponding to 'IdSearchInput.hint'"
	memberNb: Int!
	
	"Number of NEWCOMER identities corresponding to 'IdSearchInput.hint'"
	newcomerNb: Int!
	
	"All identities corresponding to 'IdSearchInput'"
	ids: [Identity!]!
	
} #IdSearchOutput

"Certifications received by an identity"
type Received_Certifications {
	
	"List of all valid received certifications"
	certifications: [Certification!]!
	
	"Limit date of the 'ParameterName.sigQty'th oldest received certification; or null if less than 'ParameterName.sigQty' certifications received"
	limit: Int64
	
} #received_Certifications

"Certification sent by 'from' and received by 'to'"
type Certification {
	
	"Sender"
	from: Identity!
	
	"Receiver"
	to: Identity!
	
	"Is certification in sandbox?"
	pending: Boolean!
	
	"Registration block"
	block: Block
	
	"Limit date (bct) of validity"
	expires_on: Int64!
	
} #Certification

"Result of distance rule evaluation"
type Distance {
	
	"Proportion of sentries reached in 'ParameterName.stepMax' steps or less"
	value: Float!
	
	"Is 'value' greater than 'ParameterName.xpercent' or equal?"
	dist_ok: Boolean!
	
} #Distance

"History of entries into the WoT and exits of an identity"
type HistoryEvent {
	
	"Entry?"
	in: Boolean!
	
	"Registration block"
	block: Block!
	
} #HistoryEvent

"Number & dates of a block"
type Block {
	
	"Block number"
	number: Int!
	
	"Blockchain time"
	bct: Int64!
	
	"UTC+0 real time"
	utc0: Int64!

} #Block

"Set of internal certifications and membership application dossiers available in sandbox"
type File {

	"List of internal certifications and membership application dossiers"
	certifs_dossiers: [CertifOrDossier!]
	
	"Number od dossiers"
	dossiers_nb: Int!
	
	"Number of internal certifications"
	certifs_nb: Int!

} #File

"Internal certification or membership application dossier"
union CertifOrDossier = DatedCertification | Dossier

"Certification in a 'File'"
type DatedCertification {
	
	certification: Certification!
	
	"Date of availability"
	date: Int64!

} #DatedCertification

"Newcomer's membership application dossier"
type Dossier {
	
	newcomer: Identity!
	
	"Minimum number of certifications needed to fulfill the distance rule"
	main_certifs: Int!
	
	"External certifications"
	certifications: [DatedCertification!]!
	
	"'ParameterName.msPeriod' after the last membership application (or 0 if none)"
	minDate: Int64!
	
	"Date of availability"
	date: Int64!

} #Dossier

"Result of 'Query.wwResult'"
type WWResult {
	
	"Total time of computation, 'File' included"
	computation_duration: Int!
	
	"Number of permutations used; this number may be very big"
	permutations_nb: Int!
	
	"Number of NEWCOMER(s)' dossiers"
	dossiers_nb: Int!
	
	"Number of internal certifications"
	certifs_nb: Int!
	
	"'permutations' displays the list of WotWizard permutations; their number may be very big"
	permutations: [WeightedPermutation!]!
	
	"Forecasts of NEWCOMER(s)' entries, sorted by dates of entries"
	forecastsByDates: [Forecast!]!
	
	"Forecasts of entries of the NEWCOMER(s) whose uid(s) begin with the 'with' parameter (or of all NEWCOMER(s) if 'with' is absent or null); the selection is not case sensitive"
	forecastsByNames (with: String = ""): [Forecast!]!
	
} #WWResult

"A permutation weighted by a probability"
type WeightedPermutation {
	
	"Probability of occurrence"
	proba: Float!
	
	"Ordered list of NEWCOMER(s)' entries"
	permutation: [PermutationElem!]!
	
} #WeightedPermutation

"An expected NEWCOMER's entry"
type PermutationElem {
	
	id: Identity!
	
	"Expected date of entry"
	date: Int64!
	
	"The expected date of entry may be later than 'date' (the computing was interrupted by lack of memory space)"
	after: Boolean!
	
} #PermutationElem

"Forecast of a NEWCOMER's entry"
type Forecast {
	
	id: Identity!
	
	"Expected date of entry"
	date: Int64!
	
	"The expected date of entry may be later than 'date' (the computing was interrupted by lack of memory space)"
	after: Boolean!
	
	"Probability of the forecast"
	proba: Float!
	
} #Forecast

"Entry or exit of an identity"
type EventId {
	
	id: Identity!
	
	"Entry or exit; true if entry"
	inOut: Boolean!
	
} #EventId

"Entries and exits of identities happening in a block"
type Event {
	
	"List of concerned identities"
	idList: [EventId!]!
	
	"Block where the event happens"
	block: Block!
	
	"Number of concerned identities in the WoT after the event"
	number: Int!
	
} #Event

"An event with non-integer value, typically a flux of entries/exits"
type FluxEvent {
	
	"Block where the event happens"
	block: Block!
	
	"Value of the flux at the event"
	value: Float!
} #FluxEvent

"A parameter of the money"
type Parameter {
	
	name: ParameterName!
	
	comment: String
	
	value: Number!
	
} #Parameter

enum ParameterName {
	
	"The relative growth of the UD every [dtReeval] period"
	c
	
	"Time period between two UD"
	dt
	
	"UD(0), i.e. initial Universal Dividend"
	ud0
	
	"Minimum delay between two certifications of a same issuer"
	sigPeriod
	
	"Maximum quantity of active certifications made by member"
	sigStock
	
	"Maximum delay a certification can wait before being expired for non-writing"
	sigWindow
	
	"Maximum age of an active certification"
	sigValidity
	
	"Minimum delay before replaying a certification"
	sigReplay
	
	"Minimum quantity of signatures to be part of the WoT"
	sigQty
	
	"Maximum delay an identity can wait before being expired for non-writing"
	idtyWindow
	
	"Maximum delay a membership can wait before being expired for non-writing"
	msWindow
	
	"Minimum delay between 2 memberships of a same issuer"
	msPeriod
	
	"Minimum percent of sentries to reach to match the distance rule"
	xpercent
	
	"Maximum age of an active membership"
	msValidity
	
	"Maximum distance between a WOT member and [xpercent] of sentries"
	stepMax
	
	"Number of blocks used for calculating median time"
	medianTimeBlocks
	
	"The average time for writing 1 block (wished time)"
	avgGenTime
	
	"The number of blocks required to evaluate again PoWMin value"
	dtDiffEval
	
	"The proportion of calculating members not excluded from the proof of work"
	percentRot
	
	"Time of first UD"
	udTime0
	
	"Time of first reevaluation of the UD"
	udReevalTime0
	
	"Time period between two re-evaluation of the UD"
	dtReeval
	
	"Maximum delay a transaction can wait before being expired for non-writing"
	txWindow

} #ParameterName

"64 bits signed integer"
scalar Int64

"Avatar of String"
scalar Hash

"Avatar of String"
scalar Pubkey

"Empty result"
scalar Void

"Int, Int64 or Float"
scalar Number

type Parameters { # Not used; for reference
	"c: The relative growth of the UD every [dtReeval] period"
	c: Float!
	"dt: Time period between two UD"
	dt: Int64!
	"ud0: UD(0), i.e. initial Universal Dividend"
	ud0: Int!
	"sigPeriod: Minimum delay between two certifications of a same issuer"
	sigPeriod: Int64!
	"sigStock: Maximum quantity of active certifications made by member"
	sigStock: Int!
	"sigWindow: Maximum delay a certification can wait before being expired for non-writing"
	sigWindow: Int64!
	"sigValidity: Maximum age of an active certification"
	sigValidity: Int64!
	"sigReplay: Minimum delay before replaying a certification"
	sigReplay: Int64!
	"sigQty: Minimum quantity of signatures to be part of the WoT"
	sigQty: Int!
	"idtyWindow: Maximum delay an identity can wait before being expired for non-writing"
	idtyWindow: Int64!
	"msWindow: Maximum delay a membership can wait before being expired for non-writing"
	msWindow: Int64!
	"msPeriod: Minimum delay between 2 memberships of a same issuer"
	msPeriod: Int64!
	"xpercent: Minimum percent of sentries to reach to match the distance rule"
	xpercent: Float!
	"msValidity: Maximum age of an active membership"
	msValidity: Int64!
	"stepMax: Maximum distance between a WOT member and [xpercent] of sentries"
	stepMax: Int!
	"medianTimeBlocks: Number of blocks used for calculating median time"
	medianTimeBlocks: Int!
	"avgGenTime: The average time for writing 1 block (wished time)"
	avgGenTime: Int64!
	"dtDiffEval: The number of blocks required to evaluate again PoWMin value"
	dtDiffEval: Int!
	"percentRot: The percent of calculating members not excluded from the proof of work"
	percentRot: Float!
	"udTime0: Time of first UD"
	udTime0: Int64!
	"udReevalTime0: Time of first reevaluation of the UD"
	udReevalTime0: Int64!
	"dtReeval: Time period between two re-evaluation of the UD"
	dtReeval: Int64!
	"txWindow: Maximum delay a transaction can wait before being expired for non-writing"
	txWindow: Int64!
} #Parameters
1 « J'aime »

Après un long travail de neuf mois, voici une version majeure de WotWizard (4.2.0):

J’ai beaucoup apprécié ce dernier développement. Tout s’est structuré autour de graphQL après la mise au point du document de définitions des types pour WotWizard :

Du coup, autour d’un petit noyau de quatre « packages », toutes les fonctionnalités se répartissent en modules indépendants qui se branchent sur graphQL au niveau des types définis dans ce document de définition. C’est simple et facile à développer.

Je vais essayer maintenant d’ajouter une interface http plus commode que le système actuel par échange de fichiers. J’aimerais aussi développer quelques directives permettant de relier certains résultats entre eux. Cela pourrait améliorer les performances.

J’espère arriver à terme à présenter enfin une interface web pour WotWizard. Si certains veulent m’aider, je suis preneur.

11 « J'aime »

Salut @gerard94, j’arrive à faire tourner WotWizard sous docker, je vais faire quelques recherches en go pour ajouter une interface http, je te tiens au courant !
https://hub.docker.com/r/fabwice/docker-wot-wizard

3 « J'aime »

Super. Je regarde aussi de mon côté.

Dans rsrc/duniter, il y a un fichier log.txt qui permet de suivre ce qu’il fait.

La version 5.0.0 vient de sortir.

Toujours en deux parties : serveur graphQL et client optionnel. Ils fonctionnent pour l’instant uniquement sur Linux. Le serveur doit se trouver sur un poste faisant tourner Duniter. Les nouveautés :

  • Tout est écrit en Go, client comme serveur.
  • Les deux parties communiquent par http (POST).
  • La manipulation et l’affichage du client se font sur le navigateur.

Malheureusement, une perte de fonctionnalité dans les versions 1.8.x de Duniter empêche l’accès direct à sa base de données. De ce fait la dernière version pouvant faire tourner WotWizard est la 1.7.21 :worried:.

C’est mon premier essai de programmation de pages web. Soyez indulgent S.V.P. Si quelques-uns veulent bien tester et m’envoyer leurs remarques, je serai ravi.

8 « J'aime »

Comment envisages-tu l’évolution de WotWizard à l’avenir ? Est-ce qu’il vaudrait mieux l’adapter comme module pour Duniter 1.9+, le rendre compatible avec les nouvelles bases de données, ou en faire un client GVA ?

J’aimerais bien écrire un client alternatif pour WotWizard axé sur la lisibilité grand public. Y a-t-il un endpoint GraphQL public pour faire des tests ?

1 « J'aime »

J’ai le plaisir d’annoncer que, depuis le 22 décembre, la dernière version de WotWizard (5.0.3) est enfin en ligne (merci cgeek).

Vous y trouverez tout un tas de renseignements sur la toile de confiance. Je vous conseille surtout la « Fenêtre WotWizard » et l’« explorateur de la toile de confiance ».

De ce fait, les posts journaliers suivants sont terminés, car chacun peut vérifier où il en est grâce à l’explorateur :

6 « J'aime »

GVA, forcément. Cela permettrait en plus de ne pas se limiter à un seul nœud.

J’aimerais bien aussi que tu le fasses :slightly_smiling_face:. Le client actuel fait quelques calculs qui ne sont pas dans le serveur graphQL, je pourrai te passer des billes si tu veux.

@cgeek : Y a-t-il une adresse publique pour wwServer ?

Sinon tu peux installer wwServer dans la dernière version de WotWizard et l’utiliser en local.

2 « J'aime »

Mais il faut avoir un serveur en 1.7, non ? Je n’ai pas ça sur le laptop boulot et je ne suis pas chez moi sur ma tour. Pour du prototypage rapide et portable, c’est plus simple de fonctionner sans serveur local. J’ai regardé la page web, mais elle fait des requêtes post à un endpoint qui dépend de la page. Par exemple, pour « https://wot-wizard.duniter.org/402membersLossT », elle fait une requête POST à « https://wot-wizard.duniter.org/402membersLossT » au format application/x-www-form-urlencoded avec à l’intérieur delay=7. Je n’arrive pas à comprendre précisément la config serveur.

J’ai rendu ma thèse, j’ai donc un peu de temps pour souffler avant la soutenance fin janvier ! C’est un petit projet qui m’intéresserait ^^ (mais il faut que je continue le nouveau site de duniter et que je participe à la formation pour contribuer à GVA).

Hélas oui. Vivement GVA.

Sinon, je n’en sais pas beaucoup plus. Je me suis servi de la bibliothèque standard de Go, package net/http :

1 « J'aime »

Comme tu veux et comme tu peux. Librement.

Est-ce que ce serait facile de faire une liste des fonctionnalités de GVA dont WotWizard a besoin pour suivre celles qui sont déjà implémentées et celles qui restent à implémenter ?

Le cadre général a déjà été tracé par @elois. En gros, on aurait accès à toute la blockchain, bloc par bloc. Il reste à écrire le détail (fichier de définition des types).

2 « J'aime »

Wahou ! Un nouveau WotWizard, c’est super.
Le problème c’est que je comprend à peine ce que signifient tous ces menus, et tous ces chiffres.
Quelques lignes explicatives seraient bienvenues. A mon humble avis.

Merci. Il n’est pas si nouveau que ça, puisque les fonctionnalités n’ont pas beaucoup changé depuis plus d’un an. Par contre la structure interne a été modifié profondément (utilisation de l’interface graphQL) et un nouveau client HTTP a été créé, permettant d’afficher les résultats dans le navigateur.

J’ai conscience que certaines parties sont encore mal présentées, mais je voulais en finir rapidement, pour avoir enfin quelque chose en ligne. Cela sera corrigé peu à peu. Pour l’instant, outre la première page traditionnelle « Prévisions: Fenêtre WotWizard », la plus intéressante est « Explorateur de la toile de confiance », qui permet de voir beaucoup de données sur toute identité dans la toile. Si la description de certaines données dans cette page semble peu claire à certains, je peux reformuler.

2 « J'aime »

Concernant les blocs, tu as déjà la commande dex export-bc e la souscription GVA newBlock, donc tu peux déjà aller voir le format :wink:

3 « J'aime »

Non, justement, l’idée est que seul wwClient soit exposé afin de constituer un 1er filet de sécurité (restrictions d’appels à l’API wwServer).

1 « J'aime »

OK. Dommage pour @HugoTrentesaux.

12 messages ont été scindés en un nouveau sujet : Blocage WotWizard (Duniter v1.7.21) au bloc 434742 à l’entrée d’ElenaMavida