I am trying learn more about blockchain by building a small project using JavaScript. Can anyone explain to me why the previousHash does not show when I console.log the test blockchain?
(npm install --save crypto-js if you need SHA256)
const SHA256 = require('crypto-js/sha256');
class Block{
//Index: (Optional) tells us where the block is in the chain
//Timestamp: tells us when the block was created
//Data: Can include any kind of data; for a currency you could store details of the transaction(transfer amount, sender id, receiver id)
//previousHash: String which contains the hash of the block which came before it (Ensures data integrity)
constructor(index, timestamp, data, previousHash = ''){
this.index = index;
this.timestamp = timestamp;
this.data = data;
this.previousHash = previousHash;
//Hash of this block
this.hash = this.calculateHash();
}
//Runs values from block through a hashing function to create a hash
calculateHash(){
return SHA256(this.index + this.previousHash + this.timestamp + JSON.stringify(this.data)).toString();
}
}
//8.44
class Blockchain{
//Initializes blockchain
constructor(){
this.chain = [this.createGenesisBlock];
}
// first block needs to be created manually
//index, timeStamp, data, previousHash(there is none in this case)
createGenesisBlock(){
return new Block(0, "01/01/2017", "Genesis block", "0");
}
//Returns most recently added block
getLatestBlock(){
return this.chain[this.chain.length -1];
}
//adds a new block to the chain
addBlock(newBlock){
newBlock.previousHash = this.getLatestBlock().hash;
newBlock.hash = newBlock.calculateHash
//The chain is just an array so you can use regular array methods
this.chain.push(newBlock);
}
}
//create instance of blockchhain
let Coin = new Blockchain();
Coin.addBlock(new Block(1, "10/07/2017", {amount: 4}));
Coin.addBlock(new Block(2, "12/07/2017", {amount: 10}));
console.log(JSON.stringify(Coin, null, 4));
I expect the console.logged JSON file to contain the previousHash as well as the index, timestamp and data. It contains all except previousHash.
Thanks for the help have been scratching my head for a while trying to figure this out...
You forgot the paranthesis in the line with: this.chain = [this.createGenesisBlock()]; line, thus the first element of the chain will be a reference to a function, instead of an instance of a Block. Add the paranthesis, and it should work.
Additionally, you also forgot the paranthesis at another function call: when you are trying to call the function newBlock.hash = newBlock.calculateHash()
You also don't have hash in your console. This is the line with the error:
newBlock.hash = newBlock.calculateHash
calculateHash is a function
newBlock.hash = newBlock.calculateHash()
Now it is working:
{
"chain": [
null,
{
"index": 1,
"timestamp": "10/07/2017",
"data": {
"amount": 4
},
"hash": "8f84adcf036e9aa052a4d7e689c7b8b06070b851eff535870f5cb8f7d53ab05a"
},
{
"index": 2,
"timestamp": "12/07/2017",
"data": {
"amount": 10
},
"previousHash": "8f84adcf036e9aa052a4d7e689c7b8b06070b851eff535870f5cb8f7d53ab05a",
"hash": "a2479e7df8f2a61f97f3ae4830aff93c0d43041b4a7cbb8079c2309a915d8945"
}
]
}
Related
I am trying to save the current time inside a temporary object inside the timestamp key using new Date.getTime() and push it into an array which is inside a globally accessible variable, GLOBAL_VAR.
But after I make the temporary variable and print its value it shows the timestamp is NaN I don't know why I can't get it inside the object (the console.log() and the result is shown below)
Also,
handleOrderMessage function is called when a socket.io event is received I don't know if that will affect the new Date.getTime() function, showing output:
console.log("TEMP OBJECT IS", tempObject)
/*
{
id: "-909e-11ea-9ede-066a42ffe1ae",
price: "0.1",
quantity: "0.1",
side: "buy",
timestamp: NaN
}
*/
function handleOrderMessage(msg) {
let d = new Date();
console.log(d.getTime());
if (msg['status'] === "PLACED") {
//for buy
if (msg['orderSide'] === "Buy") {
let tempObject = {
side: "buy",
id: msg["OrderID"],
timestamp: d.getTime(),
quantity: parseFloat(msg["Quantity"].toFixed(4)).toString(),
price: parseFloat(msg["Price"].toFixed(4)).toString()
}
//pushing to the global orders with price from msg as key
if (tempObject.price in GLOBAL_VAR.bidOrdersPricesAsKey) {
GLOBAL_VAR.bidOrdersPricesAsKey[tempObject.price].push(tempObject);
} else {
GLOBAL_VAR.bidOrdersPricesAsKey[tempObject.price] = [tempObject]
}
console.log("GLOBAL VAR BUY ORDERS PRICES ASK KEY", GLOBAL_VAR.bidOrdersPricesAsKey)
console.log("TEMP OBJECT IS", tempObject)
}
}
Following seems to be working fine, not sure why you're getting NaN. Please provide full working code to troubleshoot the issue.
doit();
function doit() {
let d = new Date();
let tempObject = {
side: "buy",
timestamp: d.getTime()
};
console.log(tempObject);
}
I am trying to build this simple code of "BlockChain" I found it online to give me a better understanding of the blockchain technique.
But when I run it it gives me an error when it runs.
This is the error that I got:-
import {BlockChain} from 'BlockChain';
^
SyntaxError: Unexpected token
class Block
export class Block{
constructor(timestamp, data, previousHash = '') {
this.timestamp = timestamp;
this.data = data;
this.previousHash = previousHash;
// The calculation of the hash must be at the end so to ensure that all data is assigned correctly before calculation
this.hash = this.calculateHash(); }
calculateHash() {
return SHA256(this.previousHash + this.timestamp + JSON.stringify(this.data)).toString();
}
}
class BlockChain
import {Block} from 'Block';
export class BlockChain {
constructor() {
this.chain = [this.createGenesisBlock()];
}
createGenesisBlock(){
return new Block("2018-11-11 00:00:00", "Genesis block of simple chain", "");
}
getLatestBlock() {
return this.chain[this.chain.length - 1];
}
addBlock(newBlock) {
// The previous hash value of the new block is the hash value of the last block of the existing blockchain;
newBlock.previousHash = this.getLatestBlock().hash;
// Recalculate the hash value of the new block (because the previousHash is specified);
newBlock.hash = newBlock.calculateHash();
//Add new blocks to the chain;
this.chain.push(newBlock);
}
isChainValid() {
//Traverse all the blocks
for (let i = 1; i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
//Recalculate the has value of the current block. If the hash value is not matched, it indicates that data of the block was changed without permission, and therefore the has value is not recalculated.
if (currentBlock.hash !== currentBlock.calculateHash()) {
console.error("hash not equal: " + JSON.stringify(currentBlock));
return false;
}
// Determine whether the previousHash of the current block is equal to the hash of the previous block. If they are not equal to each other, this means that the previous block was changed without permission. Although the hash value is recalculated correctly, the hash value of the subsequent block is not recalculated, resulting the the whole chain breaking.
if (currentBlock.previousHash !== previousBlock.calculateHash) {
console.error("previous hash not right: " + JSON.stringify(currentBlock));
return false;
}
}
return true;
}
}
Class Test
import {BlockChain} from 'BlockChain';
import {Block} from 'Block';
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));
console.log(JSON.stringify(simpleChain, null, 4));
console.log("is the chain valid? " + simpleChain.isChainValid());
The code is fine. You can run the code as follows:
Install crypto-js using Node:
npm install crypto-js
Open a Node prompt from the Command window/Terminal:
Node
Open the Editor in Node:
Require the sha256 module. Paste the following code in the editor:
const SHA256 = require('crypto-js/sha256');
Paste the Block, BlockChain and Test classes, in the editor:
Class Block
class Block{
constructor(timestamp, data, previousHash = '') {
this.timestamp = timestamp;
this.data = data;
this.previousHash = previousHash;
// The calculation of the hash must be at the end so to ensure that all data is assigned correctly before calculation
this.hash = this.calculateHash(); }
calculateHash() {
return SHA256(this.previousHash + this.timestamp + JSON.stringify(this.data)).toString();
}
}
Class BlockChain
class BlockChain {
constructor() {
this.chain = [this.createGenesisBlock()];
}
createGenesisBlock(){
return new Block("2018-11-11 00:00:00", "Genesis block of simple chain", "");
}
getLatestBlock() {
return this.chain[this.chain.length - 1];
}
addBlock(newBlock) {
// The previous hash value of the new block is the hash value of the last block of the existing blockchain;
newBlock.previousHash = this.getLatestBlock().hash;
// Recalculate the hash value of the new block (because the previousHash is specified);
newBlock.hash = newBlock.calculateHash();
//Add new blocks to the chain;
this.chain.push(newBlock);
}
isChainValid() {
//Traverse all the blocks
for (let i = 1; i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
//Recalculate the has value of the current block. If the hash value is not matched, it indicates that data of the block was changed without permission, and therefore the has value is not recalculated.
if (currentBlock.hash !== currentBlock.calculateHash()) {
console.error("hash not equal: " + JSON.stringify(currentBlock));
return false;
}
// Determine whether the previousHash of the current block is equal to the hash of the previous block. If they are not equal to each other, this means that the previous block was changed without permission. Although the hash value is recalculated correctly, the hash value of the subsequent block is not recalculated, resulting the the whole chain breaking.
if (currentBlock.previousHash !== previousBlock.calculateHash) {
console.error("previous hash not right: " + JSON.stringify(currentBlock));
return false;
}
}
return true;
}
}
Class Test
let simpleChain = new BlockChain();
simpleChain.addBlock(new Block("2018-11-11 00:00:01", {amount: 10}));
simpleChain.addBlock(new Block("2018-11-11 00:00:02", {amount: 20}));
console.log(JSON.stringify(simpleChain, null, 4));
console.log("is the chain valid? " + simpleChain.isChainValid());
Press ^D to finish
This will give you the following output:
I've got two pages I'm working on, and both return an array of objects. When I use the following code, the new results work:
this.adminService.waiversGetAll()
.subscribe((data: Waiver[]) => {
this.waivers = data;
this.waivers.forEach((e) => {
if(e.has_signed === true) {
e.url = `View`
} else {
e.url = `${e.message}`;
}
return e;
});
console.log(this.waivers);
})
}
But when I try to do the same thing with a different array (where I need to update the values of an array nested inside) I don't get updated values:
this.adminService.GetUnsignedWaivers()
.subscribe((data: Player[]) => {
console.log("data",data);
data.forEach(e => {
let record: Object = {};
for(let i = 0; i < e.waivers.length; i++) {
console.log(e.waivers[i].has_signed);
if (e.waivers[i].has_signed === true) {
e.waivers[i].url = e.waivers[i].signatureUrl;
console.log(e.waivers[i].url);
e.waivers[i].message = "View Waiver";
} else {
e.waivers[i].url = e.waivers[i].url;
e.waivers[i].message = e.waivers[i].message;
}
console.log(e.waivers[i].message);
return;
};
return e;
});
this.size = this.players.length;
console.log(this.players);
})
}
When I look at the console.log of e.waivers[i].has_signed, the data is correct, but after that it's not right.
What do I have to do to make this work? I've tried using a for loop inside the foreach, and a bunch of other stuff.
The data supplied to the loop provides info like:
{
buyer: "email#someaddress.edu"
event: "COED A"
field: "Main"
net: null
player: {shirtSize: null, avp_id: 12345678, adult: true, …}
team: null
waivers: [{
email: "someemail#gmail.com",
has_signed: true,
message: "Liability Waiver",
signatureUrl: "https://somelink.pdf",
url: "https://somelink.com/somekeyidentifier"
}
IF the player has signed the waiver, there will be a signatureUrl field and the message should say "View Waiver" instead of the message telling me what type of waiver they will sign. I want the url to be set to signatureUrl if they signed, so I can use it in a table that doesn't like manipulation of data.
A visual of what is returned in my table:
All I get is 1600 records showing the url as though everyone hasn't signed, but when I console.log has_signed in the inner loop, it's showing TRUE for the ones that should show a signatureUrl instead.
Quickly looking at it, you have a return statement within your for loop, which would stop it from running after the first iteration.
First of all drop all the return statements in your code. Next, use map instead of forEach as the former returns you the new manipulated array and the latter is used just for iteration purpose.
Your code within subscribe then becomes:
data.waivers = data.waivers.map((waiver) => {
if (waiver.has_signed) {
// your logic goes here...
waiver.url = waiver.signatureUrl;
waivers.message = "View Waiver";
}
// No else is required as you are just reassigning with same values
});
this.playerDetails = data;
At last bind this modified data in your template.
I have this code, the thing with it is, I need it to get some data from that website, the string in apiurl. This code needs to download these websites, with the certain appids found in the json. It needs to download the data on these websites and store them in a json file. For some reason this does not work.
I have this piece of code in a .js file:
var gamekeys = JSON.parse(fs.readFileSync('gamekeys.json'));
var jsonstring = JSON.stringify(gamekeys, null, 4);
UpdateGamePricelist();
function UpdateGamePricelist() {
for(var i = 0;i<gamekeys.keys.length;i++) {
appid = gamekeys.keys[i].appid;
var apiurl = "http://store.steampowered.com/api/appdetails?appids="+appid;
if (i < 95) {
request(apiurl, function(err, response, body) {
if (err) {
console.log("Error when updating game prices: " + err+"\n");
return;
}
var apiresponse = JSON.parse(body);
if (body == "") {
console.log("Could not find a pricelist m8");
return;
}
fs.writeFile("C:/Users/ahmad/Desktop/Bots/SteamKeyProfitter/gamespricelist/"+appid+".json", body, function(err) {
if(err) {
console.log("Error saving data to game pricelist: " + err);
return;
}
console.log("Game pricelist has been updated!");
});
});
}
}
}
And I have a json file, the json file called gamekeys.json
Here it is:
{
"keys": [
{
"appid": 10,
"price":0,
"listofkeys":[],
"game": "Counter-Strike"
},
{
"appid": 20,
"price":0,
"listofkeys":[],
"game": "Team Fortress Classic"
},
{
"appid": 30,
"price":0,
"listofkeys":[],
"game": "Day of Defeat"
},
{
"appid": 40,
"price":0,
"listofkeys":[],
"game": "Deathmatch Classic"
},
It ofcourse keeps going (2 million lines of that)
Why does the first code not create 95 json files?
The problems is that your appid is the same for all of the writeFile invocations.
Try changing:
appid = gamekeys.keys[i].appid;
to:
let appid = gamekeys.keys[i].appid;
You need a fresh binding for all of the callbacks or otherwise they all get the same value (from the last loop iteration). Note that var would not work here, you need let. If you use i in one of the closures then you also need to use for (let i = ...) instead of for (var i = ...)
apiurl can be declared with var because its value is passed to the request() invocation instead of being captured by a closure, but if you use let alle of the time and never use var you wouldn't have to worry about it.
If you always start every program with 'use strict'; (with quotes) and never use var (using let or const instead) then you will not have problems with the scoping that you have here, so it's a good practice to follow and enforce with linters.
This is one of the problems. There may be more but this is certainly one of them.
Update
Answering the comment by Alex "why can't he use var appid"
Run this code:
for (var i = 0; i < 4; i++) {
let appid = 'ID' + i;
setTimeout(function () {
console.log(appid);
}, 500 * i);
}
And run this program:
for (var i = 0; i < 4; i++) {
var appid = 'ID' + i;
setTimeout(function () {
console.log(appid);
}, 500 * i);
}
And compare the output.
This demonstrates the difference between let and var.
See this answer for more info about the difference between let and var:
Why let and var bindings behave differently using setTimeout function?
I wrote code that parsing a lot of words (innerHTML) from some webpages.
and I'd like to insert data to json file directly..
Here is my js code...
var words = [];
var casper = require('casper').create();
function getWords() {
var words = document.querySelectorAll('td.subject a');
return Array.prototype.map.call(words, function(e) {
return e.innerHTML;
});
}
casper.start('http://www.todayhumor.co.kr/board/list.php?table=bestofbest', function() {
words = this.evaluate(getWords);
});
for (var i=2; i <=5; i++) {
casper.thenOpen('http://www.todayhumor.co.kr/board/list.php?table=bestofbest&page='+i, function() {
words = words.concat(this.evaluate(getWords));
});
}
casper.run(function() {
// echo results in some pretty fashion
this.echo(words.length + ' links found:').exit();
this.echo(words.join('\n')).exit();
});
and
I run this code through terminal like this!
username#wow:~/workspace/app/assets/javascripts $ casperjs application.js
and the result is (for example)
150 words found:
apple
banana
melon
kiwi
citrus
watermelon
passionfruit
mango
orange
...
So I want to insert this data in "word" part of my json file (example code of json below)
and make other columns("type": "fruit" and "spell":) automatically added
{ "my_initial_words": [
{
"type": "fruit",
"word": "apple",
"spell": "ap"
},
{
"type": "fruit",
"word": "banana",
"spell": "ba"
},
{
"type": "fruit",
"word": "melon",
"spell": "me"
}
]
}
----------------------------------------------------------------------------
thanks for adding more answer!..
but I couldn't catch where should I put these code
Could you tell me once more that... Which code you gave me executes "Saving the results to JSON file?" because I have to read json file(makeyourap.json) in my seeds.rb file like this
require 'json'
file = File.open(Rails.root.join('db','makeyourap.json'))
contents = file.read
json = ActiveSupport::JSON.decode(contents)["my_initial_words"]
So, something like this?
function makeTypeObject(name, type) {
return {
name: name,
type: type,
spell: name.substr(0,2)
};
}
var wordDesc = words.map(function (word) {
return makeTypeObject(word, "fruit");
});
var finalObject = {
my_initial_words: wordDesc
};
var jsonString = JSON.stringify(finalObject);
// if you want prettyprint, try JSON.stringify(finalObject, null, "\t");
I hope this helps.
Write to file via casper
If you want to have a file from which you read and write, appending content, you can do it like this:
var fs = require('fs');
var FILENAME = 'makeyourap.json';
function add_new_fruits(fruits) {
var data;
if ( fs.isFile(FILENAME) ) {
data = fs.read(FILENAME);
} else {
data = JSON.stringify({'my_initial_words' : [] });
}
var json = JSON.parse(data);
fruits.forEach(function(word) {
json.my_initial_words.push({"type": "fruit",
"name": word,
"spell": word.slice(0,2)});
});
data = JSON.stringify(json, null, '\t');
fs.write(FILENAME, data, "w");
}
Use this instead of the older this.echo. Just call it as
casperjs application.js
This either reads the object from a file, or creates it if it does not exist. Then, it appends each new object from the new fruits (including duplicates), and writes it back to FILENAME.
Previous approach: how to roll your own
create Object
So first, you want to create an object that only has the parameter my_initial_words with values as above.
You can create a function via
function createFinal(wordArray) {
var out = [];
wordArray.forEach(function(word) {
out.push({"type": "fruit", "name": word, "spell": word.slice(0,2)});
});
return out;
}
to create the array. Then, create the object via
var my_object = { "my_initial_words": createFinal(words) };
to JSON
Javascript has a built-in JSON-object. With a javascript-object like
var my_object = { "my_initial_words": ...
as above, use
JSON.stringify(my_object)
to get the JSON representation to write.
Older: write to file via redirection
Before, you had
this.echo(words.join('\n')).exit();
which gave you the basic list. Using this.echo, try replacing this by
var my_object = { "my_initial_words": createFinal(words) };
this.echo(JSON.stringify(my_object)).exit();
This prints to standard output. Just remove the other this.echo line (150 words found) and redirect the output via
casperjs application.js > makeyourap.json
If you want to write to file in casperjs, look at write-results-into-a-file-using-casperjs.