Permalink
Browse files

feat(address): address generation is done on lite client

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...
1 parent 991e60f commit 4cc44a66fd2b06041c1c62aae4281c114980a9c6 @beregovoy68 beregovoy68 committed Jul 25, 2016
Showing with 123 additions and 91 deletions.
  1. +6 −2 Gruntfile.js
  2. +2 −0 js/waves.settings.js
  3. +4 −6 js/waves.ui.functions.js
  4. +5 −7 js/waves.ui.js
  5. +56 −76 js/waves.ui.lockscreen.js
  6. +22 −0 js/waves.util.js
  7. +28 −0 tests/spec/waves.util.spec.js
View
@@ -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.
@@ -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: {
@@ -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 || {}));
@@ -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));
});
}
View
@@ -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() {
@@ -97,7 +97,6 @@ var Waves = (function(Waves, $, undefined) {
$("#publicKeyLockscreen").html('');
$("#privateKeyLockscreen").html('');
$("#addresLockscreen").html('');
-
});
//Create new Waves Acount
@@ -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);
@@ -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(){
@@ -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) {
@@ -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) {
@@ -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();
View
@@ -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;
@@ -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));
@@ -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.