Developer Portal - First Challenge - genesis hash

Howdy All,

Just wondering if anyone else is trying to use the developer challenges as a way of learning to use the Algorand JavaScript SDK?

If so how did you get past the genesis hash error?

I tool the hash from here;

And I get the below error;

Unmapped error: Error: genesis hash must be specified and in a base64 string.
Hint: hit control+c anytime to enter REPL.
{
type: ‘ValidationError’,
detail: { transaction_ids: [ ‘This list may not be empty.’ ] },
fallback_message: ‘Transaction Ids: This list may not be empty.’
}
Something went wrong, please review the error and try again

I base64 encoded the genesis hash, but got the same error.

const ptxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
// TODO: Fill out the transaction parameters to send yourself 1 Algo
from: ‘BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM’, // The from (sender) should be set to your address
to: ‘BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM’, // The to (receiver) should be set to your address
amount: 1000000, // The amount should be set to 1 algo (Hint: 1 algo is 1 million micro algos)
suggestedParams: params, // Use the suggested parameters you got from the client above
gh: ‘SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=’
});

I am assuming that he right json field name is gh as named in the below documentation;

The error message about transaction ids being empty is probably because you accidentally removed the bit of code that appends tx ids for validation.

There should be a line something like

    // Send the transaction, returns the transaction id for the first transaction in the group
    const { txId } = await client.sendRawTransaction(signed).do();
    txids.push(txId);

that saves the transaction id to be passed in and validated on the backend.

Ben

Hi Ben,

your code suggestion is in there

const algosdk = require(“algosdk”);
const {validate, printError, algod} = require(“./utils”);

// DO NOT CHANGE
const challenge_id = “3474867148855516251”
const client = new algosdk.Algodv2(algod.token, algod.server, algod.port);
let txids = ;

let params = client.getTransactionParams();
let gh = params.genesishashb64;
const sk = // TODO: Paste your secret key here. You can find it underneath the code editor.

// Decode the secretKey into a Uint8Array from base 64
// This will produce an array of length 64
const secret = new Uint8Array(Buffer.from(sk, “base64”));
const acct = {
// The public key is the secret[32:], or the last 32 bytes
// We encode it to the address which is easier to read and includes a checksum
addr: algosdk.encodeAddress(secret.slice(32)),
// We need not do anything with the secret
sk: secret,
};

(async function () {
try {
// Get the suggested parameters from the Algod server. These include current fee levels and suggested first/last rounds.
const sp = algosdk.ALGORAND_MIN_TX_FEE; // TODO: use the client initialized above to get the suggested parameters from the algod server

// Create a payment transaction from you to you using the `acct` variable defined above
const ptxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
  // TODO: Fill out the transaction parameters to send yourself 1 Algo 
  from: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',    // The from (sender) should be set to your address
  to: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',      // The to (receiver) should be set to your address
  amount: 1000000,  // The amount should be set to 1 algo (Hint: 1 algo is 1 million micro algos)
  suggestedParams: params, // Use the suggested parameters you got from the client above
gh: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI='
});

// Sign the transaction. This should return a Uint8Array representing the bytes to be sent to the network
const signed = undefined; // TODO: Sign the transaction object using the accounts secret key

// Send the transaction, returns the transaction id for the first transaction in the group
const { txId } = await client.sendRawTransaction(signed).do();
txids.push(txId);

// Wait for the transaction to be confirmed.
const result = await algosdk.waitForConfirmation(client, txId, 2);

// Log out the confirmed round
console.log("Confirmed round: " + result["confirmed-round"]);

} catch (error) {
printError(error);
}

if (await validate(challenge_id, txids)) {
console.log(“Success!”);
} else {
console.error(
“Something went wrong, please review the error and try again”
);
}

})();

Edited the post to remove your secret key.

Hi was missing the do command, for the suggested parameters, but it still throws the same error about the genesis hash.

I debugged the code, and checked the value of the params variable, and it’s populated with data.

