Skip to content

Commit

Permalink
Additional updates to reputation miner
Browse files Browse the repository at this point in the history
  • Loading branch information
kronosapiens committed Mar 25, 2022
1 parent dd967a5 commit 1c364da
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 20 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ truffle-security-output.json
.coverage_contracts
etherrouter-address.json
ganache-chain-db
.DS_Store
*.sqlite*
39 changes: 27 additions & 12 deletions packages/reputation-miner/ReputationMiner.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ class ReputationMiner {
if (minerAddress) {
this.realWallet = this.realProvider.getSigner(minerAddress);
} else {
// TODO: Check that this wallet can stake?
this.realWallet = new ethers.Wallet(privateKey, this.realProvider);
console.log("Transactions will be signed from ", this.realWallet.address);
this.minerAddress = this.realWallet.address;
}
console.log(`Transactions will be signed from ${this.realWallet.address}`);
}

/**
Expand Down Expand Up @@ -1347,20 +1349,28 @@ class ReputationMiner {
* @param { Bool } saveHistoricalStates Whether to save historical (valid) states while syncing
* @return {Promise} A promise that resolves once the state is up-to-date
*/
async sync(blockNumber, saveHistoricalStates = false) {
if (!blockNumber) {
throw new Error("Block number not supplied to sync");
}
async sync(blockNumber = 1, saveHistoricalStates = false) {

// Get the events
const filter = this.colonyNetwork.filters.ReputationMiningCycleComplete(null, null);
filter.fromBlock = blockNumber;
const events = await this.realProvider.getLogs(filter);
let localHash = await this.reputationTree.getRootHash();

console.log(`Beginning sync from block ${blockNumber} and hash ${localHash} with ${events.length} cycles to go`)

let applyLogs = false;
// We're going to apply logs if:
// - We're syncing from a user-provided hash (which is this conditional)
// - We find a match for an on-chain state in our db (which is the loop below)
// - We are syncing from scratch (e.g. no user-given or on-chain state is found, localHash is 0)
if (localHash !== `0x${new BN(0).toString(16, 64)}`) {
applyLogs = true;
}

// Run through events backwards find the most recent one that we know...
let syncFromIndex = 0;
for (let i = events.length - 1 ; i >= 0 ; i -= 1){
for (let i = events.length - 1 ; i >= 0 ; i -= 1) {
const event = events[i];
const hash = event.data.slice(0, 66);
const nLeaves = ethers.BigNumber.from(`0x${event.data.slice(66, 130)}`);
Expand All @@ -1369,22 +1379,24 @@ class ReputationMiner {
if (res.n === 1){
// We know that state! We can just sync from the next one...
syncFromIndex = i + 1;
localHash = hash;
await this.loadState(hash);
applyLogs = true;
break;
}
}

// We're not going to apply the logs unless we're syncing from scratch (which is this if statement)
// or we find a hash that we recognise as our current state, and we're going to sync from there (which
// is the if statement at the end of the loop below
console.log(`Syncing forward from index ${syncFromIndex} with local hash ${localHash}`)

if (localHash === `0x${new BN(0).toString(16, 64)}`) {
applyLogs = true;
}

for (let i = syncFromIndex; i < events.length; i += 1) {
console.log(`${new Date().toLocaleTimeString()}: Syncing mining cycle ${i + 1} of ${events.length}...`)
const event = events[i];
const time = new Date().toLocaleTimeString();
console.log(`${time}: Syncing mining cycle ${i + 1} of ${events.length}, from block ${event.blockNumber} and localHash ${localHash}`);

if (i === 0) {
// If we are syncing from the very start of the reputation history, the block
// before the very first 'ReputationMiningCycleComplete' does not have an
Expand Down Expand Up @@ -1433,7 +1445,8 @@ class ReputationMiner {
localHash = await this.reputationTree.getRootHash();
const localNLeaves = await this.nReputations;
if (localHash !== currentHash || !currentNLeaves.eq(localNLeaves)) {
console.log("ERROR: Sync failed and did not recover");
console.log(`Error: Sync failed and did not recover, final hash does not match ${currentHash}.`);
console.log("If the miner has been syncing for a while, try restarting, as the mining cycle may have advanced.");
} else {
console.log("Sync successful, even if there were warnings above");
}
Expand Down Expand Up @@ -1504,7 +1517,9 @@ class ReputationMiner {
}
const currentStateHash = await this.reputationTree.getRootHash();
if (currentStateHash !== reputationRootHash) {
console.log("WARNING: The supplied state failed to be recreated successfully. Are you sure it was saved?");
console.log(`WARNING: The supplied state ${reputationRootHash} failed to be recreated successfully. Are you sure it was saved?`);
} else {
console.log(`Reputation state ${reputationRootHash} was loaded successfully.`);
}
}

Expand Down
18 changes: 14 additions & 4 deletions packages/reputation-miner/ReputationMinerClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,18 @@ class ReputationMinerClient {
* @param {string} colonyNetworkAddress The address of the current `ColonyNetwork` contract
* @return {Promise}
*/
async initialise(colonyNetworkAddress, startingBlock) {
async initialise(colonyNetworkAddress, startingBlock, startingHash) {
this.resolveBlockChecksFinished = undefined;
await this._miner.initialise(colonyNetworkAddress);

const minerStake = await this._miner.getMiningStake();
const numEntries = minerStake.amount.div(this._miner.getMinStake());
this._adapter.log(`Miner has staked ${minerStake.amount} CLNY, allowing up to ${numEntries} entries per cycle`);

if (minerStake.amount.eq(0)) {
this._adapter.log(`Stake for mining by depositing ${minStake} in tokenLocking then calling stakeForMining on the network`);
}

let resumedSuccessfully = false;
// If we have a JRH saved, and it goes from the current (on chain) state to
// a state that we know, then let's assume it's correct
Expand Down Expand Up @@ -268,9 +272,14 @@ class ReputationMinerClient {

// Get latest state from database if available, otherwise sync to current state on-chain
await this._miner.createDB();
this._adapter.log(`Attempting to load latest on-chain state ${latestConfirmedReputationHash}`);
await this._miner.loadState(latestConfirmedReputationHash);
if (this._miner.nReputations.eq(0)) {
this._adapter.log("Latest state not found - need to sync");
if (startingHash !== undefined) {
this._adapter.log(`Loading starting hash ${startingHash}`);
await this._miner.loadState(startingHash);
}
await this._miner.sync(startingBlock, true);
}

Expand Down Expand Up @@ -460,7 +469,7 @@ class ReputationMinerClient {
const {entryIndex} = this.best12Submissions[this.submissionIndex];
const canSubmit = await this._miner.submissionPossible(entryIndex);
if (canSubmit) {
this._adapter.log("⏰ Looks like it's time to submit an entry to the current cycle");
this._adapter.log(`⏰ ${new Date().toLocaleTimeString()}: Looks like it's time to submit an entry to the current cycle`);
this.submissionIndex += 1;
await this.updateGasEstimate('average');
await this.submitEntry(entryIndex);
Expand Down Expand Up @@ -730,7 +739,7 @@ class ReputationMinerClient {

async submitEntry(entryIndex) {
const rootHash = await this._miner.getRootHash();
this._adapter.log(`#️⃣ Miner ${this._miner.minerAddress} submitting new reputation hash ${rootHash} at entry index ${entryIndex.toNumber()}`);
this._adapter.log(`#️⃣ Submitting new reputation hash ${rootHash} at entry index ${entryIndex.toNumber()}`);

// Submit hash
let submitRootHashTx = await this._miner.submitRootHash(entryIndex);
Expand All @@ -745,8 +754,9 @@ class ReputationMinerClient {
}

async confirmEntry() {
this._adapter.log("⏰ Looks like it's time to confirm the new hash");
this._adapter.log(`⏰ ${new Date().toLocaleTimeString()}: Looks like it's time to confirm the new hash`);
// Confirm hash if possible

const [round] = await this._miner.getMySubmissionRoundAndIndex();
if (round && round.gte(0)) {
await this.updateGasEstimate('average');
Expand Down
11 changes: 7 additions & 4 deletions packages/reputation-miner/bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { argv } = require("yargs")
.option('privateKey', {string:true})
.option('colonyNetworkAddress', {string:true})
.option('minerAddress', {string:true})
.option('startingHash', {string:true})
.option('providerAddress', {type: "array", default: []});
const ethers = require("ethers");
const backoff = require("exponential-backoff").backOff;
Expand All @@ -33,6 +34,7 @@ const {
oraclePort,
processingDelay,
adapterLabel,
startingHash,
} = argv;

class RetryProvider extends ethers.providers.StaticJsonRpcProvider {
Expand All @@ -53,16 +55,16 @@ class RetryProvider extends ethers.providers.StaticJsonRpcProvider {
return backoff(() => super.getNetwork(), {retry: RetryProvider.attemptCheck});
}

// This should return a Promise (and may throw erros)
// This should return a Promise (and may throw errors)
// method is the method name (e.g. getBalance) and params is an
// object with normalized values passed in, depending on the method
perform(method, params) {
return backoff(() => super.perform(method, params), {retry: RetryProvider.attemptCheck, startingDelay: 1000});
}
}

if ((!minerAddress && !privateKey) || !colonyNetworkAddress || !syncFrom) {
console.log("❗️ You have to specify all of ( --minerAddress or --privateKey ) and --colonyNetworkAddress and --syncFrom on the command line!");
if ((!minerAddress && !privateKey) || !colonyNetworkAddress) {
console.log("❗️ You have to specify all of ( --minerAddress or --privateKey ) and --colonyNetworkAddress on the command line!");
process.exit();
}

Expand Down Expand Up @@ -126,4 +128,5 @@ const client = new ReputationMinerClient({
oraclePort,
processingDelay
});
client.initialise(colonyNetworkAddress, syncFrom);

client.initialise(colonyNetworkAddress, syncFrom, startingHash);

0 comments on commit 1c364da

Please sign in to comment.