From 93793cff0bbd7047da4beed6aa00eeb1d18d9806 Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Thu, 20 Sep 2018 12:13:09 +0100 Subject: [PATCH 01/17] Adds the RPC request ID to the context which is passed to called method. Update request/response data structs to include extra fields Refactor the SendTransactionAsync method to just call the SendTransaction method in a goroutine, instead of reimplementing logic for a new transaction. --- internal/ethapi/api.go | 89 ++++++++++++------------------------------ rpc/server.go | 6 ++- 2 files changed, 31 insertions(+), 64 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 65a644e22..bcff5a2f4 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -28,8 +28,6 @@ import ( "encoding/hex" "encoding/json" "net/http" - "sync" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" @@ -1069,8 +1067,11 @@ type SendTxArgs struct { Data hexutil.Bytes `json:"data"` Nonce *hexutil.Uint64 `json:"nonce"` + //Quorum PrivateFrom string `json:"privateFrom"` PrivateFor []string `json:"privateFor"` + PrivateTxType string `json:"restriction"` + //End-Quorum } // prepareSendTxArgs is a helper function that fills in default values for unspecified tx fields. @@ -1095,6 +1096,11 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { } args.Nonce = (*hexutil.Uint64)(&nonce) } + //Quorum + if args.PrivateTxType == "" { + args.PrivateTxType = "restricted" + } + //End-Quorum return nil } @@ -1437,6 +1443,7 @@ func (s *PublicNetAPI) Version() string { return fmt.Sprintf("%d", s.networkVersion) } +// Quorum // Please note: This is a temporary integration to improve performance in high-latency // environments when sending many private transactions. It will be removed at a later // date when account management is handled outside Ethereum. @@ -1447,17 +1454,19 @@ type AsyncSendTxArgs struct { } type AsyncResult struct { - TxHash common.Hash `json:"txHash"` - Error string `json:"error"` + TxHash common.Hash `json:"txHash,omitempty"` + Error string `json:"error,omitempty"` + Id string `json:"id,omitempty"` } -type Async struct { - sync.Mutex - sem chan struct{} -} - -func (a *Async) send(ctx context.Context, s *PublicTransactionPoolAPI, asyncArgs AsyncSendTxArgs) { +func (s *PublicTransactionPoolAPI) send(ctx context.Context, asyncArgs AsyncSendTxArgs) { res := new(AsyncResult) + + //don't need to nil check this since id is required for every geth rpc call + //even though this is stated in the specification as an "optional" parameter + id := ctx.Value("id").(*json.RawMessage) + res.Id = string(*id) + if asyncArgs.CallbackUrl != "" { defer func() { buf := new(bytes.Buffer) @@ -1473,58 +1482,14 @@ func (a *Async) send(ctx context.Context, s *PublicTransactionPoolAPI, asyncArgs } }() } - args := asyncArgs.SendTxArgs - err := args.setDefaults(ctx, s.b) - if err != nil { - log.Info("Async.send: Error doing setDefaults: %v", err) - res.Error = err.Error() - return - } - b, err := private.P.Send([]byte(args.Data), args.PrivateFrom, args.PrivateFor) - if err != nil { - log.Info("Error running Private.P.Send", "err", err) - res.Error = err.Error() - return - } - res.TxHash, err = a.save(ctx, s, args, b) + + var err error + res.TxHash, err = s.SendTransaction(ctx, asyncArgs.SendTxArgs) if err != nil { res.Error = err.Error() } } -func (a *Async) save(ctx context.Context, s *PublicTransactionPoolAPI, args SendTxArgs, data []byte) (common.Hash, error) { - a.Lock() - defer a.Unlock() - if args.Nonce == nil { - nonce, err := s.b.GetPoolNonce(ctx, args.From) - if err != nil { - return common.Hash{}, err - } - args.Nonce = (*hexutil.Uint64)(&nonce) - } - var tx *types.Transaction - if args.To == nil { - tx = types.NewContractCreation((uint64)(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), data) - } else { - tx = types.NewTransaction((uint64)(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), data) - } - - signed, err := s.sign(args.From, tx) - if err != nil { - return common.Hash{}, err - } - - return submitTransaction(ctx, s.b, signed, args.PrivateFor != nil) -} - -func newAsync(n int) *Async { - a := &Async{ - sem: make(chan struct{}, n), - } - return a -} - -var async = newAsync(100) // SendTransactionAsync creates a transaction for the given argument, signs it, and // submits it to the transaction pool. This call returns immediately to allow sending @@ -1537,12 +1502,9 @@ var async = newAsync(100) // Please note: This is a temporary integration to improve performance in high-latency // environments when sending many private transactions. It will be removed at a later // date when account management is handled outside Ethereum. -func (s *PublicTransactionPoolAPI) SendTransactionAsync(ctx context.Context, args AsyncSendTxArgs) { - async.sem <- struct{}{} - go func() { - async.send(ctx, s, args) - <-async.sem - }() +func (s *PublicTransactionPoolAPI) SendTransactionAsync(ctx context.Context, args AsyncSendTxArgs) (common.Hash, error){ + go s.send(ctx, args) + return common.Hash{}, nil } // GetQuorumPayload returns the contents of a private transaction @@ -1569,3 +1531,4 @@ func (s *PublicBlockChainAPI) GetQuorumPayload(digestHex string) (string, error) } return fmt.Sprintf("0x%x", data), nil } +//End-Quorum \ No newline at end of file diff --git a/rpc/server.go b/rpc/server.go index 30c288349..5111c0e84 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -299,9 +299,13 @@ func (s *Server) handle(ctx context.Context, codec ServerCodec, req *serverReque return codec.CreateErrorResponse(&req.id, rpcErr), nil } + //Quorum + //Pass the request ID to the method as part of the context, in case the method needs it later + contextWithId := context.WithValue(ctx, "id", req.id) + //End-Quorum arguments := []reflect.Value{req.callb.rcvr} if req.callb.hasCtx { - arguments = append(arguments, reflect.ValueOf(ctx)) + arguments = append(arguments, reflect.ValueOf(contextWithId)) } if len(req.args) > 0 { arguments = append(arguments, req.args...) From 237bdbace52d8ae9f61d7e6536eda6a9b55cf771 Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Thu, 20 Sep 2018 13:26:12 +0100 Subject: [PATCH 02/17] Rearrange method to remove unneeded goroutine (since we are already in a goroutine at this point) --- internal/ethapi/api.go | 58 +++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index bcff5a2f4..86e1a955c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1453,41 +1453,47 @@ type AsyncSendTxArgs struct { CallbackUrl string `json:"callbackUrl"` } -type AsyncResult struct { - TxHash common.Hash `json:"txHash,omitempty"` - Error string `json:"error,omitempty"` +type AsyncResultSuccess struct { Id string `json:"id,omitempty"` + TxHash common.Hash `json:"txHash"` +} + +type AsyncResultFailure struct { + Id string `json:"id,omitempty"` + Error string `json:"error"` } func (s *PublicTransactionPoolAPI) send(ctx context.Context, asyncArgs AsyncSendTxArgs) { - res := new(AsyncResult) - //don't need to nil check this since id is required for every geth rpc call - //even though this is stated in the specification as an "optional" parameter - id := ctx.Value("id").(*json.RawMessage) - res.Id = string(*id) + txHash, err := s.SendTransaction(ctx, asyncArgs.SendTxArgs) if asyncArgs.CallbackUrl != "" { - defer func() { - buf := new(bytes.Buffer) - err := json.NewEncoder(buf).Encode(res) - if err != nil { - log.Info("Error encoding callback JSON: %v", err) - return - } - _, err = http.Post(asyncArgs.CallbackUrl, "application/json", buf) - if err != nil { - log.Info("Error sending callback: %v", err) - return - } - }() + + //don't need to nil check this since id is required for every geth rpc call + //even though this is stated in the specification as an "optional" parameter + jsonId := ctx.Value("id").(*json.RawMessage) + id := string(*jsonId) + + var resultResponse interface{} + if err != nil { + resultResponse = &AsyncResultFailure{Id: id, Error: err.Error()} + } else { + resultResponse = &AsyncResultSuccess{Id: id, TxHash: txHash} + } + + buf := new(bytes.Buffer) + err := json.NewEncoder(buf).Encode(resultResponse) + if err != nil { + log.Info("Error encoding callback JSON: %v", err) + return + } + _, err = http.Post(asyncArgs.CallbackUrl, "application/json", buf) + if err != nil { + log.Info("Error sending callback: %v", err) + return + } } - var err error - res.TxHash, err = s.SendTransaction(ctx, asyncArgs.SendTxArgs) - if err != nil { - res.Error = err.Error() - } } From 5944ff234691e736faabc36c2bf38ba27e9317ee Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Mon, 1 Oct 2018 10:07:50 +0100 Subject: [PATCH 03/17] Added back the async throttling, fixing an issue where it could block when the channel is full. Now it returns immediately with an error indicating the channel is overloaded. --- internal/ethapi/api.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 86e1a955c..c85afd510 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -23,6 +23,7 @@ import ( "math/big" "strings" "time" + "sync" "bytes" "encoding/hex" @@ -1463,6 +1464,11 @@ type AsyncResultFailure struct { Error string `json:"error"` } +type Async struct { + sync.Mutex + sem chan struct{} +} + func (s *PublicTransactionPoolAPI) send(ctx context.Context, asyncArgs AsyncSendTxArgs) { txHash, err := s.SendTransaction(ctx, asyncArgs.SendTxArgs) @@ -1496,6 +1502,14 @@ func (s *PublicTransactionPoolAPI) send(ctx context.Context, asyncArgs AsyncSend } +func newAsync(n int) *Async { + a := &Async{ + sem: make(chan struct{}, n), + } + return a +} + +var async = newAsync(100) // SendTransactionAsync creates a transaction for the given argument, signs it, and // submits it to the transaction pool. This call returns immediately to allow sending @@ -1509,8 +1523,17 @@ func (s *PublicTransactionPoolAPI) send(ctx context.Context, asyncArgs AsyncSend // environments when sending many private transactions. It will be removed at a later // date when account management is handled outside Ethereum. func (s *PublicTransactionPoolAPI) SendTransactionAsync(ctx context.Context, args AsyncSendTxArgs) (common.Hash, error){ - go s.send(ctx, args) - return common.Hash{}, nil + + select { + case async.sem <- struct{}{}: + go func() { + s.send(ctx, args) + <-async.sem + }() + return common.Hash{}, nil + default: + return common.Hash{}, errors.New("too many concurrent requests") + } } // GetQuorumPayload returns the contents of a private transaction From c3f565db34d9c3dc5fc9e1fdd84c2846b63011ba Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Mon, 1 Oct 2018 10:09:14 +0100 Subject: [PATCH 04/17] Updated import order --- internal/ethapi/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c85afd510..7ac49471a 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -23,12 +23,12 @@ import ( "math/big" "strings" "time" - "sync" - "bytes" "encoding/hex" "encoding/json" "net/http" + "sync" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" From 2474f53efd84c1ea420be3074efa2ad3892fa854 Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Mon, 1 Oct 2018 12:16:31 +0100 Subject: [PATCH 05/17] Add API docs --- docs/api.md | 148 ++++++++++++++++++++++++++++------------- internal/ethapi/api.go | 1 + 2 files changed, 102 insertions(+), 47 deletions(-) diff --git a/docs/api.md b/docs/api.md index 2c2a6c0cf..2923ef9d9 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4,50 +4,103 @@ ## Privacy APIs __To support private transactions in Quorum, the `web3.eth.sendTransaction(object)` API method has been modified.__ - -```js -web3.eth.sendTransaction(transactionObject [, callback]) -``` - -Sends a transaction to the network. - -##### Parameters - -1. `Object` - The transaction object to send: - - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. - - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. - - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. - - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). - - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. - - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. - - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. - - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. - - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. -2. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. - -##### Returns - -`String` - The 32 Bytes transaction hash as HEX string. - -If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. - -##### Example - -```js -// compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ -var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; - -web3.eth.sendTransaction({ - data: code, - privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] - }, - function(err, address) { - if (!err) { - console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" - } - } -}); -``` + + ```js + web3.eth.sendTransaction(transactionObject [, callback]) + ``` + + Sends a transaction to the network. + + ##### Parameters + + 1. `Object` - The transaction object to send: + - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. + - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. + - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. + - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). + - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. + - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. + - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. + - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. + - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. + 2. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. + + ##### Returns + + `String` - The 32 Bytes transaction hash as HEX string. + + If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. + + ##### Example + + ```js + // compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ + var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; + + web3.eth.sendTransaction({ + data: code, + privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] + }, + function(err, address) { + if (!err) { + console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" + } + } + }); + ``` + +--- + +##### eth_sendTransactionAsync + + Sends a transaction to the network asynchronously. This will return immediately, potentially + before the transaction has been submitted to the transaction pool. A callback can be provided + to receive the result of submitting the transaction. + + ##### Parameters + + 1. `Object` - The transaction object to send: + - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. + - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. + - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. + - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). + - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. + - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. + - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. + - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. + - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. + - `callbackUrl`: `String` - (optional) the URL to perform a POST request to to post the result of submitted the transaction + + ##### Returns + + 1. `String` - The empty hash, defined as `0x0000000000000000000000000000000000000000000000000000000000000000` + + The callback URL receives the following object: + + 2. `Object` - The result object: + - `id`: `String` - the identifier in the original RPC call, used to match this result to the request + - `txHash`: `String` - the transaction hash that was generated, if successful + - `error`: `String` - the error that occurred whilst submitting the transaction. + + If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. + + ##### Example + + ```js + // compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ + var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; + + web3.eth.sendTransaction({ + data: code, + privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] + }, + function(err, address) { + if (!err) { + console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" + } + } + }); + ``` *** ## JSON RPC Privacy API Reference @@ -61,7 +114,8 @@ Returns the storage root of given address (Contract/Account etc) ##### Parameters -address, block number (hex) +1. `address`: `String` - The address to fetch the storage root for in hex +2. `block`: `String` - (optional) The block number to look at in hex (e.g. `0x15` for block 21). Uses the latest block if not specified. ##### Returns @@ -99,7 +153,7 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_st // After private state of the contract is changed from '42' to '99' // Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_storageRoot", "params":["0x1349f3e1b8d71effb47b840594ff27da7e603d17","0x2"], "id": 67}' +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc": "2.0", "method": "eth_storageRoot", "params":["0x1349f3e1b8d71effb47b840594ff27da7e603d17", "0x2"], "id": 67}' // Response { @@ -117,7 +171,7 @@ Returns the unencrypted payload from Tessera/constellation ##### Parameters -Transaction payload hash in Hex format +1. `id`: `String` - the HEX formatted generated Sha3-512 hash of the encrypted payload from the Private Transaction Manager. This is seen in the transaction as the `data` field ##### Returns diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7ac49471a..df7e5642b 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -23,6 +23,7 @@ import ( "math/big" "strings" "time" + "bytes" "encoding/hex" "encoding/json" From 87e852ed0d6ed1a891601a2c96facf7e803ab4cf Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Mon, 1 Oct 2018 13:42:08 +0100 Subject: [PATCH 06/17] Updated API docs from comments --- docs/api.md | 105 ++++++++++++++++++++++++++-------------------------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/docs/api.md b/docs/api.md index 2923ef9d9..18482ba1b 100644 --- a/docs/api.md +++ b/docs/api.md @@ -49,58 +49,6 @@ __To support private transactions in Quorum, the `web3.eth.sendTransaction(objec }); ``` ---- - -##### eth_sendTransactionAsync - - Sends a transaction to the network asynchronously. This will return immediately, potentially - before the transaction has been submitted to the transaction pool. A callback can be provided - to receive the result of submitting the transaction. - - ##### Parameters - - 1. `Object` - The transaction object to send: - - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. - - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. - - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. - - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). - - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. - - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. - - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. - - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. - - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. - - `callbackUrl`: `String` - (optional) the URL to perform a POST request to to post the result of submitted the transaction - - ##### Returns - - 1. `String` - The empty hash, defined as `0x0000000000000000000000000000000000000000000000000000000000000000` - - The callback URL receives the following object: - - 2. `Object` - The result object: - - `id`: `String` - the identifier in the original RPC call, used to match this result to the request - - `txHash`: `String` - the transaction hash that was generated, if successful - - `error`: `String` - the error that occurred whilst submitting the transaction. - - If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. - - ##### Example - - ```js - // compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ - var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; - - web3.eth.sendTransaction({ - data: code, - privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] - }, - function(err, address) { - if (!err) { - console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" - } - } - }); - ``` *** ## JSON RPC Privacy API Reference @@ -199,3 +147,56 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ "result": "0x" } ``` + +*** + +#### eth_sendTransactionAsync + + Sends a transaction to the network asynchronously. This will return immediately, potentially + before the transaction has been submitted to the transaction pool. A callback can be provided + to receive the result of submitting the transaction. + + ##### Parameters + + 1. `Object` - The transaction object to send: + - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. + - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. + - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. + - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). + - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. + - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. + - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. + - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. + - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. + - `callbackUrl`: `String` - (optional) the URL to perform a POST request to to post the result of submitted the transaction + + ##### Returns + + 1. `String` - The empty hash, defined as `0x0000000000000000000000000000000000000000000000000000000000000000` + + The callback URL receives the following object: + + 2. `Object` - The result object: + - `id`: `String` - the identifier in the original RPC call, used to match this result to the request + - `txHash`: `String` - the transaction hash that was generated, if successful + - `error`: `String` - the error that occurred whilst submitting the transaction. + + If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. + + ##### Example + + ```js + // compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ + var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; + + web3.eth.sendTransaction({ + data: code, + privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] + }, + function(err, address) { + if (!err) { + console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" + } + } + }); + ``` \ No newline at end of file From 40f7d2b8b4ca772b69c2d35e03eabbfd2b96bb67 Mon Sep 17 00:00:00 2001 From: Nguyen Kien Trung Date: Mon, 1 Oct 2018 14:37:05 -0400 Subject: [PATCH 07/17] Value Transfer in Private Transactions (#538) Fix #528 --- core/tx_pool.go | 4 +-- core/tx_pool_test.go | 66 ++++++++++++++++++++++++++++++++++++------ internal/ethapi/api.go | 33 ++++++++++++--------- 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index 55c7405af..1cac19a83 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -585,8 +585,8 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrNonceTooLow } // Ether value is not currently supported on private transactions - if tx.IsPrivate() && (tx.Value().Sign() != 0) { - return ErrEtherValueUnsupported; + if tx.IsPrivate() && (len(tx.Data()) == 0 || tx.Value().Sign() != 0) { + return ErrEtherValueUnsupported } // Transactor should have enough funds to cover the costs // cost == V + GP * GL diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 84c5dc617..73fe320bd 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -19,8 +19,14 @@ package core import ( "crypto/ecdsa" "fmt" + "io/ioutil" "math/big" + "math/rand" + "os" + "reflect" "testing" + "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -28,11 +34,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" - "math/rand" - "time" - "io/ioutil" - "os" - "reflect" ) // testTxPoolConfig is a transaction pool configuration without stateful disk @@ -281,6 +282,54 @@ func TestQuorumInvalidTransactions(t *testing.T) { } +func TestValidateTx_whenValueZeroTransferForPrivateTransaction(t *testing.T) { + pool, key := setupQuorumTxPool() + defer pool.Stop() + zeroValue := common.Big0 + zeroGasPrice := common.Big0 + defaultTxPoolGasLimit := big.NewInt(1000000) + arbitraryTx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, zeroValue, defaultTxPoolGasLimit, zeroGasPrice, nil), types.HomesteadSigner{}, key) + arbitraryTx.SetPrivate() + + if err := pool.AddRemote(arbitraryTx); err != ErrEtherValueUnsupported { + t.Error("expected:", ErrEtherValueUnsupported, "; got:", err) + } +} + +func TestValidateTx_whenValueNonZeroTransferForPrivateTransaction(t *testing.T) { + pool, key := setupQuorumTxPool() + defer pool.Stop() + arbitraryValue := common.Big3 + arbitraryTx, balance, from := newPrivateTransaction(arbitraryValue, nil, key) + pool.currentState.AddBalance(from, balance) + + if err := pool.AddRemote(arbitraryTx); err != ErrEtherValueUnsupported { + t.Error("expected: ", ErrEtherValueUnsupported, "; got:", err) + } +} + +func newPrivateTransaction(value *big.Int, data []byte, key *ecdsa.PrivateKey) (*types.Transaction, *big.Int, common.Address) { + zeroGasPrice := common.Big0 + defaultTxPoolGasLimit := big.NewInt(1000000) + arbitraryTx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, value, defaultTxPoolGasLimit, zeroGasPrice, data), types.HomesteadSigner{}, key) + arbitraryTx.SetPrivate() + balance := new(big.Int).Add(arbitraryTx.Value(), new(big.Int).Mul(arbitraryTx.Gas(), arbitraryTx.GasPrice())) + from, _ := deriveSender(arbitraryTx) + return arbitraryTx, balance, from +} + +func TestValidateTx_whenValueNonZeroWithSmartContractForPrivateTransaction(t *testing.T) { + pool, key := setupQuorumTxPool() + defer pool.Stop() + arbitraryValue := common.Big3 + arbitraryTx, balance, from := newPrivateTransaction(arbitraryValue, []byte("arbitrary bytecode"), key) + pool.currentState.AddBalance(from, balance) + + if err := pool.AddRemote(arbitraryTx); err != ErrEtherValueUnsupported { + t.Error("expected: ", ErrEtherValueUnsupported, "; got:", err) + } +} + func TestTransactionQueue(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() @@ -1527,9 +1576,9 @@ func benchmarkPoolBatchInsert(b *testing.B, size int) { //Checks that the EIP155 signer is assigned to the TxPool no matter the configuration, even invalid config func TestEIP155SignerOnTxPool(t *testing.T) { var flagtests = []struct { - name string - homesteadBlock *big.Int - eip155Block *big.Int + name string + homesteadBlock *big.Int + eip155Block *big.Int }{ {"hsnileip155nil", nil, nil}, {"hsnileip1550", nil, big.NewInt(0)}, @@ -1567,4 +1616,3 @@ func TestEIP155SignerOnTxPool(t *testing.T) { } } - diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 65a644e22..4c2a1fff8 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -362,12 +362,14 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs data := []byte(args.Data) isPrivate := args.PrivateFor != nil if isPrivate { - log.Info("sending private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor) - data, err = private.P.Send(data, args.PrivateFrom, args.PrivateFor) - log.Info("sent private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor) - if err != nil { - return common.Hash{}, err - } + if len(data) > 0 { + log.Info("sending private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor) + data, err = private.P.Send(data, args.PrivateFrom, args.PrivateFor) + log.Info("sent private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor) + if err != nil { + return common.Hash{}, err + } + } // else tx_pool.go#validateTx will capture and throw error args.Data = data } @@ -1152,13 +1154,15 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen isPrivate := args.PrivateFor != nil if isPrivate { - //Send private transaction to local Constellation node - log.Info("sending private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor) - data, err = private.P.Send(data, args.PrivateFrom, args.PrivateFor) - log.Info("sent private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor) - if err != nil { - return common.Hash{}, err - } + if len(data) > 0 { + //Send private transaction to local Constellation node + log.Info("sending private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor) + data, err = private.P.Send(data, args.PrivateFrom, args.PrivateFor) + log.Info("sent private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor) + if err != nil { + return common.Hash{}, err + } + } // else tx_pool.go#validateTx will capture and throw error args.Data = data } @@ -1239,6 +1243,9 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen if err != nil { return nil, err } + if args.PrivateFor != nil { + tx.SetPrivate() + } data, err := rlp.EncodeToBytes(tx) if err != nil { return nil, err From 2ad2e0b4bf016dc7dafd494fcdfa82a8aff3d1cf Mon Sep 17 00:00:00 2001 From: Jitendra Bhurat Date: Mon, 1 Oct 2018 16:39:01 -0400 Subject: [PATCH 08/17] =?UTF-8?q?Added=20a=20validateConsensus()=20which?= =?UTF-8?q?=20exits=20geth=20if=20no=20consensus=20is=20speci=E2=80=A6=20(?= =?UTF-8?q?#540)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validate for a Quorum supported consensus and exit if no consensus is specified. --- cmd/geth/config.go | 14 ++++++ cmd/geth/consolecmd_test.go | 92 ++++++++++++++++++++++++++++++++----- cmd/geth/main.go | 4 ++ 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 4437cc946..cd634aecf 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -264,3 +264,17 @@ func RegisterRaftService(stack *node.Node, ctx *cli.Context, cfg gethConfig, eth } } + +// quorumValidateConsensus checks if a consensus was used. The node is killed if consensus was not used +func quorumValidateConsensus(stack *node.Node, isRaft bool) { + var ethereum *eth.Ethereum + + err := stack.Service(ðereum) + if err != nil { + utils.Fatalf("Error retrieving Ethereum service: %v", err) + } + + if !isRaft && ethereum.ChainConfig().Istanbul == nil && ethereum.ChainConfig().Clique == nil { + utils.Fatalf("Consensus not specified. Exiting!!") + } +} diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index 258b9e6dd..01b2f4576 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -18,6 +18,7 @@ package main import ( "crypto/rand" + "io/ioutil" "math/big" "os" "path/filepath" @@ -31,18 +32,52 @@ import ( ) const ( - ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0" + ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0" httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" + nodeKey = "b68c0338aa4b266bf38ebe84c6199ae9fac8b29f32998b3ed2fbeafebe8d65c9" ) +var genesis = `{ + "config": { + "chainId": 2017, + "homesteadBlock": 1, + "eip150Block": 2, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 3, + "eip158Block": 3, + "istanbul": { + "epoch": 30000, + "policy": 0 + } + }, + "nonce": "0x0", + "timestamp": "0x0", + "gasLimit": "0x47b760", + "difficulty": "0x1", + "mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "491937757d1b26e29c507b8d4c0b233c2747e68d": { + "balance": "0x446c3b15f9926687d2c40534fdb564000000000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} +` + // Tests that a node embedded within a console can be started up properly and // then terminated by closing the input stream. func TestConsoleWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" + coinbase := "0x491937757d1b26e29c507b8d4c0b233c2747e68d" + + datadir := setupIstanbul(t) + defer os.RemoveAll(datadir) // Start a geth console, make sure it's cleaned up and terminate the console geth := runGeth(t, - "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", + "--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--etherbase", coinbase, "--shh", "console") @@ -72,19 +107,22 @@ at block: 0 ({{niltime}}) // Tests that a console can be attached to a running node via various means. func TestIPCAttachWelcome(t *testing.T) { // Configure the instance for IPC attachement - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" + coinbase := "0x491937757d1b26e29c507b8d4c0b233c2747e68d" var ipc string + + datadir := setupIstanbul(t) + defer os.RemoveAll(datadir) + if runtime.GOOS == "windows" { ipc = `\\.\pipe\geth` + strconv.Itoa(trulyRandInt(100000, 999999)) } else { - ws := tmpdir(t) - defer os.RemoveAll(ws) - ipc = filepath.Join(ws, "geth.ipc") + ipc = filepath.Join(datadir, "geth.ipc") } + // Note: we need --shh because testAttachWelcome checks for default // list of ipc modules and shh is included there. geth := runGeth(t, - "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", + "--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--etherbase", coinbase, "--shh", "--ipcpath", ipc) time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open @@ -95,10 +133,14 @@ func TestIPCAttachWelcome(t *testing.T) { } func TestHTTPAttachWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" + coinbase := "0x491937757d1b26e29c507b8d4c0b233c2747e68d" port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P + + datadir := setupIstanbul(t) + defer os.RemoveAll(datadir) + geth := runGeth(t, - "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", + "--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--etherbase", coinbase, "--rpc", "--rpcport", port) time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open @@ -109,11 +151,14 @@ func TestHTTPAttachWelcome(t *testing.T) { } func TestWSAttachWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" + coinbase := "0x491937757d1b26e29c507b8d4c0b233c2747e68d" port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P + datadir := setupIstanbul(t) + defer os.RemoveAll(datadir) + geth := runGeth(t, - "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", + "--datadir", datadir, "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--etherbase", coinbase, "--ws", "--wsport", port) time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open @@ -161,3 +206,26 @@ func trulyRandInt(lo, hi int) int { num, _ := rand.Int(rand.Reader, big.NewInt(int64(hi-lo))) return int(num.Int64()) + lo } + +// setupIstanbul creates a temporary directory and copies nodekey and genesis.json. +// It initializes istanbul by calling geth init +func setupIstanbul(t *testing.T) string { + datadir := tmpdir(t) + gethPath := filepath.Join(datadir, "geth") + os.Mkdir(gethPath, 0700) + + // Initialize the data directory with the custom genesis block + json := filepath.Join(datadir, "genesis.json") + if err := ioutil.WriteFile(json, []byte(genesis), 0600); err != nil { + t.Fatalf("failed to write genesis file: %v", err) + } + + nodeKeyFile := filepath.Join(gethPath, "nodekey") + if err := ioutil.WriteFile(nodeKeyFile, []byte(nodeKey), 0600); err != nil { + t.Fatalf("failed to write nodekey file: %v", err) + } + + runGeth(t, "--datadir", datadir, "init", json).WaitExit() + + return datadir +} diff --git a/cmd/geth/main.go b/cmd/geth/main.go index bace336bf..7c4c23684 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -216,6 +216,10 @@ func main() { func geth(ctx *cli.Context) error { node := makeFullNode(ctx) startNode(ctx, node) + + // Check if a valid consensus is used + quorumValidateConsensus(node, ctx.GlobalBool(utils.RaftModeFlag.Name)) + node.Wait() return nil } From 05f6cf9bb2ea29bd4b450a7c538f7877b620b941 Mon Sep 17 00:00:00 2001 From: Poh Zi How Date: Wed, 3 Oct 2018 04:38:20 +0800 Subject: [PATCH 09/17] look up IP if host is FQDN (#544) Fixes #147 --- p2p/discover/node.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 711b940e7..0cdadc49a 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -145,7 +145,7 @@ var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$") // // For complete nodes, the node ID is encoded in the username portion // of the URL, separated from the host by an @ sign. The hostname can -// only be given as an IP address, DNS domain names are not allowed. +// be given as an IP address or a DNS domain name. // The port in the host name section is the TCP listening port. If the // TCP and UDP (discovery) ports differ, the UDP port is specified as // query parameter "discport". @@ -192,7 +192,13 @@ func parseComplete(rawurl string) (*Node, error) { return nil, fmt.Errorf("invalid host: %v", err) } if ip = net.ParseIP(host); ip == nil { - return nil, errors.New("invalid IP address") + // attempt to look up IP addresses if host is a FQDN + lookupIPs, err := net.LookupIP(host) + if err != nil { + return nil, errors.New("invalid IP address") + } + // set to first ip by default + ip = lookupIPs[0] } // Ensure the IP is 4 bytes long for IPv4 addresses. if ipv4 := ip.To4(); ipv4 != nil { From f0b629bed8ef726f338d4f938b6d8576bcfb0265 Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Tue, 2 Oct 2018 22:21:14 +0100 Subject: [PATCH 10/17] Updated eth_sendTransactionAsync example --- docs/api.md | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/docs/api.md b/docs/api.md index 18482ba1b..e2675fa85 100644 --- a/docs/api.md +++ b/docs/api.md @@ -183,20 +183,23 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. - ##### Example - - ```js - // compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ - var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; - - web3.eth.sendTransaction({ - data: code, - privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] - }, - function(err, address) { - if (!err) { - console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" - } - } - }); - ``` \ No newline at end of file +##### Example + +``` +// Request + +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xee9d02e382b34818e88b88a309c7fe71e65f419d", "data": "0x603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' + +// Response +{ + "id": 67, + "jsonrpc": "2.0", + "result": "0x0000000000000000000000000000000000000000000000000000000000000000" +} + +// In the callback +{ + "id":67, + "txHash": "0xc3a24a83dc1b4ebb046cc90ffd6b80ac4a6c51d5b810a43f1cabdeabf1dcdc04" +} +``` \ No newline at end of file From d8f3fcad81693315eee5b3077493c8b91cd393db Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Wed, 3 Oct 2018 10:37:46 +0100 Subject: [PATCH 11/17] Add more eth_sendTransactionAsync examples --- docs/api.md | 163 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 109 insertions(+), 54 deletions(-) diff --git a/docs/api.md b/docs/api.md index e2675fa85..50c156d8c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4,51 +4,50 @@ ## Privacy APIs __To support private transactions in Quorum, the `web3.eth.sendTransaction(object)` API method has been modified.__ - - ```js - web3.eth.sendTransaction(transactionObject [, callback]) - ``` - - Sends a transaction to the network. - - ##### Parameters - - 1. `Object` - The transaction object to send: - - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. - - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. - - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. - - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). - - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. - - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. - - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. - - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. - - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. - 2. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. - - ##### Returns - - `String` - The 32 Bytes transaction hash as HEX string. - - If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. - - ##### Example - - ```js - // compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ - var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; - - web3.eth.sendTransaction({ - data: code, - privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] - }, - function(err, address) { - if (!err) { - console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" - } - } - }); - ``` - + +```js +web3.eth.sendTransaction(transactionObject [, callback]) +``` + +Sends a transaction to the network. + +##### Parameters + +1. `Object` - The transaction object to send: + - `from`: `String` - The address for the sending account. Uses the `web3.eth.defaultAccount` property, if not specified. + - `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction. + - `value`: `Number|String|BigNumber` - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. + - `gas`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). + - `gasPrice`: `Number|String|BigNumber` - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price. + - `data`: `String` - (optional) Either a [byte string](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI) containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. + - `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. + - `privateFrom`: `String` - (optional) When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, use the default key as configured in the `TransactionManager`. + - `privateFor`: `List` - (optional) When sending a private transaction, an array of the recipients' base64-encoded public keys. +2. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. + +##### Returns + +`String` - The 32 Bytes transaction hash as HEX string. + +If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. + +##### Example + +```js +// compiled solidity source code using https://chriseth.github.io/cpp-ethereum/ +var code = "603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; + +web3.eth.sendTransaction({ + data: code, + privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] + }, + function(err, address) { + if (!err) { + console.log(address); // "0x7f9fade1c0d57a7af66ab4ead7c2eb7b11a91385" + } + } +}); +``` *** ## JSON RPC Privacy API Reference @@ -152,9 +151,11 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ #### eth_sendTransactionAsync - Sends a transaction to the network asynchronously. This will return immediately, potentially - before the transaction has been submitted to the transaction pool. A callback can be provided - to receive the result of submitting the transaction. + Sends a transaction to the network asynchronously. This will return + immediately, potentially before the transaction has been submitted to the + transaction pool. A callback can be provided to receive the result of + submitting the transaction; a server must be set up to receive POST requests + at the given URL. ##### Parameters @@ -178,17 +179,23 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ 2. `Object` - The result object: - `id`: `String` - the identifier in the original RPC call, used to match this result to the request - - `txHash`: `String` - the transaction hash that was generated, if successful + - `txHash`: `String` - the transaction hash that was generated, if successful - `error`: `String` - the error that occurred whilst submitting the transaction. If the transaction was a contract creation use `web3.eth.getTransactionReceipt()` to get the contract address, after the transaction was mined. ##### Example +For the sake of brevity, the data used for each of the following calls is the simple storage contract, with the bytecode defined as: +`js +var storageData = "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a"; +` + +For the RPC call and the immediate response: + ``` // Request - -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xee9d02e382b34818e88b88a309c7fe71e65f419d", "data": "0x603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": storageData", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' // Response { @@ -197,9 +204,57 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_send "result": "0x0000000000000000000000000000000000000000000000000000000000000000" } + +// Request +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xe2e382b3b8871e65f419d", "data": storageData, "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' + +//If a syntactic error occured with the RPC call. +//In this example the wallet address is the wrong length +//so the error is it cannot convert the parameter to the correct type +//it is NOT an error relating the the address not being managed by this node. + +//Response +{ + "id": 67, + "jsonrpc": "2.0", + "error": { + "code": -32602, + "message": "invalid argument 0: json: cannot unmarshal hex string of odd length into Go struct field AsyncSendTxArgs.from of type common.Address" + } +} +``` + +If the callback URL is provided, the following response will be received after +the transaction has been submitted; this example assumes a webserver that can +be accessed by calling http://localhost:8080 has been set up to accept POST +requests: + +``` + + +// Request +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": storageData, "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="], "callbackUrl": "http://localhost:8080"}], "id":67}' + +// Response +//Note that the ID is the same in the callback as the request - this can be used to match the request to the response. +{ + "id": 67, + "txHash": "0x75ebbf4fbe29355fc8a4b8d1e14ecddf0228b64ef41e6d2fce56047650e2bf17" +} + + + + +// Request +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xae9bc6cd5145e67fbd1887a5145271fd182f0ee7", "callbackUrl": "http://localhost:8080", "data": storageData, "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' + +//If a semantic error occured with the RPC call. +//In this example the wallet address is not managed by the node +//So the RPC call will succeed (giving the empty hash), but the callback will show a failure + // In the callback { - "id":67, - "txHash": "0xc3a24a83dc1b4ebb046cc90ffd6b80ac4a6c51d5b810a43f1cabdeabf1dcdc04" + "id": 67, + "error":"unknown account" } -``` \ No newline at end of file +``` From 37fdc6b2a4202085ca092881d6a3750fd5aac4bf Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Wed, 3 Oct 2018 11:02:52 +0100 Subject: [PATCH 12/17] Update field name --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index 50c156d8c..1e1d7690e 100644 --- a/docs/api.md +++ b/docs/api.md @@ -118,7 +118,7 @@ Returns the unencrypted payload from Tessera/constellation ##### Parameters -1. `id`: `String` - the HEX formatted generated Sha3-512 hash of the encrypted payload from the Private Transaction Manager. This is seen in the transaction as the `data` field +1. `id`: `String` - the HEX formatted generated Sha3-512 hash of the encrypted payload from the Private Transaction Manager. This is seen in the transaction as the `input` field ##### Returns From db8cc814fed929d3e396cd508310e5e1927c1e43 Mon Sep 17 00:00:00 2001 From: dbryan0516 Date: Wed, 3 Oct 2018 20:14:48 -0400 Subject: [PATCH 13/17] Raft Block Signature (#395) Added block signature to raft in the header.Extra field --- raft/backend.go | 3 ++ raft/minter.go | 51 ++++++++++++++++++++++++++++++--- raft/minter_test.go | 69 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 raft/minter_test.go diff --git a/raft/backend.go b/raft/backend.go index a9e328fa1..dc3bd0bac 100644 --- a/raft/backend.go +++ b/raft/backend.go @@ -3,6 +3,7 @@ package raft import ( "sync" "time" + "crypto/ecdsa" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/core" @@ -32,6 +33,7 @@ type RaftService struct { // we need an event mux to instantiate the blockchain eventMux *event.TypeMux minter *minter + nodeKey *ecdsa.PrivateKey } func New(ctx *node.ServiceContext, chainConfig *params.ChainConfig, raftId, raftPort uint16, joinExisting bool, blockTime time.Duration, e *eth.Ethereum, startPeers []*discover.Node, datadir string) (*RaftService, error) { @@ -43,6 +45,7 @@ func New(ctx *node.ServiceContext, chainConfig *params.ChainConfig, raftId, raft accountManager: e.AccountManager(), downloader: e.Downloader(), startPeers: startPeers, + nodeKey: ctx.NodeKey(), } service.minter = newMinter(chainConfig, service, blockTime) diff --git a/raft/minter.go b/raft/minter.go index 5ece9e389..7bb7c2b2a 100644 --- a/raft/minter.go +++ b/raft/minter.go @@ -25,16 +25,22 @@ import ( "github.com/eapache/channels" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" +) + +var ( + extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for arbitrary signer vanity ) // Current state information for building the next block @@ -50,7 +56,7 @@ type minter struct { config *params.ChainConfig mu sync.Mutex mux *event.TypeMux - eth miner.Backend + eth *RaftService chain *core.BlockChain chainDb ethdb.Database coinbase common.Address @@ -66,6 +72,11 @@ type minter struct { txPreSub event.Subscription } +type extraSeal struct { + RaftId []byte // RaftID of the block minter + Signature []byte // Signature of the block minter +} + func newMinter(config *params.ChainConfig, eth *RaftService, blockTime time.Duration) *minter { minter := &minter{ config: config, @@ -318,8 +329,6 @@ func (minter *minter) mintNewBlock() { ethash.AccumulateRewards(minter.chain.Config(), work.publicState, header, nil) header.Root = work.publicState.IntermediateRoot(minter.chain.Config().IsEIP158(work.header.Number)) - // NOTE: < QuorumChain creates a signature here and puts it in header.Extra. > - allReceipts := append(publicReceipts, privateReceipts...) header.Bloom = types.CreateBloom(allReceipts) @@ -330,6 +339,14 @@ func (minter *minter) mintNewBlock() { l.BlockHash = headerHash } + //Sign the block and build the extraSeal struct + extraSealBytes := minter.buildExtraSeal(headerHash) + + // add vanity and seal to header + // NOTE: leaving vanity blank for now as a space for any future data + header.Extra = make([]byte, extraVanity+len(extraSealBytes)) + copy(header.Extra[extraVanity:], extraSealBytes) + block := types.NewBlock(header, committedTxes, nil, publicReceipts) log.Info("Generated next block", "block num", block.Number(), "num txes", txCount) @@ -407,3 +424,29 @@ func (env *work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, g return publicReceipt, privateReceipt, nil } + +func (minter *minter) buildExtraSeal(headerHash common.Hash) []byte { + //Sign the headerHash + nodeKey := minter.eth.nodeKey + sig, err := crypto.Sign(headerHash.Bytes(), nodeKey) + if err != nil { + log.Warn("Block sealing failed", "err", err) + } + + //build the extraSeal struct + raftIdString := hexutil.EncodeUint64(uint64(minter.eth.raftProtocolManager.raftId)) + + var extra extraSeal + extra = extraSeal{ + RaftId: []byte(raftIdString[2:]), //remove the 0x prefix + Signature: sig, + } + + //encode to byte array for storage + extraDataBytes, err := rlp.EncodeToBytes(extra) + if err != nil { + log.Warn("Header.Extra Data Encoding failed", "err", err) + } + + return extraDataBytes +} diff --git a/raft/minter_test.go b/raft/minter_test.go new file mode 100644 index 000000000..dd60d4746 --- /dev/null +++ b/raft/minter_test.go @@ -0,0 +1,69 @@ +package raft + +import ( + "testing" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +func TestSignHeader(t *testing.T){ + //create only what we need to test the seal + var testRaftId uint16 = 5 + config := &node.Config{Name: "unit-test", DataDir: ""} + + nodeKey := config.NodeKey() + + raftProtocolManager := &ProtocolManager{raftId:testRaftId} + raftService := &RaftService{nodeKey: nodeKey, raftProtocolManager: raftProtocolManager} + minter := minter{eth: raftService,} + + //create some fake header to sign + fakeParentHash := common.HexToHash("0xc2c1dc1be8054808c69e06137429899d") + + header := &types.Header{ + ParentHash: fakeParentHash, + Number: big.NewInt(1), + Difficulty: big.NewInt(1), + GasLimit: new(big.Int), + GasUsed: new(big.Int), + Coinbase: minter.coinbase, + Time: big.NewInt(time.Now().UnixNano()), + } + + headerHash := header.Hash() + extraDataBytes := minter.buildExtraSeal(headerHash) + var seal *extraSeal + err := rlp.DecodeBytes(extraDataBytes[:], &seal) + if err != nil { + t.Fatalf("Unable to decode seal: %s", err.Error()) + } + + // Check raftId + sealRaftId, err := hexutil.DecodeUint64("0x"+ string(seal.RaftId)) //add the 0x prefix + if err != nil { + t.Errorf("Unable to get RaftId: %s", err.Error()) + } + if sealRaftId != uint64(testRaftId) { + t.Errorf("RaftID does not match. Expected: %d, Actual: %d", testRaftId, sealRaftId) + } + + //Identify who signed it + sig:= seal.Signature + pubKey, err := crypto.SigToPub(headerHash.Bytes(), sig) + if err != nil { + t.Fatalf("Unable to get public key from signature: %s", err.Error()) + } + + //Compare derived public key to original public key + if pubKey.X.Cmp(nodeKey.X) != 0 { + t.Errorf("Signature incorrect!") + } + +} From 581eed5a0f4776e51b9d0b12fac6a1f9188de4d7 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Fri, 5 Oct 2018 11:39:41 -0400 Subject: [PATCH 14/17] Adding docker hub link --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 17665240b..0e7515c39 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,12 @@ The above diagram is a high-level overview of the privacy architecture used by Q The quickest way to get started with Quorum is by following instructions in the [Quorum Examples](https://github.com/jpmorganchase/quorum-examples) repository. This allows you to quickly create a network of Quorum nodes, and includes a step-by-step demonstration of the privacy features of Quorum. ## Further Reading - Further documentation can be found in the [docs](docs/) folder and on the [wiki](https://github.com/jpmorganchase/quorum/wiki). +## Official Docker Containers +The official docker containers can be found under https://hub.docker.com/u/quorumengineering/ + + ## See also * [Quorum](https://github.com/jpmorganchase/quorum): this repository From 7a282ff4339c447a6a2a19b65991988ec28a94c7 Mon Sep 17 00:00:00 2001 From: Peter Fox Date: Fri, 5 Oct 2018 20:20:18 +0100 Subject: [PATCH 15/17] Inline example data --- docs/api.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/api.md b/docs/api.md index 1e1d7690e..d7e2b84d0 100644 --- a/docs/api.md +++ b/docs/api.md @@ -186,16 +186,11 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_getQ ##### Example -For the sake of brevity, the data used for each of the following calls is the simple storage contract, with the bytecode defined as: -`js -var storageData = "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a"; -` - For the RPC call and the immediate response: ``` // Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": storageData", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' // Response { @@ -206,7 +201,7 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_send // Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xe2e382b3b8871e65f419d", "data": storageData, "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xe2e382b3b8871e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' //If a syntactic error occured with the RPC call. //In this example the wallet address is the wrong length @@ -233,7 +228,7 @@ requests: // Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": storageData, "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="], "callbackUrl": "http://localhost:8080"}], "id":67}' +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="], "callbackUrl": "http://localhost:8080"}], "id":67}' // Response //Note that the ID is the same in the callback as the request - this can be used to match the request to the response. @@ -246,7 +241,7 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_send // Request -curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xae9bc6cd5145e67fbd1887a5145271fd182f0ee7", "callbackUrl": "http://localhost:8080", "data": storageData, "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' +curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0", "method":"eth_sendTransactionAsync", "params":[{"from":"0xae9bc6cd5145e67fbd1887a5145271fd182f0ee7", "callbackUrl": "http://localhost:8080", "data": "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029000000000000000000000000000000000000000000000000000000000000002a", "gas": "0x47b760", "privateFor": ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}], "id":67}' //If a semantic error occured with the RPC call. //In this example the wallet address is not managed by the node From 0d0c507a5945ab63c8441007f022a143e2418f1e Mon Sep 17 00:00:00 2001 From: jpmsam Date: Tue, 16 Oct 2018 16:56:55 -0400 Subject: [PATCH 16/17] Quorum version update --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/version.go b/params/version.go index 1b0306019..e832d86cc 100644 --- a/params/version.go +++ b/params/version.go @@ -28,7 +28,7 @@ const ( QuorumVersionMajor = 2 QuorumVersionMinor = 1 - QuorumVersionPatch = 0 + QuorumVersionPatch = 1 ) // Version holds the textual version string. From 347f6fc356b92f57881b0977ee1e9a859608edf5 Mon Sep 17 00:00:00 2001 From: Nguyen Kien Trung Date: Mon, 22 Oct 2018 15:00:03 -0400 Subject: [PATCH 17/17] Docker: Add git commit hash (#554) --- .dockerignore | 1 - Dockerfile | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 07eab0766..0c013d18b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,3 @@ -**/.git **/*_test.go build/_workspace diff --git a/Dockerfile b/Dockerfile index 2b08a8425..02dabd4bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # Build Geth in a stock Go builder container FROM golang:1.9-alpine as builder -RUN apk add --no-cache make gcc musl-dev linux-headers +RUN apk add --no-cache make gcc musl-dev linux-headers git ADD . /go-ethereum RUN cd /go-ethereum && make geth bootnode