Code below;
const algosdk = require(“algosdk”);
const {validate, printError, algod} = require(“./utils”);

// DO NOT CHANGE
const challenge_id = “3474867148855516251”
const client = new algosdk.Algodv2(algod.token, algod.server, algod.port);
let txids = ;
let params = client.getTransactionParams().do();
const sk = “REMOVED”; // TODO: Paste your secret key here. You can find it underneath the code editor.

// Decode the secretKey into a Uint8Array from base 64
// This will produce an array of length 64
const secret = new Uint8Array(Buffer.from(sk, “base64”));
const acct = {
// The public key is the secret[32:], or the last 32 bytes
// We encode it to the address which is easier to read and includes a checksum
addr: algosdk.encodeAddress(secret.slice(32)),
// We need not do anything with the secret
sk: secret,
};

(async function () {
try {
// Get the suggested parameters from the Algod server. These include current fee levels and suggested first/last rounds.
const sp = algosdk.ALGORAND_MIN_TX_FEE; // TODO: use the client initialized above to get the suggested parameters from the algod server

// Create a payment transaction from you to you using the `acct` variable defined above
const ptxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
  // TODO: Fill out the transaction parameters to send yourself 1 Algo 
  from: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',    // The from (sender) should be set to your address
  to: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',      // The to (receiver) should be set to your address
  amount: 1000000,  // The amount should be set to 1 algo (Hint: 1 algo is 1 million micro algos)
  suggestedParams: params, // Use the suggested parameters you got from the client above
  gh: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI='
});

// Sign the transaction. This should return a Uint8Array representing the bytes to be sent to the network
const signed = undefined; // TODO: Sign the transaction object using the accounts secret key

// Send the transaction, returns the transaction id for the first transaction in the group
const { txId } = await client.sendRawTransaction(signed).do();
txids.push(txId);

// Wait for the transaction to be confirmed.
const result = await algosdk.waitForConfirmation(client, txId, 2);

// Log out the confirmed round
console.log("Confirmed round: " + result["confirmed-round"]);

} catch (error) {
printError(error);
}

if (await validate(challenge_id, txids)) {
console.log(“Success!”);
} else {
console.error(
“Something went wrong, please review the error and try again”
);
}

})();

You still have one todo in here

Thanks for that Jason

// Sign the transaction. This should return a Uint8Array representing the bytes to be sent to the network
const signed = se**strong text**cret; // TODO: Sign the transaction object using the accounts secret key

I do need to be doing this on a larger laptop.

I do get the same error though

In debugging it’s never getting to the signing of the transaction, its never getting past this block

const ptxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
  // TODO: Fill out the transaction parameters to send yourself 1 Algo 
  from: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',    // The from (sender) should be set to your address
  to: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',      // The to (receiver) should be set to your address
  amount: 1000000,  // The amount should be set to 1 algo (Hint: 1 algo is 1 million micro algos)
  suggestedParams: params, // Use the suggested parameters you got from the client above
  gh: 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI='
});

Howdy,

Got back onto this problem today, and found I was putting the genesis hash in the wrong place. I now put it into the “suggestedParams” not the body of the transaction JSON.

My code is now failing after this line because there is never a transaction returned.

const { txId } = await client.sendRawTransaction(signed).do();

Below is the code with the secret key removed.

const algosdk = require("algosdk");
const {validate, printError, algod} = require("./utils");

// DO NOT CHANGE
const challenge_id = "3474867148855516251"
const client = new algosdk.Algodv2(algod.token, algod.server, algod.port);
let txids = [];
let params = client.getTransactionParams().do();
params.genesisHash = 'U0dPMUdLU3p5RTdJRVBJdFR4Q0J5dzl4OEZtbnJDRGV4aTkvY09VSk9pST0=';
params.genesisID = 'testnet-v1.0';
params.firstRound = 22946747;
params.lastRound = 22996747;
params.flatFee = true;
const sk = "REMOVED"; // TODO: Paste your secret key here. You can find it underneath the code editor.

