Last active
November 27, 2019 00:10
-
-
Save mfcodeworks/8b2a59e16c834aa5d11e8d74bc528571 to your computer and use it in GitHub Desktop.
Web miner using Argon2id hashing from argon2-browser package
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default class Miner { | |
constructor(difficulty = 1, block = undefined) { | |
this.difficulty = difficulty; | |
this.block = block || { | |
id: 1, | |
time: new Date().getTime(), | |
prevHash: 'd5cd02605f5dd530caa73c799ee75d92b8e637986ab4b23875c2fa95da7d5674', | |
data: { | |
foo: 42 | |
} | |
} | |
this.nonce = 0; | |
this.hash = ''; | |
this.mined = false; | |
this.salt = 'nygmacoin'; | |
} | |
mine() { | |
if (!this.mined) { | |
this.nonce++; | |
console.log('Attempting hash', `${this.block.id}${this.block.time}${this.nonce}`); | |
return argon2.hash({ | |
pass: `${this.block.id}${this.block.time}${this.nonce}`, | |
salt: this.salt, | |
time: 3, | |
mem: 2048, | |
hashLen: 64, | |
parallelism: 1, | |
type: argon2.ArgonType.Argon2id | |
}) | |
.then(result => { | |
console.log(`Hash ${this.nonce}`, result.hashHex); | |
if (result.hashHex.substr(0, this.difficulty) === '0'.repeat(this.difficulty)) { | |
this.mined = true; | |
this.hash = result.hashHex; | |
return { | |
block: this.block, | |
nonce: this.nonce, | |
hash: this.hash | |
}; | |
} else { | |
return this.mine(); | |
} | |
}) | |
.catch(err => { console.warn('Hash error', err) }); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Observable } from 'rxjs'; | |
import { share } from 'rxjs/operators'; | |
export default class Miner { | |
constructor(difficulty = 1, block = undefined) { | |
this.difficulty = difficulty; | |
this.block = block || { | |
id: 1, | |
time: new Date().getTime(), | |
prevHash: 'd5cd02605f5dd530caa73c799ee75d92b8e637986ab4b23875c2fa95da7d5674', | |
data: { | |
foo: 42 | |
} | |
} | |
this.nonce = 0; | |
this.hash = ''; | |
this.mined = false; | |
this.salt = 'nygmacoin'; | |
this.observer = null; | |
} | |
mine() { | |
// Return observable for miner process | |
return Observable.create(observer => { | |
this.observer = observer; | |
observer.next(this.hashBlock()); | |
}) | |
.pipe(share()); | |
} | |
hashBlock() { | |
// Check if block has been mined | |
if (!this.mined) { | |
// Increase nonce and begin hashing | |
this.nonce++; | |
argon2.hash({ | |
pass: `${this.block.id}${this.block.time}${this.nonce}`, | |
salt: this.salt, | |
time: 3, | |
mem: 2048, | |
hashLen: 64, | |
parallelism: 1, | |
type: argon2.ArgonType.Argon2id | |
}) | |
.then(result => { | |
// Validate result | |
if (result.hashHex.substr(0, this.difficulty) === '0'.repeat(this.difficulty)) { | |
// If valid set results | |
this.mined = true; | |
this.hash = result.hashHex; | |
this.block.hash = this.hash; | |
this.block.nonce = this.nonce; | |
// Close out miner observer | |
this.observer.next({ | |
block: this.block, | |
nonce: this.nonce, | |
hash: this.hash | |
}); | |
this.observer.complete(); | |
} else { | |
// If not vaid send update and continue mining | |
this.observer.next(`Hash ${this.nonce}: ${result.hashHex}`); | |
this.hashBlock(); | |
} | |
}) | |
.catch(this.observer.error); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Miner from './miner.js'; | |
let mine = new Miner(1, { | |
id: 1, | |
time: new Date().getTime(), | |
prevHash: 'd5cd02605f5dd530caa73c799ee75d92b8e637986ab4b23875c2fa95da7d5674', | |
data: { | |
foo: 42 | |
} | |
}); | |
const start = new Date().getTime(); | |
mine.mine() | |
.then(mined => { | |
let elapsed = (new Date().getTime() - start)/1000 | |
console.log('Block mined', mined); | |
console.log( | |
`Attempts ${mined.nonce}\ntime ${elapsed}s\nhash rate ${Math.floor(mined.nonce / elapsed)} h/s` | |
); | |
}); | |
/* DEBUG: For future implementation | |
const worker = new Worker('mine.worker.js', { type: "module" }); | |
worker.addEventListener('message', (e) => { | |
console.log(e); | |
}); | |
worker.postMessage({ | |
difficulty: 1, | |
block: { | |
id: 1, | |
time: new Date().getTime(), | |
data: 43 | |
} | |
}); | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import './node_modules/argon2-browser/lib/argon2.js'; | |
import Miner from './miner.js'; | |
// DEBUG: Currently module import not supported in browsers | |
self.addEventListener('message', (e) => { | |
// init miner and time | |
let mine = new Miner(e.difficulty, e.block); | |
let start = new Date().getTime(); | |
// start mining | |
mine.mine() | |
.then(mined => { | |
// calc time and return result | |
self.postMessage({ | |
mined, | |
elapsed: (new Date().getTime() - start)/1000 | |
}); | |
self.close(); | |
}); | |
}, false); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment