Added table view

This commit is contained in:
Ladd Hoffman 2023-01-27 21:20:13 -06:00
parent acda73fff4
commit 4c9cee9963
9 changed files with 148 additions and 43 deletions

View File

@ -48,3 +48,5 @@ If this is the only scenario in which new rep tokens are minted, and from then o
then we probably want each token to store information about the history of its value. then we probably want each token to store information about the history of its value.
At a minimum this can be a list where each item includes the identifier of the corresponding validation pool, and the resulting increment/decrement of token value. At a minimum this can be a list where each item includes the identifier of the corresponding validation pool, and the resulting increment/decrement of token value.
Each validation pool can then keep a record of the reputation staked by each voter, and the identifier of the corresponding post. Each validation pool can then keep a record of the reputation staked by each voter, and the identifier of the corresponding post.
---

View File

@ -6,6 +6,7 @@ export class Actor {
this.status = this.scene.addDisplayValue(`${this.name} status`); this.status = this.scene.addDisplayValue(`${this.name} status`);
this.status.set('Created'); this.status.set('Created');
this.values = new Map(); this.values = new Map();
this.valueFunctions = new Map();
this.active = 0; this.active = 0;
this.scene.registerActor(this); this.scene.registerActor(this);
} }
@ -50,13 +51,16 @@ export class Actor {
return this; return this;
} }
addValue(label) { addValue(label, fn) {
this.values.set(label, this.scene.addDisplayValue(`${this.name} ${label}`)); this.values.set(label, this.scene.addDisplayValue(`${this.name} ${label}`));
if (fn) {
this.valueFunctions.set(label, fn);
}
return this; return this;
} }
async setValue(label, value) { async setValue(label, value) {
if (typeof value === 'number') { if (typeof value === 'number' && value.toString().length > 6) {
value = value.toFixed(2); value = value.toFixed(2);
} }
let displayValue = this.values.get(label); let displayValue = this.values.get(label);
@ -70,4 +74,26 @@ export class Actor {
displayValue.set(value); displayValue.set(value);
return this; return this;
} }
async computeValues() {
for (const [label, fn] of this.valueFunctions.entries()) {
const displayValue = this.values.get(label);
let value = fn();
if (typeof value === 'number' && value.toString().length > 6) {
value = value.toFixed(2);
}
if (value !== displayValue.get()) {
await this.scene.sequence.log(`note over ${this.name} : ${label} = ${value}`);
}
displayValue.set(value);
}
}
getValuesMap() {
return new Map(Array.from(this.values.entries())
.map(([key, displayValue]) => [key, {
name: displayValue.getName(),
value: displayValue.get(),
}]));
}
} }

View File

@ -20,4 +20,8 @@ export class DisplayValue {
get() { get() {
return this.value; return this.value;
} }
getName() {
return this.name;
}
} }

View File

