add support for private sendRawTransaction - merge with latest quorum

This commit is contained in:
namtruong 2018-12-05 14:30:42 +00:00
parent 47954d8a55
commit c49a833eb9
6 changed files with 130 additions and 3 deletions

View File

@ -3,6 +3,8 @@
## Privacy APIs
#### eth.sendTransaction
__To support private transactions in Quorum, the `web3.eth.sendTransaction(object)` API method has been modified.__
```js
@ -50,6 +52,55 @@ web3.eth.sendTransaction({
```
***
#### eth.sendRawPrivateTransaction
__To support sending raw transactions in Quorum, the `web3.eth.sendRawPrivateTransaction(string, object)` API method has been created.__
```js
web3.eth.sendRawPrivateTransaction(signedTransactionData [, privateData] [, callback])
```
Sends an already signed transaction. For example can be signed using: https://github.com/SilentCicero/ethereumjs-accounts
__Important:__ Please note that before calling this API, a `storeraw` api need to be called first to Quorum's private transaction manager. Instructions on how to do this can be found [here](https://github.com/jpmorganchase/tessera/wiki/Interface-&-API).
##### Parameters
1. `String` - Signed transaction data in HEX format
2. `Object` - Private data to send
- `privateFor`: `List<String>` - When sending a private transaction, an array of the recipients' base64-encoded public keys.
3. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. See [this note](#using-callbacks) for details.
##### Returns
`String` - The 32 Bytes transaction hash as HEX string.
If the transaction was a contract creation use [web3.eth.getTransactionReceipt()](#web3ethgettransactionreceipt) to get the contract address, after the transaction was mined.
##### Example
```js
var Tx = require('ethereumjs-tx');
var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex')
var rawTx = {
nonce: '0x00',
gasPrice: '0x09184e72a000',
gasLimit: '0x2710',
to: '0x0000000000000000000000000000000000000000',
value: '0x00',
// This data should be the hex value of the hash returned by Quorum's privacy transaction manager after invoking storeraw api
data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057'
}
var tx = new Tx(rawTx);
tx.sign(privateKey);
var serializedTx = tx.serialize();
//console.log(serializedTx.toString('hex'));
//f889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f
web3.eth.sendRawPrivateTransaction('0x' + serializedTx.toString('hex'), {privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}, function(err, hash) {
if (!err)
console.log(hash); // "0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385"
});
```
## JSON RPC Privacy API Reference
__In addition to the JSON-RPC provided by Ethereum, Quorum exposes below two API calls.__

View File

@ -1168,12 +1168,17 @@ type SendTxArgs struct {
Input *hexutil.Bytes `json:"input"`
//Quorum
PrivateFrom string `json:"privateFrom"`
PrivateFor []string `json:"privateFor"`
PrivateTxType string `json:"restriction"`
PrivateFrom string `json:"privateFrom"`
PrivateFor []string `json:"privateFor"`
PrivateTxType string `json:"restriction"`
//End-Quorum
}
// SendRawTxArgs represents the arguments to submit a new signed private transaction into the transaction pool.
type SendRawTxArgs struct {
PrivateFor []string `json:"privateFor"`
}
// setDefaults is a helper function that fills in default values for unspecified tx fields.
func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
if args.Gas == nil {
@ -1315,6 +1320,33 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
return submitTransaction(ctx, s.b, tx, tx.IsPrivate())
}
// SendRawPrivateTransaction will add the signed transaction to the transaction pool.
// The sender is responsible for signing the transaction and using the correct nonce.
func (s *PublicTransactionPoolAPI) SendRawPrivateTransaction(ctx context.Context, encodedTx hexutil.Bytes, args SendRawTxArgs) (common.Hash, error) {
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err
}
txHash := []byte(tx.Data())
isPrivate := args.PrivateFor != nil
if isPrivate {
if len(txHash) > 0 {
//Send private transaction to privacy manager
log.Info("sending private tx", "data", fmt.Sprintf("%x", txHash), "privatefor", args.PrivateFor)
result, err := private.P.SendSignedTx(txHash, args.PrivateFor)
log.Info("sent private tx", "result", fmt.Sprintf("%x", result), "privatefor", args.PrivateFor)
if err != nil {
return common.Hash{}, err
}
}
}
return submitTransaction(ctx, s.b, tx, isPrivate)
}
// Sign calculates an ECDSA signature for:
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
//
@ -1688,4 +1720,5 @@ func (s *PublicBlockChainAPI) GetQuorumPayload(digestHex string) (string, error)
}
return fmt.Sprintf("0x%x", data), nil
}
//End-Quorum

View File

@ -396,6 +396,12 @@ const Eth_JS = `
web3._extend({
property: 'eth',
methods: [
new web3._extend.Method({
name: 'sendRawPrivateTransaction',
call: 'eth_sendRawPrivateTransaction',
params: 2,
inputFormatter: [null, null]
}),
new web3._extend.Method({
name: 'sign',
call: 'eth_sign',

View File

@ -33,6 +33,18 @@ func (g *Constellation) Send(data []byte, from string, to []string) (out []byte,
return out, nil
}
func (g *Constellation) SendSignedTx(data []byte, to []string) (out []byte, err error) {
if g.isConstellationNotInUse {
return nil, ErrConstellationIsntInit
}
out, err = g.node.SendSignedPayload(data, to)
if err != nil {
return nil, err
}
return out, nil
}
func (g *Constellation) Receive(data []byte) ([]byte, error) {
if g.isConstellationNotInUse {
return nil, nil

View File

@ -106,6 +106,30 @@ func (c *Client) SendPayload(pl []byte, b64From string, b64To []string) ([]byte,
return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, res.Body))
}
func (c *Client) SendSignedPayload(signedPayload []byte, b64To []string) ([]byte, error) {
buf := bytes.NewBuffer(signedPayload)
req, err := http.NewRequest("POST", "http+unix://c/sendsignedtx", buf)
if err != nil {
return nil, err
}
req.Header.Set("c11n-to", strings.Join(b64To, ","))
req.Header.Set("Content-Type", "application/octet-stream")
res, err := c.httpClient.Do(req)
if res != nil {
defer res.Body.Close()
}
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("Non-200 status code: %+v", res)
}
return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, res.Body))
}
func (c *Client) ReceivePayload(key []byte) ([]byte, error) {
req, err := http.NewRequest("GET", "http+unix://c/receiveraw", nil)
if err != nil {

View File

@ -8,6 +8,7 @@ import (
type PrivateTransactionManager interface {
Send(data []byte, from string, to []string) ([]byte, error)
SendSignedTx(data []byte, to []string) ([]byte, error)
Receive(data []byte) ([]byte, error)
}