mirror of https://github.com/poanetwork/quorum.git
add support for private sendRawTransaction - merge with latest quorum
This commit is contained in:
parent
47954d8a55
commit
c49a833eb9
51
docs/api.md
51
docs/api.md
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
## Privacy APIs
|
## Privacy APIs
|
||||||
|
|
||||||
|
#### eth.sendTransaction
|
||||||
|
|
||||||
__To support private transactions in Quorum, the `web3.eth.sendTransaction(object)` API method has been modified.__
|
__To support private transactions in Quorum, the `web3.eth.sendTransaction(object)` API method has been modified.__
|
||||||
|
|
||||||
```js
|
```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
|
## JSON RPC Privacy API Reference
|
||||||
|
|
||||||
__In addition to the JSON-RPC provided by Ethereum, Quorum exposes below two API calls.__
|
__In addition to the JSON-RPC provided by Ethereum, Quorum exposes below two API calls.__
|
||||||
|
|
|
@ -1168,12 +1168,17 @@ type SendTxArgs struct {
|
||||||
Input *hexutil.Bytes `json:"input"`
|
Input *hexutil.Bytes `json:"input"`
|
||||||
|
|
||||||
//Quorum
|
//Quorum
|
||||||
PrivateFrom string `json:"privateFrom"`
|
PrivateFrom string `json:"privateFrom"`
|
||||||
PrivateFor []string `json:"privateFor"`
|
PrivateFor []string `json:"privateFor"`
|
||||||
PrivateTxType string `json:"restriction"`
|
PrivateTxType string `json:"restriction"`
|
||||||
//End-Quorum
|
//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.
|
// setDefaults is a helper function that fills in default values for unspecified tx fields.
|
||||||
func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
|
func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
|
||||||
if args.Gas == nil {
|
if args.Gas == nil {
|
||||||
|
@ -1315,6 +1320,33 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
|
||||||
return submitTransaction(ctx, s.b, tx, tx.IsPrivate())
|
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:
|
// Sign calculates an ECDSA signature for:
|
||||||
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
|
// 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
|
return fmt.Sprintf("0x%x", data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//End-Quorum
|
//End-Quorum
|
||||||
|
|
|
@ -396,6 +396,12 @@ const Eth_JS = `
|
||||||
web3._extend({
|
web3._extend({
|
||||||
property: 'eth',
|
property: 'eth',
|
||||||
methods: [
|
methods: [
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'sendRawPrivateTransaction',
|
||||||
|
call: 'eth_sendRawPrivateTransaction',
|
||||||
|
params: 2,
|
||||||
|
inputFormatter: [null, null]
|
||||||
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'sign',
|
name: 'sign',
|
||||||
call: 'eth_sign',
|
call: 'eth_sign',
|
||||||
|
|
|
@ -33,6 +33,18 @@ func (g *Constellation) Send(data []byte, from string, to []string) (out []byte,
|
||||||
return out, nil
|
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) {
|
func (g *Constellation) Receive(data []byte) ([]byte, error) {
|
||||||
if g.isConstellationNotInUse {
|
if g.isConstellationNotInUse {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -106,6 +106,30 @@ func (c *Client) SendPayload(pl []byte, b64From string, b64To []string) ([]byte,
|
||||||
return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, res.Body))
|
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) {
|
func (c *Client) ReceivePayload(key []byte) ([]byte, error) {
|
||||||
req, err := http.NewRequest("GET", "http+unix://c/receiveraw", nil)
|
req, err := http.NewRequest("GET", "http+unix://c/receiveraw", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
type PrivateTransactionManager interface {
|
type PrivateTransactionManager interface {
|
||||||
Send(data []byte, from string, to []string) ([]byte, error)
|
Send(data []byte, from string, to []string) ([]byte, error)
|
||||||
|
SendSignedTx(data []byte, to []string) ([]byte, error)
|
||||||
Receive(data []byte) ([]byte, error)
|
Receive(data []byte) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue