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.
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.
---

View File

@ -6,6 +6,7 @@ export class Actor {
this.status = this.scene.addDisplayValue(`${this.name} status`);
this.status.set('Created');
this.values = new Map();
this.valueFunctions = new Map();
this.active = 0;
this.scene.registerActor(this);
}
@ -50,13 +51,16 @@ export class Actor {
return this;
}
addValue(label) {
addValue(label, fn) {
this.values.set(label, this.scene.addDisplayValue(`${this.name} ${label}`));
if (fn) {
this.valueFunctions.set(label, fn);
}
return this;
}
async setValue(label, value) {
if (typeof value === 'number') {
if (typeof value === 'number' && value.toString().length > 6) {
value = value.toFixed(2);
}
let displayValue = this.values.get(label);
@ -70,4 +74,26 @@ export class Actor {
displayValue.set(value);
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() {
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 {
constructor(name, rootBox) {
this.name = name;
@ -46,6 +90,7 @@ export class Scene {
this.box.addBox('Spacer').setInnerHTML(' ');
this.topSection = this.box.addBox('Top section').flex();
this.displayValuesBox = this.topSection.addBox('Values');
this.middleSection = this.box.addBox('Middle section').flex();
this.box.addBox('Spacer').setInnerHTML(' ');
this.actors = new Set();
@ -86,6 +131,16 @@ export class Scene {
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) {
const actor = new Actor(name, this);
if (this.sequence) {
@ -130,4 +185,22 @@ export class Scene {
this.sequence.inSection--;
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),
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() {
@ -171,6 +176,12 @@ export class ValidationPool extends ReputationHolder {
voter.addVoteRecord(this);
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() {
@ -266,5 +277,17 @@ export class ValidationPool extends ReputationHolder {
}
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 {
width: 800px;
}
.hidden {
/* display: none; */
/* visibility: hidden; */
th {
text-align: left;
padding: 10px;
}
td {
background-color: #0c2025;
}

View File

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

View File

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

View File

@ -19,7 +19,8 @@
const rootBox = new Box('rootBox', rootElement).flex();
const scene = (window.scene = new Scene('Validation Pool test', rootBox));
await scene.withSequenceDiagram();
scene.withSequenceDiagram();
scene.withTable();
const expert1 = (window.expert1 = await new Expert(
'Expert1',
scene,
@ -31,25 +32,6 @@
const forum = (window.forum = new Forum('Forum', 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);
// First expert can self-approve
@ -75,7 +57,6 @@
}
await delay(1000);
await pool.evaluateWinningConditions(); // Vote passes
await updateDisplayValues();
await delay(1000);
}
@ -88,7 +69,6 @@
});
await delay(1000);
await pool.evaluateWinningConditions(); // Quorum not met!
await updateDisplayValues();
await delay(1000);
} catch (e) {
if (e.message.match(/Quorum is not met/)) {
@ -113,13 +93,8 @@
});
await delay(1000);
await pool.evaluateWinningConditions(); // Stake passes
await updateDisplayValues();
await delay(1000);
}
await updateDisplayValues();
scene.deactivateAll();
await updateDisplayValues();
</script>