1

Context

I have a quorum network mounted following the example of 7nodes. In node 1 I have deployed a smart contract privately, putting the public key of this ("BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=") in the private form.

My goal is to make a transfer to this smart contract, to execute one of its functions. Being a private contract the transfer has to be signed.

All this from a nodejs server.

Code

The smart contract is the following:

pragma solidity ^0.4.19;

contract SimpleStorage {
  uint storedData;
  uint secondData;
  uint TData;
  function set(uint x) external {
    storedData = x;
  }
  function setSecond(uint x) external {
    secondData = x;
  }
  function setT(uint x) external {
    TData = x;
  }
  function get() external view returns (uint retVal) {
    return storedData;
  }
  function getSecond() external view returns (uint retVal) {
    return secondData;
  }
  function getT() external view returns (uint retVal) {
    return TData;
  }
}

The code in nodejs is the following:

const Web3 = require('web3');
const EthereumTx = require('ethereumjs-tx');
const contract = require('truffle-contract');
const simpleStorageInterface = require("./contracts/SimpleStorage.json");
var web3 = new Web3(
    new Web3.providers.HttpProvider('http://172.10.4.159:22000')
);

var generalInfo = {
    contractAddress: "0x1932c48b2bf8102ba33b4a6b545c32236e342f34",
    account: "0xed9d02e382b34818e88b88a309c7fe71e65f419d",
    keystore: {"address":"ed9d02e382b34818e88b88a309c7fe71e65f419d","crypto":{"cipher":"aes-128-ctr","ciphertext":"4e77046ba3f699e744acb4a89c36a3ea1158a1bd90a076d36675f4c883864377","cipherparams":{"iv":"a8932af2a3c0225ee8e872bc0e462c11"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"8ca49552b3e92f79c51f2cd3d38dfc723412c212e702bd337a3724e8937aff0f"},"mac":"6d1354fef5aa0418389b1a5d1f5ee0050d7273292a1171c51fd02f9ecff55264"},"id":"a65d1ac3-db7e-445d-a1cc-b6c5eeaa05e0","version":3},
    bytecode: "0x608060405234801561001057600080fd5b506101ec806100206000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631b03316f1461007d57806322554f34146100a857806360fe47b1146100d35780636d4ce63c14610100578063b698c1291461012b578063f5f3194114610158575b600080fd5b34801561008957600080fd5b50610092610185565b6040518082815260200191505060405180910390f35b3480156100b457600080fd5b506100bd61018f565b6040518082815260200191505060405180910390f35b3480156100df57600080fd5b506100fe60048036038101908080359060200190929190505050610199565b005b34801561010c57600080fd5b506101156101a3565b6040518082815260200191505060405180910390f35b34801561013757600080fd5b50610156600480360381019080803590602001909291905050506101ac565b005b34801561016457600080fd5b50610183600480360381019080803590602001909291905050506101b6565b005b6000600154905090565b6000600254905090565b8060008190555050565b60008054905090565b8060018190555050565b80600281905550505600a165627a7a723058209cc3ec1ccb2383d74522ba2e5974347862883f4c4aa826bb69e6e1cfcc5bdd110029",
    interface: [{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"setSecond","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"setT","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getSecond","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getT","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}],
    privateFor: "BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo="
}

web3.eth.getAccounts().then(async (_result) => {
    // Set web3 default account
    web3.eth.defaultAccount = _result[0];

    // Get truffle-contract
    let myContract = contract(simpleStorageInterface);
    // Set provider
    myContract.setProvider(web3.currentProvider);
    if (typeof myContract.currentProvider.sendAsync !== "function") {
        myContract.currentProvider.sendAsync = function() {
            return myContract.currentProvider.send.apply(
                myContract.currentProvider, arguments
            );
        };
    }

    // Instanciate the contract
    var contractInstance = new web3.eth.Contract(simpleStorageInterface.abi, generalInfo.contractAddress);

    // Function data
    let encodedABI = contractInstance.methods.set(123).encodeABI();
    let nonce = await web3.eth.getTransactionCount(web3.eth.defaultAccount);

    // Transaction
    let tx = {
        nonce: web3.utils.toHex(nonce),
        from: generalInfo.account,
        to: generalInfo.contractAddress,
        gas: 2000000,
        gasPrice: 0,
        data: encodedABI,
        privateFor: [generalInfo.privateFor]
    }
    let decrypt = web3.eth.accounts.decrypt(generalInfo.keystore, "");
    // Remove 0x from private key
    var privateKey = decryptKey.privateKey.substring(2);
    var bufferPK = new Buffer(privateK, 'hex');
    // Generate transaction using "ethereumjs-tx"
    var transaction = new EthereumTx(tx);
    // Sign transaction
    transaction.sign(bufferPK);

    // Send signed transaction
    web3.eth.sendSignedTransaction("0x" + transaction.serialize().toString('hex'), (_err, _res) => {
        if(_err){
            console.error("ERROR: ", _err);
        } else {
            console.log("Success: ", _res);
        }
    }).on('confirmation', (confirmationNumber, receipt) => {
        console.log('=> confirmation: ' + confirmationNumber);
    })
    .on('transactionHash', hash => {
        console.log('=> hash');
        console.log(hash);
    })
    .on('receipt', receipt => {
        console.log('=> reciept');
        console.log(receipt);
    })
    .on('error', console.error);
});

