Skip to content

Commit

Permalink
feat(address): address generation is done on lite client
Browse files Browse the repository at this point in the history
Implemented address generation in javascript.
Added constants for Addressing version and network codes.
Wrote tests comparing client generated addresses with backend generated ones.
Updated build.
  • Loading branch information
beregovoy68 committed Jul 25, 2016
1 parent 991e60f commit 4cc44a6
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 91 deletions.
8 changes: 6 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ module.exports = function (grunt) {
return content
.replace(/CLIENT_VERSION\s*=\s*'[^']+'/, grunt.template.process("CLIENT_VERSION = '<%= pkg.version %>a'"))
.replace(/NODE_ADDRESS\s*=\s*'[^']+'/, grunt.template.process("NODE_ADDRESS = '<%= meta.configurations.testnet.server %>'"))
.replace(/NETWORK_NAME\s*=\s*'[^']+'/, grunt.template.process("NETWORK_NAME = '<%= meta.configurations.testnet.name %>'"));
.replace(/NETWORK_NAME\s*=\s*'[^']+'/, grunt.template.process("NETWORK_NAME = '<%= meta.configurations.testnet.name %>'"))
.replace(/NETWORK_CODE\s*=\s*'[^']+'/, grunt.template.process("NETWORK_CODE = '<%= meta.configurations.testnet.code %>'"));
};

var replaceMainnetVersion = function (content) {
return content
.replace(/CLIENT_VERSION\s*=\s*'[^']+'/, grunt.template.process("CLIENT_VERSION = '<%= pkg.version %>a'"))
.replace(/NODE_ADDRESS\s*=\s*'[^']+'/, grunt.template.process("NODE_ADDRESS = '<%= meta.configurations.mainnet.server %>'"))
.replace(/NETWORK_NAME\s*=\s*'[^']+'/, grunt.template.process("NETWORK_NAME = '<%= meta.configurations.mainnet.name %>'"));
.replace(/NETWORK_NAME\s*=\s*'[^']+'/, grunt.template.process("NETWORK_NAME = '<%= meta.configurations.mainnet.name %>'"))
.replace(/NETWORK_CODE\s*=\s*'[^']+'/, grunt.template.process("NETWORK_CODE = '<%= meta.configurations.mainnet.code %>'"));
};

