-
Notifications
You must be signed in to change notification settings - Fork 811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds Neutrino Client #1163
base: master
Are you sure you want to change the base?
Adds Neutrino Client #1163
Changes from all commits
c979112
e8f7df8
7fab563
c75d4ca
41009b8
0f4519e
5fdee1b
c717a9b
d0bf737
7b78379
62dfdbd
8e0bec0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#!/usr/bin/env node | ||
|
||
'use strict'; | ||
|
||
console.log('Starting bcoin'); | ||
process.title = 'bcoin'; | ||
const Neutrino = require('../lib/node/neutrino'); | ||
|
||
const node = new Neutrino({ | ||
file: true, | ||
argv: true, | ||
env: true, | ||
logFile: true, | ||
logConsole: true, // todo: remove | ||
logLevel: 'debug', // todo: remove | ||
db: 'leveldb', | ||
memory: false, | ||
workers: true, | ||
loader: require | ||
}); | ||
|
||
if (!node.config.bool('no-wallet') && !node.has('walletdb')) { | ||
const plugin = require('../lib/wallet/plugin'); | ||
node.use(plugin); | ||
} | ||
|
||
(async () => { | ||
await node.ensure(); | ||
await node.open(); | ||
await node.connect(); | ||
node.startSync(); | ||
})().catch((err) => { | ||
console.error(err.stack); | ||
process.exit(1); | ||
}); | ||
|
||
process.on('unhandledRejection', (err, promise) => { | ||
throw err; | ||
}); | ||
|
||
process.on('SIGINT', async () => { | ||
await node.close(); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,8 @@ class ChainDB { | |
this.state = new ChainState(); | ||
this.pending = null; | ||
this.current = null; | ||
this.neutrinoState = null; | ||
this.neutrinoSave = false; | ||
|
||
this.cacheHash = new LRU(this.options.entryCache, null, BufferMap); | ||
this.cacheHeight = new LRU(this.options.entryCache); | ||
|
@@ -90,6 +92,11 @@ class ChainDB { | |
this.logger.info('ChainDB successfully initialized.'); | ||
} | ||
|
||
if (this.options.neutrino) { | ||
if (!this.neutrinoState) | ||
this.neutrinoState = await this.getNeutrinoState(); | ||
} | ||
|
||
this.logger.info( | ||
'Chain State: hash=%h tx=%d coin=%d value=%s.', | ||
this.state.tip, | ||
|
@@ -1001,7 +1008,7 @@ class ChainDB { | |
*/ | ||
|
||
async getRawBlock(block) { | ||
if (this.options.spv) | ||
if (this.options.spv && !this.options.neutrino) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm what's wrong with this line? We can't get raw blocks in neutrino mode There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We would need this in order to check if a requested block by wallet already exists in the database or not, in order to skip fetching it if it exists. |
||
return null; | ||
|
||
const hash = await this.getHash(block); | ||
|
@@ -1150,6 +1157,14 @@ class ChainDB { | |
* @returns {Promise} | ||
*/ | ||
|
||
async updateNeutrinoSave () { | ||
if (this.neutrinoSave) { | ||
this.neutrinoSave = false; | ||
} else { | ||
this.neutrinoSave = true; | ||
} | ||
} | ||
|
||
Comment on lines
+1160
to
+1167
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whats this for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its to update the neutrinoSave flag. So that whenever we are not saving a pruned block, it skips saveBlock |
||
async save(entry, block, view) { | ||
this.start(); | ||
try { | ||
|
@@ -1478,7 +1493,7 @@ class ChainDB { | |
async saveBlock(entry, block, view) { | ||
const hash = block.hash(); | ||
|
||
if (this.options.spv) | ||
if (this.options.spv && !this.neutrinoSave) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same question here - SPV mode does just fine without calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we get a pruned block on request by wallet, without the neutrinoSave flag, the chain skips saving the block. |
||
return; | ||
|
||
// Write actual block data. | ||
|
@@ -1670,6 +1685,39 @@ class ChainDB { | |
b.put(layout.O.encode(), flags.toRaw()); | ||
return b.write(); | ||
} | ||
|
||
/** | ||
* Get Neutrino State | ||
* @returns {Promise<NeutrinoState>} - Returns neutrino state | ||
*/ | ||
|
||
async getNeutrinoState() { | ||
const data = await this.db.get(layout.N.encode()); | ||
if (!data) | ||
return new NeutrinoState(); | ||
return NeutrinoState.fromRaw(data); | ||
} | ||
|
||
async getCFHeaderHeight() { | ||
const state = await this.getNeutrinoState(); | ||
return state.headerHeight; | ||
} | ||
|
||
async getCFilterHeight() { | ||
const state = await this.getNeutrinoState(); | ||
return state.filterHeight; | ||
} | ||
|
||
/** | ||
* Save Neutrino State | ||
* @returns {void} | ||
*/ | ||
async saveNeutrinoState() { | ||
const state = this.neutrinoState.toRaw(); | ||
const b = this.db.batch(); | ||
b.put(layout.N.encode(), state); | ||
return b.write(); | ||
} | ||
Comment on lines
+1715
to
+1720
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. depending on when we call this function, we might want to accept a batch as the argument, assuming it will be committed later along with other data. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand what you mean. Could you please explain further? |
||
} | ||
|
||
/** | ||
|
@@ -1952,6 +2000,28 @@ function fromU32(num) { | |
return data; | ||
} | ||
|
||
class NeutrinoState { | ||
constructor() { // TODO: do we add support for multiple filters? | ||
this.headerHeight = 0; | ||
this.filterHeight = 0; | ||
} | ||
|
||
toRaw() { | ||
const bw = bio.write(8); | ||
bw.writeU32(this.headerHeight); | ||
bw.writeU32(this.filterHeight); | ||
return bw.render(); | ||
} | ||
|
||
static fromRaw(data) { | ||
const state = new NeutrinoState(); | ||
const br = bio.read(data); | ||
state.headerHeight = br.readU32(); | ||
state.filterHeight = br.readU32(); | ||
return state; | ||
} | ||
} | ||
|
||
/* | ||
* Expose | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK! Clever. We should make sure this isn't blocking the event loop etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we check that?