Question and problem

The transaction is executed successfully, but the new value "123" is not changed in the smart contract. Only if I unlock the account before the transaction await web3.eth.personal.unlockAccount (account, "") works really, but I do not want to be blocking and unblocking the account for security reasons.

A correct transfer would be the following:

{
  blockHash: "0xe5a2df3f592392c71f9995d697721c046f60c81d2988418b0c7b929cb17a0cee",
  blockNumber: 2190,
  from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d",
  gas: 90000,
  gasPrice: 0,
  hash: "0x24df9e01d9fdb7acc7a2842dcdd1d93a37e7be7885ef469a262d8a690f7143f3",
  input: "0xb0101ef545cf42bb490bca4fac873ea06d989abf1fbdc89f7dfd09014c085f163c371efa5acac2b43c9dec5cb20bd11e853069a99f4bcb938d6fdcd6f2918333",
  nonce: 31,
  r: "0x9851006a766b4bd75051cdba9c06b6d251125d68894983eee3a4c1a53a03d77a",
  s: "0x1696039cedf14a82147c858bc17896664c9c74bda313307dbf9386b7d6893938",
  to: "0x1932c48b2bf8102ba33b4a6b545c32236e342f34",
  transactionIndex: 0,
  v: "0x25",
  value: 0
}

Mine looks like this:

{
  blockHash: "0x6a2aacceabe984b2c368fa9ca7c245065924dd6d88e30f81311e2a5a7e2aeab8",
  blockNumber: 2119,
  from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d",
  gas: 2000000,
  gasPrice: 0,
  hash: "0x4a918c1641478c1f229e7cdfff93669a6e08b37555eafe871fc3b05717cbcb79",
  input: "0x60fe47b1000000000000000000000000000000000000000000000000000000000000007b",
  nonce: 30,
  r: "0xac64a34de4bf0c2d3f1d8da6af3d38ee12be38846f744004eeef460ad94b528e",
  s: "0x10e642925665877c4e2571a2f835af68c025417574462ffc4864e6128e4a4deb",
  to: "0x1932c48b2bf8102ba33b4a6b545c32236e342f34",
  transactionIndex: 0,
  v: "0x1c",
  value: 0
}

The difference is the property "v", the value that is being fixed in my transfer is not correct, it has to be 0x25 or 0x26 to identify them as private transfers. I do not understand why these values are not setting well, helpme please.

  • Your questions are confusing please make your questions much more clear. about the blocking and unblocking, it is very usual and is needed to make any transactions. if you handle the ethereum wallets like you do, you will have to unlock, transact and lock the account. – Kaki Master Of Time Nov 6 '18 at 13:37
1

Quorum at the moment does not support self / externally signed transactions with privateFor/privateFrom (the privacy enabling stuff) -- all of these txns have to go through node and node accounts and the reason for that is that the node itself then manages encryption and off-chain sync with private parties and in the final step of this process writes a completely different txn onto the block -- without your keys at the node, the node is unable to re-sign. A patch for this is coming shortly, but it will be a different process than the one you have in your code.

  • 2
    This feature has been added --> github.com/jpmorganchase/quorum/pull/591 – hurb Jan 7 at 17:19
  • Thats correct. The feature enabling this feature has been commited to tessera and Quorum but hasn't been released yet. The release is imminent as well. – fixanoid Jan 7 at 19:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.