// Decode the secretKey into a Uint8Array from base 64
// This will produce an array of length 64
const secret = new Uint8Array(Buffer.from(sk, "base64"));
const acct = {
  // The public key is the secret[32:], or the last 32 bytes
  // We encode it to the address which is easier to read and includes a checksum
  addr: algosdk.encodeAddress(secret.slice(32)),
  // We need not do anything with the secret
  sk: secret
};

(async function () {
  try {
    // Get the suggested parameters from the Algod server. These include current fee levels and suggested first/last rounds.
    const sp = algosdk.ALGORAND_MIN_TX_FEE; // TODO: use the client initialized above to get the suggested parameters from the algod server
	params.fee = sp;
    // Create a payment transaction from you to you using the `acct` variable defined above
    const ptxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
      // TODO: Fill out the transaction parameters to send yourself 1 Algo 
      from: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',    // The from (sender) should be set to your address
      to: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',      // The to (receiver) should be set to your address
      amount: 1000000,  // The amount should be set to 1 algo (Hint: 1 algo is 1 million micro algos)
      suggestedParams: params // Use the suggested parameters you got from the client above

    });

    // Sign the transaction. This should return a Uint8Array representing the bytes to be sent to the network
    const signed = secret; // TODO: Sign the transaction object using the accounts secret key

    // Send the transaction, returns the transaction id for the first transaction in the group
    const { txId } = await client.sendRawTransaction(signed).do();
    txids.push(txId);

    // Wait for the transaction to be confirmed.
    const result = await algosdk.waitForConfirmation(client, txId, 2);

    // Log out the confirmed round
    console.log("Confirmed round: " + result["confirmed-round"]);

  } catch (error) {
    printError(error);
  }

  if (await validate(challenge_id, txids)) {
    console.log("Success!");
  } else {
    console.error(
      "Something went wrong, please review the error and try again"
    );
  }

})();

Below is the error message

Could you help me see what I am doing wrong?

I pointed this as the test net genesis hash taken from the below page;

I took the round info from the algo test net explorer

This code should be something like
let signed = ptxn.signTxn(secret);

1 Like

@mrclisse : small comment: to make it easier to read your code, it is best to enclose it between triple backquotes ``` (see how I edited your post above)

1 Like

How do you find out which signature failed verification?

It’s still failing on the below line

let signed = ptxn.signTxn(secret);

const algosdk = require("algosdk");
const {validate, printError, algod} = require("./utils");

// DO NOT CHANGE
const challenge_id = "3474867148855516251"
const client = new algosdk.Algodv2(algod.token, algod.server, algod.port);
let txids = [];
let params = client.getTransactionParams().do();
params.genesisHash = 'U0dPMUdLU3p5RTdJRVBJdFR4Q0J5dzl4OEZtbnJDRGV4aTkvY09VSk9pST0=';
params.genesisID = 'testnet-v1.0';
params.firstRound = 22946747;
params.lastRound = 22996747;
params.flatFee = true;
const sk = "REMOVED"; // TODO: Paste your secret key here. You can find it underneath the code editor.

// Decode the secretKey into a Uint8Array from base 64
// This will produce an array of length 64
const secret = new Uint8Array(Buffer.from(sk, "base64"));
const acct = {
  // The public key is the secret[32:], or the last 32 bytes
  // We encode it to the address which is easier to read and includes a checksum
  addr: algosdk.encodeAddress(secret.slice(32)),
  // We need not do anything with the secret
  sk: secret
};

(async function () {
  try {
    // Get the suggested parameters from the Algod server. These include current fee levels and suggested first/last rounds.
    const sp = algosdk.ALGORAND_MIN_TX_FEE; // TODO: use the client initialized above to get the suggested parameters from the algod server
	params.fee = sp;
    // Create a payment transaction from you to you using the `acct` variable defined above
    const ptxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
      // TODO: Fill out the transaction parameters to send yourself 1 Algo 
      from: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',    // The from (sender) should be set to your address
      to: 'BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM',      // The to (receiver) should be set to your address
      amount: 1000000,  // The amount should be set to 1 algo (Hint: 1 algo is 1 million micro algos)
      suggestedParams: params // Use the suggested parameters you got from the client above

    });

    // Sign the transaction. This should return a Uint8Array representing the bytes to be sent to the network
    // TODO: Sign the transaction object using the accounts secret key
	let signed = ptxn.signTxn(secret);
    // Send the transaction, returns the transaction id for the first transaction in the group
    const { txId } = await client.sendRawTransaction(signed).do();
    txids.push(txId);

    // Wait for the transaction to be confirmed.
    const result = await algosdk.waitForConfirmation(client, txId, 2);

    // Log out the confirmed round
    console.log("Confirmed round: " + result["confirmed-round"]);

  } catch (error) {
    printError(error);
  }

  if (await validate(challenge_id, txids)) {
    console.log("Success!");
  } else {
    console.error(
      "Something went wrong, please review the error and try again"
    );
  }

})();```
 