@ -38,6 +38,50 @@ class MermaidDiagram {
} }
} }
class Table {
constructor(box) {
this.box = box;
this.columns = [];
this.rows = [];
this.table = box.el.appendChild(document.createElement('table'));
this.headings = this.table.appendChild(document.createElement('tr'));
}
setColumns(columns) {
if (JSON.stringify(columns) === JSON.stringify(this.columns)) {
return;
}
if (this.columns.length) {
this.table.innerHTML = '';
this.headings = this.table.appendChild(document.createElement('tr'));
this.columns = [];
}
this.columns = columns;
for (const { title } of columns) {
const heading = document.createElement('th');
this.headings.appendChild(heading);
heading.innerHTML = title ?? '';
}
if (this.rows.length) {
const { rows } = this;
this.rows = [];
for (const row of rows) {
this.addRow(row);
}
}
}
addRow(rowMap) {
this.rows.push(rowMap);
const row = this.table.appendChild(document.createElement('tr'));
for (const { key } of this.columns) {
const value = rowMap.get(key);
const cell = row.appendChild(document.createElement('td'));
cell.innerHTML = value ?? '';
}
}
}
export class Scene { export class Scene {
constructor(name, rootBox) { constructor(name, rootBox) {
this.name = name; this.name = name;
@ -46,6 +90,7 @@ export class Scene {
this.box.addBox('Spacer').setInnerHTML(' '); this.box.addBox('Spacer').setInnerHTML(' ');
this.topSection = this.box.addBox('Top section').flex(); this.topSection = this.box.addBox('Top section').flex();
this.displayValuesBox = this.topSection.addBox('Values'); this.displayValuesBox = this.topSection.addBox('Values');
this.middleSection = this.box.addBox('Middle section').flex();
this.box.addBox('Spacer').setInnerHTML(' '); this.box.addBox('Spacer').setInnerHTML(' ');
this.actors = new Set(); this.actors = new Set();
@ -86,6 +131,16 @@ export class Scene {
return this; return this;
} }
withTable() {
if (this.table) {
return this;
}
const box = this.middleSection.addBox('Table');
this.box.addBox('Spacer').setInnerHTML(' ');
this.table = new Table(box);
return this;
}
async addActor(name) { async addActor(name) {
const actor = new Actor(name, this); const actor = new Actor(name, this);
if (this.sequence) { if (this.sequence) {
@ -130,4 +185,22 @@ export class Scene {
this.sequence.inSection--; this.sequence.inSection--;
this.sequence.log('end'); this.sequence.log('end');
} }
stateToTable(label) {
const row = new Map();
const columns = [];
columns.push({ key: 'seqNum', title: '#' });
row.set('seqNum', this.table.rows.length + 1);
row.set('label', label);
for (const actor of this.actors) {
for (const [aKey, { name, value }] of actor.getValuesMap()) {
const key = `${actor.name}:${aKey}`;
columns.push({ key, title: name });
row.set(key, value);
}
}
columns.push({ key: 'label', title: '' });
this.table.setColumns(columns);
this.table.addRow(row);
}
} }

View File

@ -85,6 +85,11 @@ export class ValidationPool extends ReputationHolder {
amount: this.mintedValue * (1 - params.stakeForAuthor), amount: this.mintedValue * (1 - params.stakeForAuthor),
tokenId: this.tokenId, tokenId: this.tokenId,
}); });
// Keep a record of voters and their votes
const voter = this.bench.voters.get(reputationPublicKey) ?? new Voter(reputationPublicKey);
voter.addVoteRecord(this);
this.bench.voters.set(reputationPublicKey, voter);
} }
getTokenLossRatio() { getTokenLossRatio() {
@ -171,6 +176,12 @@ export class ValidationPool extends ReputationHolder {
voter.addVoteRecord(this); voter.addVoteRecord(this);
this.bench.voters.set(reputationPublicKey, voter); this.bench.voters.set(reputationPublicKey, voter);
} }
// Update computed display values
for (const voter of this.bench.voters.values()) {
const actor = this.scene.findActor((a) => a.reputationPublicKey === voter.reputationPublicKey);
await actor.computeValues();
}
} }
applyTokenLocking() { applyTokenLocking() {
@ -266,5 +277,17 @@ export class ValidationPool extends ReputationHolder {
} }
console.log('pool complete'); console.log('pool complete');
// Update computed display values
for (const voter of this.bench.voters.values()) {
const actor = this.scene.findActor((a) => a.reputationPublicKey === voter.reputationPublicKey);
await actor.computeValues();
}
await this.bench.computeValues();
if (this.forum) {
await this.forum.computeValues();
}
this.scene.stateToTable(`validation pool ${this.name} complete`);
} }
} }

View File

