Shares verification

Everything you need to know about the process to verify nonces sent by miners

Here is the full process to verify nonces sent by miners

1. Import randomx-etica-node.js

Full details of how to install randomx-etica-nodejs here:

import randomx from "randomx-etica-nodejs";

2. Get nonce and from result from miner submit request:

var nonce = interaction.params.nonce;
var hashresult = interaction.params.result;

3. Load miner's Blob

The miner should have a unique blob specific for this miner. For nonce verification you need to load this minerBlob. Reserved Space Then convert minerBlob to 0x format like this:

const minerBlob = randomxHelper.convertToRawWithout0x(this.randomxBlobWithReservedHash);
(randomxHelper functions details below at bottom of the page)

4. Finally, convert inputs data in right format

const nonceBuffer = Buffer.from(nonce, 'hex');
const hashresultBuffer = Buffer.from(hashresult, 'hex');
const targetBigNumber = new BigNumber(this.target);
const targetBuffer = Buffer.from(targetBigNumber.toString(16).padStart(64, '0'), 'hex');
const seedHash = randomxHelper.convertToRawWithout0x(this.randomxSeedhash);
(randomxHelper functions details below at bottom of the page)

Check Read Etica Smart Contract section for how to retrieve the variables data from Etica Smart Contract (your system should have these variables available as vars for checks)

4. Verify Nonce

const isValid = randomx.VerifyEticaRandomXNonce(minerBlob, nonceBuffer, targetBuffer, seedHash, hashresultBuffer);

if(!isValid){           
     // invalid nonce do your logic
     console.log('invalid nonce');
}
else {
     // valid nonce do your logic
     console.log('valid nonce');
}

5. Make sure to save miner's extraNonce

You need to save extraNonce alongside the share data in your database system. Indeed you will need it to call the mintrandomX() Etica Smart Contract function. Note it is the extraNonce you need, not the extraNonceHash. Check this section for details about that: Reserved Space


Here is randomxHelper.js for details about what the mentioned randomxHelper functions like convertWithout0x() do

randomxHelper.js:

import web3utils from 'web3-utils'


export function convertWithout0x(_data){
    return _data.startsWith('0x') ? _data.slice(2) : _data;
}

export function convertAdd0x(_data){
    if (typeof _data !== 'string') {
        throw new Error('Input data must be a string');
    }
    if (_data.startsWith('0x')) {
        return _data;
    }
    const result = '0x' + _data;
    return result;
}

export function convertToRawWithout0x(_data) {
    // Check if _data is null or undefined
    if (_data == null) {
        console.warn('convertToRawWithout0x: Input data is null or undefined');
        return '';
    }

    // Ensure _data is a string
    if (typeof _data !== 'string') {
        console.warn('convertToRawWithout0x: Input is not a string, attempting to convert');
        try {
            _data = String(_data);
        } catch (error) {
            console.error('convertToRawWithout0x: Failed to convert input to string', error);
            return '';
        }
    }

    // Trim any whitespace
    _data = _data.trim();

    // Check if the string is empty after trimming
    if (_data === '') {
        console.warn('convertToRawWithout0x: Input string is empty');
        return '';
    }

    // Remove '0x' prefix if it exists
    return _data.toLowerCase().startsWith('0x') ? _data.slice(2) : _data;
}


export function convertTargetToCompact(target) {
    // Remove '0x' prefix if present
    target = target.startsWith('0x') ? target.slice(2) : target;
    
    // Convert target to BigNumber
    const targetBN = new web3utils.BN(target, 16);
    
    // Calculate difficulty: (2^256 - 1) / target
    const maxTarget = new web3utils.BN(2).pow(new web3utils.BN(256)).sub(new web3utils.BN(1));
    const difficulty = maxTarget.div(targetBN);
    
    // Calculate 32-bit representation: ((2^256 - 1) / difficulty) >> 224
    const compactTarget = maxTarget.div(difficulty).shrn(224);
    
    // Convert to hexadecimal and pad to 8 characters
    let compactHex = compactTarget.toString(16).padStart(8, '0');
    
    // Swap endianness
    compactHex = compactHex.match(/.{2}/g).reverse().join('');
    
    return compactHex;
} 


export function setReservedHashOnBlob(blockHeader, poolAddress, challengeNumber, extraNonce){

    console.log('-------------------  setting reservedHash -------------------');

    const reservedOffset = 55;
    const reservedSpaceSize = 8; // 8 bytes

    console.log('extraNonce is: ', extraNonce);

    console.log('this.poolAddress is:', poolAddress);
    console.log('this.challengeNumber is:', challengeNumber);

    console.log('typeof this.poolAddress is:', typeof poolAddress);
    console.log('typeof this.challengeNumber is:', typeof challengeNumber);

    var extraNonceHash = web3utils.soliditySha3( poolAddress, extraNonce, challengeNumber );
        console.log('extraNonceHash: ', extraNonceHash);

        // Truncate extraNonceHash to 8 bytes
        const truncatedExtraNonceHash = Buffer.from(extraNonceHash.slice(2), 'hex').slice(0, reservedSpaceSize);
        console.log('truncatedExtraNonceHash:', truncatedExtraNonceHash.toString('hex'));

        // Ensure blockHeader is a Buffer
        if (!Buffer.isBuffer(blockHeader)) {
            if (typeof blockHeader === 'string') {
                // If it's a string, assume it's hex (with or without '0x' prefix)
                blockHeader = blockHeader.startsWith('0x') ? blockHeader.slice(2) : blockHeader;
                blockHeader = Buffer.from(blockHeader, 'hex');      
            } else {
                // If it's not buffer or string, throw an error
                throw new Error(`Unsupported blockHeader type: ${typeof blockHeader}`);
            }
        }

        // Validate the resulting Buffer
        if (!Buffer.isBuffer(blockHeader) || blockHeader.length === 0) {
            throw new Error('Failed to convert blockHeader to a valid Buffer');
        }

        console.log('blockHeader before inserting truncatedExtraNonceHash:', blockHeader.toString('hex'));

        // Insert truncatedExtraNonceHash into blockHeader at offset 55, blockHeader With ReservedHash set at offset 55
        var updatedblockHeader = Buffer.concat([
            blockHeader.slice(0, reservedOffset),
            truncatedExtraNonceHash,
            blockHeader.slice(reservedOffset + reservedSpaceSize)
        ]);

        console.log('blockHeader after inserting truncatedExtraNonceHash:', updatedblockHeader.toString('hex'));

        return updatedblockHeader.toString('hex');

}

Last updated