(Note I did use the back quotes!)

Should I be base64 encoding the account addresses?

The most likely explanation is that the secret key does not match the sender address “from”.
Can you print acc.addr and check it is equal to BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM?

The most likely explanation is that the secret key does not match the sender address “from”.
Can you print acc.addr and check it is equal to BX4OKERATBF2IIIPVAMUEBPGI5YPJPF7ZYZIDVCME3ZS3ZE464GF35LANM

Hi Fabrice,

I don’t have the acc object, I am setting the address as a string in the body of the code. I had a look in the debugger at the ptxn object, how do I turn the ptxn.from object back from a Uint8Array into a string?

I did compare the account address & secret key in my code with the the ones provided in the challenge and they are identical.

You have manually set the params in the snippet, which you shouldn’t do.

On the following line, you should have called the method for params and then just pass it in as it is instead of editing the params object like you’ve done. Delete the params related code between the let txids = []; line and the const sk line and try again?

const sp = undefined // TODO: use the client initialized above to get the suggested parameters from the algod server
// You should call client.getTransactionParams().do() here

Hi Fionna,

First of all, thank you for helping me with this problem today, its really appreciated.

This loops me back into the problem I had at the start of this post.

I’ve commented out the lines as you requested;

let txids = [];
let params = client.getTransactionParams().do();
//params.genesisHash = 'U0dPMUdLU3p5RTdJRVBJdFR4Q0J5dzl4OEZtbnJDRGV4aTkvY09VSk9pST0=';
//params.genesisID = 'testnet-v1.0';
//params.firstRound = 600;
//params.lastRound = 700;
//params.flatFee = true;

When you attach the debugger, and look inside of the params variable, it doesn’t have any genesis information;

Which causes the original error I started this post with. Below is the console output;

Unmapped error: Error: genesis hash must be specified and in a base64 string.
Hint: hit control+c anytime to enter REPL.
{
type: ‘ValidationError’,
detail: { transaction_ids: [ ‘This list may not be empty.’ ] },
fallback_message: ‘Transaction Ids: This list may not be empty.’
}
Something went wrong, please review the error and try again

The only way I could get past the genesis hash error, was to manually populate the parameters myself.

The reason for that is, you are calling client.getTransactionParams().do outside of the JS Promise context. You should be calling it in an async function with an await before the method. There’s no guarantee that your params variable has returned the promise results (the suggested params) when you try to submit the transaction.

TL;DR: remove the params line you added right below let txids = [] and call it in the async function const sp line. Remove params.fee = sp and assign sp to suggestedParams.

1 Like

Thank you Fionna, I can continue with learning again

1 Like

Thanks for all of the comments and suggestions!
let params = await client.getTransactionParams().do();

Minor note:

when you don’t re-assign a variable in JS, it’s best to use const instead of let.
That is:

const params = await client.getTransactionParams().do();