@ -32,7 +32,10 @@ a:visited {
svg { svg {
width: 800px; width: 800px;
} }
.hidden { th {
/* display: none; */ text-align: left;
/* visibility: hidden; */ padding: 10px;
}
td {
background-color: #0c2025;
} }

View File

@ -26,6 +26,7 @@
const scene = (window.scene = new Scene('Availability test', rootBox)); const scene = (window.scene = new Scene('Availability test', rootBox));
scene.withSequenceDiagram(); scene.withSequenceDiagram();
scene.withFlowchart(); scene.withFlowchart();
scene.withTable();
const experts = (window.experts = []); const experts = (window.experts = []);
const newExpert = async () => { const newExpert = async () => {

View File

@ -24,6 +24,7 @@
const scene = (window.scene = new Scene('Forum test', rootBox)); const scene = (window.scene = new Scene('Forum test', rootBox));
scene.withSequenceDiagram(); scene.withSequenceDiagram();
scene.withFlowchart(); scene.withFlowchart();
scene.withTable();
scene.addDisplayValue('c3. stakeForAuthor').set(params.stakeForAuthor); scene.addDisplayValue('c3. stakeForAuthor').set(params.stakeForAuthor);
scene.addDisplayValue('q2. revaluationLimit').set(params.revaluationLimit); scene.addDisplayValue('q2. revaluationLimit').set(params.revaluationLimit);
@ -48,22 +49,19 @@
const expert2 = await newExpert(); const expert2 = await newExpert();
const expert3 = await newExpert(); const expert3 = await newExpert();
const updateDisplayValues = async () => { bench.addValue('total rep', () => bench.reputation.getTotal());
for (const expert of experts) { forum.addValue('total value', () => forum.getTotalValue());
await expert.setValue(
'rep', for (const expert of experts) {
bench.reputation.valueOwnedBy(expert.reputationPublicKey), expert.addValue('rep', () => bench.reputation.valueOwnedBy(expert.reputationPublicKey));
); }
}
await bench.setValue('total rep', bench.reputation.getTotal());
await forum.setValue('total value', forum.getTotalValue());
};
const updateDisplayValuesAndDelay = async (delayMs) => { const updateDisplayValuesAndDelay = async (delayMs) => {
await updateDisplayValues();
await delay(delayMs ?? DEFAULT_DELAY_INTERVAL); await delay(delayMs ?? DEFAULT_DELAY_INTERVAL);
}; };
scene.stateToTable('Initial state');
await updateDisplayValuesAndDelay(); await updateDisplayValuesAndDelay();
await scene.startSection(); await scene.startSection();

View File

@ -19,7 +19,8 @@
const rootBox = new Box('rootBox', rootElement).flex(); const rootBox = new Box('rootBox', rootElement).flex();
const scene = (window.scene = new Scene('Validation Pool test', rootBox)); const scene = (window.scene = new Scene('Validation Pool test', rootBox));
await scene.withSequenceDiagram(); scene.withSequenceDiagram();
scene.withTable();
const expert1 = (window.expert1 = await new Expert( const expert1 = (window.expert1 = await new Expert(
'Expert1', 'Expert1',
scene, scene,
@ -31,25 +32,6 @@
const forum = (window.forum = new Forum('Forum', scene)); const forum = (window.forum = new Forum('Forum', scene));
const bench = (window.bench = new Bench(forum, 'Bench', scene)); const bench = (window.bench = new Bench(forum, 'Bench', scene));
const updateDisplayValues = async () => {
await expert1.setValue(
'rep',
bench.reputation.valueOwnedBy(expert1.reputationPublicKey),
);
await expert2.setValue(
'rep',
bench.reputation.valueOwnedBy(expert2.reputationPublicKey),
);
await bench.setValue('total rep', bench.reputation.getTotal());
// With params.lockingTimeExponent = 0 and params.activeVoterThreshold = null,
// these next 3 propetries are all equal to total rep
// await bench.setValue('available rep', bench.reputation.getTotalAvailable());
// await bench.setValue('active rep', bench.getActiveReputation());
// await bench.setValue('active available rep', bench.getActiveAvailableReputation());
await scene.sequence.render();
};
updateDisplayValues();
await delay(1000); await delay(1000);
// First expert can self-approve // First expert can self-approve
@ -75,7 +57,6 @@
} }
await delay(1000); await delay(1000);
await pool.evaluateWinningConditions(); // Vote passes await pool.evaluateWinningConditions(); // Vote passes
await updateDisplayValues();
await delay(1000); await delay(1000);
} }
@ -88,7 +69,6 @@
}); });
await delay(1000); await delay(1000);
await pool.evaluateWinningConditions(); // Quorum not met! await pool.evaluateWinningConditions(); // Quorum not met!
await updateDisplayValues();
await delay(1000); await delay(1000);
} catch (e) { } catch (e) {
if (e.message.match(/Quorum is not met/)) { if (e.message.match(/Quorum is not met/)) {
@ -113,13 +93,8 @@
}); });
await delay(1000); await delay(1000);
await pool.evaluateWinningConditions(); // Stake passes await pool.evaluateWinningConditions(); // Stake passes
await updateDisplayValues();
await delay(1000); await delay(1000);
} }
await updateDisplayValues();
scene.deactivateAll(); scene.deactivateAll();
await updateDisplayValues();
</script> </script>