Skip to content

Commit

Permalink
Signing fixes back-ported from 2.x (#3125)
Browse files Browse the repository at this point in the history
* signing fixes back-ported from 2.x

* CHANGELOG.md updated

* transactionHash property added, docs updated, tests extended, and '0x' prefix added to messageHash for consistency reasons
  • Loading branch information
nivida committed Oct 13, 2019
1 parent d278254 commit 02c0346
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 60 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@ Released with 1.0.0-beta.37 code base.
- HttpProvider: CORS issue with Firefox and Safari (#2978)
- Ensure the immutability of the `tx` object passed to function `signTransaction` (#2190)
- Gas check fixed (#2381)
- Signing issues #1998, #2033, and #1074 fixed (#3125)
5 changes: 4 additions & 1 deletion docs/web3-eth-accounts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ Returns
- ``s`` - ``String``: Next 32 bytes of the signature
- ``v`` - ``String``: Recovery value + 27
- ``rawTransaction`` - ``String``: The RLP encoded transaction, ready to be send using :ref:`web3.eth.sendSignedTransaction <eth-sendsignedtransaction>`.
- ``transactionHash`` - ``String``: The transaction hash for the RLP encoded transaction.


-------
Expand All @@ -179,11 +180,12 @@ Example
}, '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318')
.then(console.log);
> {
messageHash: '0x88cfbd7e51c7a40540b233cf68b62ad1df3e92462f1c6018d6d67eae0f3b08f5',
messageHash: '0x31c2f03766b36f0346a850e78d4f7db2d9f4d7d54d5f272a750ba44271e370b1',
v: '0x25',
r: '0xc9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895',
s: '0x727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68',
rawTransaction: '0xf869808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a0c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895a0727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68'
transactionHash: '0xde8db924885b0803d2edc335f745b2b8750c8848744905684c20b987443a9593'
}
web3.eth.accounts.signTransaction({
Expand All @@ -201,6 +203,7 @@ Example
s: '0x440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428',
v: '0x25',
rawTransaction: '0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428'
transactionHash: '0xd8f64a42b57be0d565f385378db2f6bf324ce14a594afc05de90436e9ce01f60'
}
Expand Down
121 changes: 121 additions & 0 deletions packages/web3-eth-accounts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/web3-eth-accounts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"web3-core": "1.2.1",
"web3-core-helpers": "1.2.1",
"web3-core-method": "1.2.1",
"web3-utils": "1.2.1"
"web3-utils": "1.2.1",
"ethereumjs-tx": "^2.1.1"
}
}
67 changes: 23 additions & 44 deletions packages/web3-eth-accounts/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,20 @@ var Method = require('web3-core-method');
var Promise = require('any-promise');
var Account = require("eth-lib/lib/account");
var Hash = require("eth-lib/lib/hash");
var RLP = require("eth-lib/lib/rlp");
var Nat = require("eth-lib/lib/nat");
var Bytes = require("eth-lib/lib/bytes");
var RLP = require("eth-lib/lib/rlp");// jshint ignore:line
var Bytes = require("eth-lib/lib/bytes");// jshint ignore:line
var cryp = (typeof global === 'undefined') ? require('crypto-browserify') : require('crypto');
var scrypt = require('scrypt-shim');
var uuid = require('uuid');
var utils = require('web3-utils');
var helpers = require('web3-core-helpers');
var Transaction = require('ethereumjs-tx').Transaction;


var isNot = function(value) {
return (_.isUndefined(value) || _.isNull(value));
};

var trimLeadingZero = function (hex) {
while (hex && hex.startsWith('0x0')) {
hex = '0x' + hex.slice(3);
}
return hex;
};

var makeEven = function (hex) {
if(hex.length % 2 === 1) {
hex = hex.replace('0x', '0x0');
}
return hex;
};


var Accounts = function Accounts() {
var _this = this;

Expand Down Expand Up @@ -168,37 +154,30 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
transaction.value = transaction.value || '0x';
transaction.chainId = utils.numberToHex(transaction.chainId);

var rlpEncoded = RLP.encode([
Bytes.fromNat(transaction.nonce),
Bytes.fromNat(transaction.gasPrice),
Bytes.fromNat(transaction.gas),
transaction.to.toLowerCase(),
Bytes.fromNat(transaction.value),
transaction.data,
Bytes.fromNat(transaction.chainId || "0x1"),
"0x",
"0x"]);


var hash = Hash.keccak256(rlpEncoded);
if (privateKey.startsWith('0x')) {
privateKey = privateKey.substring(2);
}

var signature = Account.makeSigner(Nat.toNumber(transaction.chainId || "0x1") * 2 + 35)(Hash.keccak256(rlpEncoded), privateKey);
var ethTx = new Transaction(transaction);
ethTx.sign(Buffer.from(privateKey, 'hex'));

var rawTx = RLP.decode(rlpEncoded).slice(0, 6).concat(Account.decodeSignature(signature));
var validationResult = ethTx.validate(true);

rawTx[6] = makeEven(trimLeadingZero(rawTx[6]));
rawTx[7] = makeEven(trimLeadingZero(rawTx[7]));
rawTx[8] = makeEven(trimLeadingZero(rawTx[8]));
if (validationResult !== '') {
throw new Error('Signer Error: ' + validationResult);
}

var rawTransaction = RLP.encode(rawTx);
var rlpEncoded = ethTx.serialize().toString('hex');
var rawTransaction = '0x' + rlpEncoded;
var transactionHash = utils.keccak256(rawTransaction);

var values = RLP.decode(rawTransaction);
result = {
messageHash: hash,
v: trimLeadingZero(values[6]),
r: trimLeadingZero(values[7]),
s: trimLeadingZero(values[8]),
rawTransaction: rawTransaction
return {
messageHash: '0x' + Buffer.from(ethTx.hash(false)).toString('hex'),
v: '0x' + Buffer.from(ethTx.v).toString('hex'),
r: '0x' + Buffer.from(ethTx.r).toString('hex'),
s: '0x' + Buffer.from(ethTx.s).toString('hex'),
rawTransaction: rawTransaction,
transactionHash: transactionHash
};

} catch(e) {
Expand Down
4 changes: 2 additions & 2 deletions test/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -3026,7 +3026,7 @@ describe('typical usage', function() {
var expected = eth.accounts.wallet[0].signTransaction({
data: '0x1234567000000000000000000000000' + account.address.toLowerCase().replace('0x', '') + '00000000000000000000000000000000000000000000000000000000000000c8',
from: account.address.toLowerCase(),
gas: '0xc350',
gas: '0xd658',
gasPrice: '0xbb8',
chainId: '0x1',
nonce: '0x1',
Expand Down Expand Up @@ -3085,7 +3085,7 @@ describe('typical usage', function() {
arguments: [account.address, 200]
}).send({
from: account.address,
gas: 50000,
gas: 54872,
gasPrice: 3000,
chainId: 1,
nonce: 1,
Expand Down
Loading

0 comments on commit 02c0346

Please sign in to comment.