// Project configuration.
Expand All @@ -24,10 +26,12 @@ module.exports = function (grunt) {
configurations: {
testnet: {
name: 'testnet',
code: 'T',
server: 'http://52.30.47.67:6869'
},
mainnet: {
name: 'mainnet',
code: 'W',
server: 'https://nodes.wavesnodes.com'
},
chrome: {
Expand Down
2 changes: 2 additions & 0 deletions js/waves.settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ var Waves = (function (Waves) {
Waves.constants.CLIENT_VERSION = '0.4.1a';
Waves.constants.NODE_ADDRESS = 'http://52.30.47.67:6869';
Waves.constants.NETWORK_NAME = 'devel';
Waves.constants.ADDRESS_VERSION = 1;
Waves.constants.NETWORK_CODE = 'T';

return Waves;
}(Waves || {}));
10 changes: 4 additions & 6 deletions js/waves.ui.functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,11 @@ var Waves = (function(Waves, $, undefined) {

// additional address validation
var freshKey = Waves.getPublicKey(accountDetails.passphrase);
Waves.apiRequest(Waves.api.waves.address, freshKey, function(response) {
var generated = Waves.Addressing.fromRawAddress(response.address);
var bytes = converters.stringToByteArray(accountDetails.password);
var id = Base58.encode(Waves.blake2bHash(new Uint8Array(bytes)));
var generated = Waves.buildAddress(freshKey);
var bytes = converters.stringToByteArray(accountDetails.password);
var id = Base58.encode(Waves.blake2bHash(new Uint8Array(bytes)));

Waves.apiRequest(Waves.api.address.check(Waves.address, generated, id));
});
Waves.apiRequest(Waves.api.address.check(Waves.address, generated, id));
});
}

Expand Down
12 changes: 5 additions & 7 deletions js/waves.ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,13 +369,11 @@ var Waves = (function(Waves, $, undefined) {
});

$('#header-wPop-backup').on($.modal.BEFORE_OPEN, function() {
Waves.apiRequest(Waves.api.waves.address, Waves.publicKey, function(response) {
$('#seedBackup').val(Waves.passphrase);
$('#encodedSeedBackup').val(Base58.encode(converters.stringToByteArray(Waves.passphrase)));
$('#privateKeyBackup').val(Waves.privateKey);
$('#publicKeyBackup').val(Waves.publicKey);
$("#addressBackup").val(Waves.Addressing.fromRawAddress(response.address).getDisplayAddress());
});
$('#seedBackup').val(Waves.passphrase);
$('#encodedSeedBackup').val(Base58.encode(converters.stringToByteArray(Waves.passphrase)));
$('#privateKeyBackup').val(Waves.privateKey);
$('#publicKeyBackup').val(Waves.publicKey);
$("#addressBackup").val(Waves.buildAddress(Waves.publicKey).getDisplayAddress());
});

$('#header-wPop-backup').on($.modal.AFTER_CLOSE, function() {
Expand Down
132 changes: 56 additions & 76 deletions js/waves.ui.lockscreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ var Waves = (function(Waves, $, undefined) {
$("#publicKeyLockscreen").html('');
$("#privateKeyLockscreen").html('');
$("#addresLockscreen").html('');

});

//Create new Waves Acount
Expand Down Expand Up @@ -125,7 +124,6 @@ var Waves = (function(Waves, $, undefined) {
});

$('#login-wPop-new').on($.modal.CLOSE, function(event, modal) {

var passphrase = PassPhraseGenerator.generatePassPhrase();
$("#walletSeed").val(passphrase);

Expand All @@ -134,11 +132,8 @@ var Waves = (function(Waves, $, undefined) {

$("#publicKeyLockscreen").html(publicKey);
$("#privateKeyLockscreen").html(privateKey);

Waves.apiRequest(Waves.api.waves.address, publicKey, function(response) {
$("#addresLockscreen").html(Waves.Addressing.fromRawAddress(response.address).getDisplayAddress());
NProgress.done();
});
$("#addresLockscreen").html(Waves.buildAddress(publicKey).getDisplayAddress());
NProgress.done();
});

$("#close_create_account_modal").on("click", function(){
Expand All @@ -163,10 +158,7 @@ var Waves = (function(Waves, $, undefined) {

$("#publicKeyLockscreen").html(publicKey);
$("#privateKeyLockscreen").html(privateKey);

Waves.apiRequest(Waves.api.waves.address, publicKey, function(response) {
$("#addresLockscreen").html(Waves.Addressing.fromRawAddress(response.address).getDisplayAddress());
});
$("#addresLockscreen").html(Waves.buildAddress(publicKey).getDisplayAddress());
});

$("#generateRandomSeed").on("click", function(e) {
Expand All @@ -180,10 +172,7 @@ var Waves = (function(Waves, $, undefined) {

$("#publicKeyLockscreen").html(publicKey);
$("#privateKeyLockscreen").html(privateKey);

Waves.apiRequest(Waves.api.waves.address, publicKey, function(response) {
$("#addresLockscreen").html(Waves.Addressing.fromRawAddress(response.address).getDisplayAddress());
});
$("#addresLockscreen").html(Waves.buildAddress(publicKey).getDisplayAddress());
});

$(".goBack").on("click", function(e) {
Expand All @@ -206,84 +195,75 @@ var Waves = (function(Waves, $, undefined) {
var name = $("#walletName").val();
var password = $("#walletPassword").val();

var address = Waves.buildAddress(publicKey);
var cipher = Waves.encryptWalletSeed(passphrase, password).toString();
var checksum = converters.byteArrayToHexString(Waves.simpleHash(converters.stringToByteArray(passphrase)));

Waves.apiRequest(Waves.api.waves.address, publicKey, function(response) {

var address = Waves.Addressing.fromRawAddress(response.address);
var cipher = Waves.encryptWalletSeed(passphrase, password).toString();
var checksum = converters.byteArrayToHexString(Waves.simpleHash(converters.stringToByteArray(passphrase)));

var accountData = {
name: name,
cipher: cipher,
checksum: checksum,
publicKey: publicKey,
address: address.getRawAddress()
};
var accountData = {
name: name,
cipher: cipher,
checksum: checksum,
publicKey: publicKey,
address: address.getRawAddress()
};

if(Waves.hasLocalStorage) {

var currentAccounts = localStorage.getItem('Waves'+Waves.network);
currentAccounts = JSON.parse(currentAccounts);
if(Waves.hasLocalStorage) {

if(currentAccounts !== undefined && currentAccounts !== null) {
var currentAccounts = localStorage.getItem('Waves'+Waves.network);
currentAccounts = JSON.parse(currentAccounts);

currentAccounts.accounts.push(accountData);
localStorage.setItem('Waves'+Waves.network, JSON.stringify(currentAccounts));
$("#wavesAccounts").append('<br><b>'+accountData.name+'</b> ' + address.getDisplayAddress());
if(currentAccounts !== undefined && currentAccounts !== null) {

} else {
var accountArray = { accounts: [accountData] };
localStorage.setItem('Waves'+Waves.network, JSON.stringify(accountArray));
$("#wavesAccounts").append('<br><b>'+accountData.name+'</b>' + address.getDisplayAddress());
}
currentAccounts.accounts.push(accountData);
localStorage.setItem('Waves'+Waves.network, JSON.stringify(currentAccounts));
$("#wavesAccounts").append('<br><b>'+accountData.name+'</b> ' + address.getDisplayAddress());

} else {
var accountArray = { accounts: [accountData] };
localStorage.setItem('Waves'+Waves.network, JSON.stringify(accountArray));
$("#wavesAccounts").append('<br><b>'+accountData.name+'</b>' + address.getDisplayAddress());
}

Waves.getAccounts(function(currentAccounts) {

var saveData = {
name: name,
cipher: cipher,
checksum: checksum,
publicKey: publicKey,
address: address.getRawAddress()
};
} else {

if(currentAccounts !== '') {
Waves.getAccounts(function(currentAccounts) {

currentAccounts = currentAccounts['WavesAccounts'];
var saveData = {
name: name,
cipher: cipher,
checksum: checksum,
publicKey: publicKey,
address: address.getRawAddress()
};

currentAccounts.accounts.push(saveData);
chrome.storage.sync.set({'WavesAccounts': currentAccounts}, function() {
// Notify that we saved.
$.growl.notice({ message: "Added Account!" });
$("#wavesAccounts").append('<br><b>'+saveData.name+'</b> ' + address.getDisplayAddress());
});
if(currentAccounts !== '') {

} else {
currentAccounts = currentAccounts['WavesAccounts'];

var accountArray = { accounts: [saveData] };
chrome.storage.sync.set({'WavesAccounts': accountArray}, function() {
// Notify that we saved.
$.growl.notice({ message: "Added Account!" });
$("#wavesAccounts").append('<br><b>'+saveData.name+'</b> ' + address.getDisplayAddress());
});
}
currentAccounts.accounts.push(saveData);
chrome.storage.sync.set({'WavesAccounts': currentAccounts}, function() {
// Notify that we saved.
$.growl.notice({ message: "Added Account!" });
$("#wavesAccounts").append('<br><b>'+saveData.name+'</b> ' + address.getDisplayAddress());
});

});

}
} else {

accountData.firstTime = true;
accountData.password = password;
accountData.passphrase = passphrase;
passphrase = '';
var accountArray = { accounts: [saveData] };
chrome.storage.sync.set({'WavesAccounts': accountArray}, function() {
// Notify that we saved.
$.growl.notice({ message: "Added Account!" });
$("#wavesAccounts").append('<br><b>'+saveData.name+'</b> ' + address.getDisplayAddress());
});
}
});
}

Waves.login(accountData);
accountData.firstTime = true;
accountData.password = password;
accountData.passphrase = passphrase;

});

Waves.login(accountData);
});

Waves.UI.registerForm.setupValidation();
Expand Down
22 changes: 22 additions & 0 deletions js/waves.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ var Waves = (function (Waves, $, undefined) {
};

Waves.MAP = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

var getNetworkIdByte = function() {
return Waves.constants.NETWORK_CODE.charCodeAt(0) & 0xFF;
}

Waves.getLocalDateFormat = function () {
return Waves.LOCALE_DATE_FORMAT;
Expand Down Expand Up @@ -364,6 +368,24 @@ var Waves = (function (Waves, $, undefined) {
return Base58.encode(p.private);
}

Waves.buildRawAddress = function (encodedPublicKey) {
var publicKey = Base58.decode(encodedPublicKey);
var publicKeyHash = this.hashChain(publicKey);

var prefix = new Uint8Array(2);
prefix[0] = Waves.constants.ADDRESS_VERSION;
prefix[1] = getNetworkIdByte();

var unhashedAddress = this.appendUint8Arrays(prefix, publicKeyHash.slice(0, 20));
var addressHash = this.hashChain(unhashedAddress).slice(0, 4);

return Base58.encode(this.appendUint8Arrays(unhashedAddress, addressHash));
}

Waves.buildAddress = function (encodedPublicKey) {
return Waves.Addressing.fromRawAddress(this.buildRawAddress(encodedPublicKey));
}

//Returns publicKey built from string
Waves.getPublicKey = function(secretPhrase) {
return this.buildPublicKey(converters.stringToByteArray(secretPhrase));
Expand Down
28 changes: 28 additions & 0 deletions tests/spec/waves.util.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,32 @@ describe("waves.util", function() {
signature = Waves.nonDeterministicSign(privateKey, messageBytes);
expect(Waves.verify(publicKey, messageBytes, Base58.decode(signature))).toBe(true);
});

it("should generate network addresses locally", function() {
// testing testnet address generation
Waves.constants.NETWORK_CODE = 'T';
expect(Waves.buildRawAddress("5ug8nQ1ubfjAZVJFed4mcXVVEBz53DfV8nBQWuKbt2AJ"))
.toEqual("3Mtkz8KeXUZmTbNH1MFcrMGv4t1av5tmaFL");
expect(Waves.buildRawAddress("9iDrC31brcunVTRCq69iUngg1S5Ai1rd6iX7vTwAGTvn"))
.toEqual("3N33kaYS3C9pvVsVjLKLApmRQHfzm3UY36N");
expect(Waves.buildRawAddress("Dq5f76Ro3qQCPWSDrCNrVDCiKwNFKCP2UmnVZzPxVf8"))
.toEqual("3NBmgsTgGv8nfmYzbCiKvTuBJtDpVyyxqKr");
expect(Waves.buildRawAddress("6tk94Rwij3FXwfaJLWu9PhQAHDY2MUjPLYkHQ28HaRk3"))
.toEqual("3MstHyC4tKtBhzbWdhrJ3jkxPD1hYSJCi77");
expect(Waves.buildRawAddress("2oGDrLRdBsU9Nb32jgPMh3TrQXm9QifUBLnLijfWqY5e"))
.toEqual("3MzUpwpiNTr32YWoYVmRFyzJQgdDbti3shP");
expect(Waves.buildRawAddress("71m88eJxbfJnNPW87r4Qtrp9Q2qa1wsLYmrxXRAzLPF6"))
.toEqual("3MwJXUURjZY2BmbMDRMwgGnJ19RZC9Hdg3V");
expect(Waves.buildRawAddress("7Ftuept6hfNEhSeVA439asPWZQVuteqWQUEPz6RGHsAo"))
.toEqual("3MpETHR7opAMN6dWqJejq1X37YCkq6Nu5hK");
expect(Waves.buildRawAddress("AEYsMR1171SmhV77rDtBTyfjmFubzirpHqFH4hV1aDt9"))
.toEqual("3MyciTA8STrTWjZ46KdoZ1ASf5GuY7sD8be");

// testing mainnet address generation
Waves.constants.NETWORK_CODE = 'W';
expect(Waves.buildRawAddress("D1vnz91YRXyDM72R6ZsPZfj1woMzL5nZtFrfeGQYjMs6"))
.toEqual("3PKGL4nMz3sMESQXPzmX5GKbiQtCi2Tu9Z5");
expect(Waves.buildRawAddress("9Emin4uvu2cew67hkpkX2ZKV6NJEjyP7Uvzbf8ARMCc6"))
.toEqual("3P9oRcFxwjW58bqu1oXyk1JrRTy8ADSKvdN");
});
});

0 comments on commit 4cc44a6

Please sign in to comment.