newpay-wallet-js
Version:
143 lines (132 loc) • 6.31 kB
JavaScript
import {hash, key} from "bitsharesjs/es";
var bts_genesiskeys_bloom_url = undefined
try {
var url = require("file-loader?name=bts_genesiskeys_bloom_[sha1:hash:hex:7].dat!assets/bts_genesiskeys_bloom.dat")
if(url.indexOf("3cee441") === -1)
throw new Error("Incorrect hash: bts_genesiskeys_bloom.dat")
bts_genesiskeys_bloom_url = url
} catch(e) {
// webpack deployment exception (not run time)
console.log("WARN: Will be unable to filter BTS 1.0 wallet imports, did not find assets/bts_genesiskeys_bloom.dat", e)
}
/**
This should only be applied to a BTS 1.0 export file taken on the
discontinued chain. Any public key string or address (all 5 formats) carried
over to the BTS 2.0 genesis block will be in this filter.
Their may be some false positives but no false negatives.
*/
export default class GenesisFilter {
/** or call this.init */
constructor(bloom_buffer) {
if( ! bloom_buffer ) return
this.bloom_buffer = bloom_buffer
this.bits_in_filter = bloom_buffer.length * 8 // 8388608 (test data)
}
/** Was a bloom file deployed? This does not try to load it from the server. */
isAvailable() { return bts_genesiskeys_bloom_url !== undefined }
init(done) {
if( this.bloom_buffer ) { done(); return }
if( ! this.isAvailable() )
throw new Error("Genesis bloom file was not deployed")
var xhr = new XMLHttpRequest
// firefox 40 did not allow the blob url but ff 41.0.2 did
xhr.responseType = "blob"
xhr.onload = ()=> {
if (xhr.status === 404) return
var reader = new FileReader
reader.onload = evt => {
var contents = new Buffer(evt.target.result, 'binary')
if( contents.length !== 1048576) throw new Error("Wrong length")
this.bits_in_filter = contents.length * 8 // 8388608 (test data)
this.bloom_buffer = contents
done()
}
reader.readAsBinaryString(xhr.response)
}
xhr.onerror = () => { console.error('xhr.onerror',e) }
xhr.open("GET", bts_genesiskeys_bloom_url)
xhr.send()
}
inGenesis(pubkey_or_address) {
if( ! this.bloom_buffer ) throw new Error("Call init() first")
for(var hashes = 0; hashes < 3; hashes++) {
var hex = hash.sha256( hashes + ':' + pubkey_or_address)
var bit_address = parseInt(hex.slice(-3).toString('hex'), 16) % this.bits_in_filter // 3090564
// console.error("bit_address", bit_address.toString(16))
var byte_address = bit_address >> 3 // 386320
// console.error("byte_address", byte_address.toString(16))
var mask = 1 << (bit_address & 7) // 16
// console.error("mask", mask.toString(16))
var byte = this.bloom_buffer[byte_address]
// console.error("byte", byte.toString(16))
// console.error("byte & mask", byte & mask, (byte & mask) === 0, '\n')
if( (byte & mask) === 0 ) return false
}
return true
}
filter( account_keys, status ) {
if( ! this.isAvailable() ) {
console.log("WARN: Missing bloom filter for BTS 0.9.x wallets")
status({ error: "missing_bloom" })
return
}
var initalizing = true
status({ initalizing })
this.init(()=> {
try {
initalizing = false
status({ initalizing })
var running_count_progress = 1
for(var a = 0; a < account_keys.length; a++) {
var removed_count = 0, count = 0
var keys = account_keys[a]
var total = keys.encrypted_private_keys.length
status({ importing: true, account_name: keys.account_name, count, total })
for(var k = keys.encrypted_private_keys.length - 1; k >= 0; k--) {
count++
if( count % running_count_progress === 0 ) {
running_count_progress = 47
status({ importing: true, account_name: keys.account_name, count, total })
}
if( ! keys.public_keys) {
// un-released format, just for testing
status({ error: "missing_public_keys" })
return
}
var currentKey = keys.public_keys[k]
if( /^GPH/.test(currentKey) ) currentKey = "BTS" + currentKey.substring(3)
if(this.inGenesis( currentKey )) continue
var addresses = key.addresses(currentKey, 'BTS')
var addy_found = false
for(var i = 0; i < addresses.length; i++) {
if(this.inGenesis( addresses[i] )) {
addy_found = true
break
}
}
if( addy_found ) continue
delete keys.encrypted_private_keys[k]
delete keys.public_keys[k]
removed_count++
}
var encrypted_private_keys = [], public_keys = []
for(var k = keys.encrypted_private_keys.length - 1; k >= 0; k--) {
if( ! keys.encrypted_private_keys[k]) continue
encrypted_private_keys.push( keys.encrypted_private_keys[k] )
public_keys.push( keys.public_keys[k] )
}
keys.encrypted_private_keys = encrypted_private_keys
status({ importing: false, account_name: keys.account_name,
count: count - removed_count, total })
keys.public_keys = public_keys
}
status({ success: true, })
} finally {
if( initalizing ) {
initalizing = false
status({ initalizing })
}
}
})
}
}