Merge branch 'privateAbigen' of https://github.com/vsmk98/quorum into 1812MergePerm

This commit is contained in:
vsmk98 2018-10-25 02:22:42 +00:00
commit c37530e7d1
12 changed files with 2695 additions and 1 deletions

View File

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
)
@ -82,6 +83,9 @@ type ContractTransactor interface {
EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error)
// SendTransaction injects the transaction into the pending pool for execution.
SendTransaction(ctx context.Context, tx *types.Transaction) error
// PreparePrivateTransaction sends the encoded raw transaction to Constellation,
// returning the encoded commitment transaction.
PreparePrivateTransaction(ctx context.Context, encodedTx hexutil.Bytes, privateFrom string, privateFor []string) (hexutil.Bytes, error)
}
// ContractFilterer defines the methods needed to access log events using one-off

View File

@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
@ -40,6 +41,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/rlp"
)
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
@ -380,8 +382,29 @@ func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethere
}
}), nil
}
// PreparePrivateTransaction replaces the payload data of the transaction with a
// commitment to turn it into a private tx.
func (b *SimulatedBackend) PreparePrivateTransaction(ctx context.Context, encodedTx hexutil.Bytes, privateFrom string, privateFor []string) (hexutil.Bytes, error) {
if len(privateFor) == 0 {
return nil, errors.New("need at least one private for")
}
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return nil, err
}
data := tx.Data()
tx.SetPrivate()
tx.SetData(data)
newEncoded, err := rlp.EncodeToBytes(tx)
if err != nil {
return nil, err
}
return hexutil.Bytes(newEncoded), nil
}
// AdjustTime adds a time shift to the simulated clock.
// JumpTimeInSeconds adds skip seconds to the clock
func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
b.mu.Lock()
defer b.mu.Unlock()

View File

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// SignerFn is a signer function callback when a contract requires a method to
@ -50,6 +51,9 @@ type TransactOpts struct {
Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state)
Signer SignerFn // Method to use for signing the transaction (mandatory)
PrivateFrom string // The public key of the Constellation identity to send this tx from.
PrivateFor []string // The public keys of the Constellation identities this tx is intended for.
Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds)
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
@ -226,13 +230,26 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
return nil, fmt.Errorf("failed to estimate gas needed: %v", err)
}
}
// Create the transaction, sign it and schedule it for execution
// Create the raw transaction.
var rawTx *types.Transaction
if contract == nil {
rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input)
} else {
rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input)
}
// If this transaction is private, we need to substitute the data payload
// with one from constelation.
if len(opts.PrivateFor) > 0 {
rawTx, err = c.preparePrivateTransaction(
ensureContext(opts.Context), rawTx, opts.PrivateFrom, opts.PrivateFor)
if err != nil {
return nil, err
}
}
// Sign the transaction and submit it to the mempool.
if opts.Signer == nil {
return nil, errors.New("no signer to authorize the transaction with")
}
@ -342,6 +359,22 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log)
}
return parseTopics(out, indexed, log.Topics[1:])
}
// PreparePrivateTransaction replaces the payload data of the transaction with a
// commitment to turn it into a private tx.
func (c *BoundContract) preparePrivateTransaction(ctx context.Context, tx *types.Transaction, privateFrom string, privateFor []string) (*types.Transaction, error) {
raw, _ := rlp.EncodeToBytes(tx)
privTxBytes, err := c.transactor.PreparePrivateTransaction(ctx, raw, privateFrom, privateFor)
if err != nil {
return nil, err
}
tx = new(types.Transaction)
if err := rlp.DecodeBytes(privTxBytes, tx); err != nil {
return nil, err
}
return tx, nil
}
// ensureContext is a helper method to ensure a context is not nil, even if the
// user specified it as such.

7
accounts/abi/bind/doc.md Normal file
View File

@ -0,0 +1,7 @@
# Abigen with Quorum
Abigen is a source code generator that converts quorum abi definitions into type-safe Go packages. In addition to the original capabilities provided by Ethereum described [here](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) Quorum abigen also supports deploying private transactions.
PrivateFrom and PrivateFor fields have been added to the *bind.TransactOpts type which allows users to specify the public keys of the Constellation identity used to send and receive transactions.
When using the PrivateFrom and PrivateFor fields, the "PRIVATE_CONFIG" environment variable must be set to point to the running constellation node's .ipc file and this node much match the public key set in the PrivateFrom field. If not, deploying the private contract will fail.

View File

@ -0,0 +1,20 @@
# Swarm ENS interface
## Usage
Full documentation for the Ethereum Name Service [can be found as EIP 137](https://github.com/ethereum/EIPs/issues/137).
This package offers a simple binding that streamlines the registration of arbitrary UTF8 domain names to swarm content hashes.
## Development
The SOL file in contract subdirectory implements the ENS root registry, a simple
first-in, first-served registrar for the root namespace, and a simple resolver contract;
they're used in tests, and can be used to deploy these contracts for your own purposes.
The solidity source code can be found at [github.com/arachnid/ens/](https://github.com/arachnid/ens/).
The go bindings for ENS contracts are generated using `abigen` via the go generator:
```shell
go generate ./contracts/ens
```

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,226 @@
// Ethereum Name Service contracts by Nick Johnson <nick@ethereum.org>
//
// To the extent possible under law, the person who associated CC0 with
// ENS contracts has waived all copyright and related or neighboring rights
// to ENS.
//
// You should have received a copy of the CC0 legalcode along with this
// work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
/**
* The ENS registry contract.
*/
contract ENS {
struct Record {
address owner;
address resolver;
}
mapping(bytes32=>Record) records;
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the owner of a node changes the resolver for that node.
event NewResolver(bytes32 indexed node, address resolver);
// Permits modifications only by the owner of the specified node.
modifier only_owner(bytes32 node) {
if(records[node].owner != msg.sender) throw;
_;
}
/**
* Constructs a new ENS registrar, with the provided address as the owner of the root node.
*/
function ENS(address owner) {
records[0].owner = owner;
}
/**
* Returns the address that owns the specified node.
*/
function owner(bytes32 node) constant returns (address) {
return records[node].owner;
}
/**
* Returns the address of the resolver for the specified node.
*/
function resolver(bytes32 node) constant returns (address) {
return records[node].resolver;
}
/**
* Transfers ownership of a node to a new address. May only be called by the current
* owner of the node.
* @param node The node to transfer ownership of.
* @param owner The address of the new owner.
*/
function setOwner(bytes32 node, address owner) only_owner(node) {
Transfer(node, owner);
records[node].owner = owner;
}
/**
* Transfers ownership of a subnode sha3(node, label) to a new address. May only be
* called by the owner of the parent node.
* @param node The parent node.
* @param label The hash of the label specifying the subnode.
* @param owner The address of the new owner.
*/
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) only_owner(node) {
var subnode = sha3(node, label);
NewOwner(node, label, owner);
records[subnode].owner = owner;
}
/**
* Sets the resolver address for the specified node.
* @param node The node to update.
* @param resolver The address of the resolver.
*/
function setResolver(bytes32 node, address resolver) only_owner(node) {
NewResolver(node, resolver);
records[node].resolver = resolver;
}
}
/**
* A registrar that allocates subdomains to the first person to claim them. It also deploys
* a simple resolver contract and sets that as the default resolver on new names for
* convenience.
*/
contract FIFSRegistrar {
ENS ens;
PublicResolver defaultResolver;
bytes32 rootNode;
/**
* Constructor.
* @param ensAddr The address of the ENS registry.
* @param node The node that this registrar administers.
*/
function FIFSRegistrar(address ensAddr, bytes32 node) {
ens = ENS(ensAddr);
defaultResolver = new PublicResolver(ensAddr);
rootNode = node;
}
/**
* Register a name, or change the owner of an existing registration.
* @param subnode The hash of the label to register.
* @param owner The address of the new owner.
*/
function register(bytes32 subnode, address owner) {
var node = sha3(rootNode, subnode);
var currentOwner = ens.owner(node);
if(currentOwner != 0 && currentOwner != msg.sender)
throw;
// Temporarily set ourselves as the owner
ens.setSubnodeOwner(rootNode, subnode, this);
// Set up the default resolver
ens.setResolver(node, defaultResolver);
// Set the owner to the real owner
ens.setOwner(node, owner);
}
}
contract Resolver {
event AddrChanged(bytes32 indexed node, address a);
event ContentChanged(bytes32 indexed node, bytes32 hash);
function has(bytes32 node, bytes32 kind) returns (bool);
function addr(bytes32 node) constant returns (address ret);
function content(bytes32 node) constant returns (bytes32 ret);
}
/**
* A simple resolver anyone can use; only allows the owner of a node to set its
* address.
*/
contract PublicResolver is Resolver {
ENS ens;
mapping(bytes32=>address) addresses;
mapping(bytes32=>bytes32) contents;
modifier only_owner(bytes32 node) {
if(ens.owner(node) != msg.sender) throw;
_;
}
/**
* Constructor.
* @param ensAddr The ENS registrar contract.
*/
function PublicResolver(address ensAddr) {
ens = ENS(ensAddr);
}
/**
* Fallback function.
*/
function() {
throw;
}
/**
* Returns true if the specified node has the specified record type.
* @param node The ENS node to query.
* @param kind The record type name, as specified in EIP137.
* @return True if this resolver has a record of the provided type on the
* provided node.
*/
function has(bytes32 node, bytes32 kind) returns (bool) {
return (kind == "addr" && addresses[node] != 0) ||
(kind == "content" && contents[node] != 0);
}
/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/
function addr(bytes32 node) constant returns (address ret) {
ret = addresses[node];
if(ret == 0)
throw;
}
/**
* Returns the content hash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated content hash.
*/
function content(bytes32 node) constant returns (bytes32 ret) {
ret = contents[node];
if(ret == 0)
throw;
}
/**
* Sets the address associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param addr The address to set.
*/
function setAddr(bytes32 node, address addr) only_owner(node) {
addresses[node] = addr;
AddrChanged(node, addr);
}
/**
* Sets the content hash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param hash The content hash to set.
*/
function setContent(bytes32 node, bytes32 hash) only_owner(node) {
contents[node] = hash;
ContentChanged(node, hash);
}
}

View File

@ -0,0 +1,182 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package ens
//go:generate abigen --sol contract/ens.sol --pkg contract --out contract/ens.go
import (
"strings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/contracts/ens_private/contract"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
)
var (
MainNetAddress = common.HexToAddress("0x314159265dD8dbb310642f98f50C066173C1259b")
TestNetAddress = common.HexToAddress("0x112234455c3a32fd11230c42e7bccd4a84e02010")
)
// swarm domain name registry and resolver
type ENS struct {
*contract.ENSSession
contractBackend bind.ContractBackend
}
// NewENS creates a struct exposing convenient high-level operations for interacting with
// the Ethereum Name Service.
func NewENS(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*ENS, error) {
ens, err := contract.NewENS(contractAddr, contractBackend)
if err != nil {
return nil, err
}
return &ENS{
&contract.ENSSession{
Contract: ens,
TransactOpts: *transactOpts,
},
contractBackend,
}, nil
}
// DeployENS deploys an instance of the ENS nameservice, with a 'first-in, first-served' root registrar.
func DeployENS(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend) (*ENS, error) {
// Deploy the ENS registry
ensAddr, _, _, err := contract.DeployENS(transactOpts, contractBackend, transactOpts.From)
if err != nil {
return nil, err
}
ens, err := NewENS(transactOpts, ensAddr, contractBackend)
if err != nil {
return nil, err
}
// Deploy the registrar
regAddr, _, _, err := contract.DeployFIFSRegistrar(transactOpts, contractBackend, ensAddr, [32]byte{})
if err != nil {
return nil, err
}
// Set the registrar as owner of the ENS root
_, err = ens.SetOwner([32]byte{}, regAddr)
if err != nil {
return nil, err
}
return ens, nil
}
func ensParentNode(name string) (common.Hash, common.Hash) {
parts := strings.SplitN(name, ".", 2)
label := crypto.Keccak256Hash([]byte(parts[0]))
if len(parts) == 1 {
return [32]byte{}, label
} else {
parentNode, parentLabel := ensParentNode(parts[1])
return crypto.Keccak256Hash(parentNode[:], parentLabel[:]), label
}
}
func ensNode(name string) common.Hash {
parentNode, parentLabel := ensParentNode(name)
return crypto.Keccak256Hash(parentNode[:], parentLabel[:])
}
func (self *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) {
resolverAddr, err := self.Resolver(node)
if err != nil {
return nil, err
}
resolver, err := contract.NewPublicResolver(resolverAddr, self.contractBackend)
if err != nil {
return nil, err
}
return &contract.PublicResolverSession{
Contract: resolver,
TransactOpts: self.TransactOpts,
}, nil
}
func (self *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) {
registrarAddr, err := self.Owner(node)
if err != nil {
return nil, err
}
registrar, err := contract.NewFIFSRegistrar(registrarAddr, self.contractBackend)
if err != nil {
return nil, err
}
return &contract.FIFSRegistrarSession{
Contract: registrar,
TransactOpts: self.TransactOpts,
}, nil
}
// Resolve is a non-transactional call that returns the content hash associated with a name.
func (self *ENS) Resolve(name string) (common.Hash, error) {
node := ensNode(name)
resolver, err := self.getResolver(node)
if err != nil {
return common.Hash{}, err
}
ret, err := resolver.Content(node)
if err != nil {
return common.Hash{}, err
}
return common.BytesToHash(ret[:]), nil
}
// Register registers a new domain name for the caller, making them the owner of the new name.
// Only works if the registrar for the parent domain implements the FIFS registrar protocol.
func (self *ENS) Register(name string) (*types.Transaction, error) {
parentNode, label := ensParentNode(name)
registrar, err := self.getRegistrar(parentNode)
if err != nil {
return nil, err
}
opts := self.TransactOpts
opts.GasLimit = 200000
return registrar.Contract.Register(&opts, label, self.TransactOpts.From)
}
// SetContentHash sets the content hash associated with a name. Only works if the caller
// owns the name, and the associated resolver implements a `setContent` function.
func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) {
node := ensNode(name)
resolver, err := self.getResolver(node)
if err != nil {
return nil, err
}
opts := self.TransactOpts
opts.GasLimit = 200000
return resolver.Contract.SetContent(&opts, node, hash)
}

View File

@ -0,0 +1,74 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package ens
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
)
var (
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
name = "my name on ENS"
hash = crypto.Keccak256Hash([]byte("my content"))
addr = crypto.PubkeyToAddress(key.PublicKey)
)
func TestENS(t *testing.T) {
contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}})
transactOpts := bind.NewKeyedTransactor(key)
// Workaround for bug estimating gas in the call to Register
transactOpts.GasLimit = 1000000
//set privacy fields
privateFrom := "BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo="
privateFor := make([]string, 2)
privateFor[0] = "ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="
privateFor[1] = "QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc="
transactOpts.PrivateFrom = privateFrom
transactOpts.PrivateFor = privateFor
ens, err := DeployENS(transactOpts, contractBackend)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
contractBackend.Commit()
_, err = ens.Register(name)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
contractBackend.Commit()
_, err = ens.SetContentHash(name, hash)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
contractBackend.Commit()
vhost, err := ens.Resolve(name)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if vhost != hash {
t.Fatalf("resolve error, expected %v, got %v", hash.Hex(), vhost.Hex())
}
}

View File

@ -181,6 +181,10 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) }
func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit }
func (tx *Transaction) SetData(data []byte) {
tx.data.Payload = common.CopyBytes(data)
}
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }

168
eth/bind.go Normal file
View File

@ -0,0 +1,168 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package eth
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/private"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
)
// ContractBackend implements bind.ContractBackend with direct calls to Ethereum
// internals to support operating on contracts within subprotocols like eth and
// swarm.
//
// Internally this backend uses the already exposed API endpoints of the Ethereum
// object. These should be rewritten to internal Go method calls when the Go API
// is refactored to support a clean library use.
type ContractBackend struct {
eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata
bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data
txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data
}
// NewContractBackend creates a new native contract backend using an existing
// Ethereum object.
func NewContractBackend(apiBackend ethapi.Backend) *ContractBackend {
return &ContractBackend{
eapi: ethapi.NewPublicEthereumAPI(apiBackend),
bcapi: ethapi.NewPublicBlockChainAPI(apiBackend),
txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend, new(ethapi.AddrLocker)),
}
}
// CodeAt retrieves any code associated with the contract from the local API.
func (b *ContractBackend) CodeAt(ctx context.Context, contract common.Address, blockNum *big.Int) ([]byte, error) {
return b.bcapi.GetCode(ctx, contract, toBlockNumber(blockNum))
}
// CodeAt retrieves any code associated with the contract from the local API.
func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) {
return b.bcapi.GetCode(ctx, contract, rpc.PendingBlockNumber)
}
// ContractCall implements bind.ContractCaller executing an Ethereum contract
// call with the specified data as the input. The pending flag requests execution
// against the pending block, not the stable head of the chain.
func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int) ([]byte, error) {
out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(blockNum))
return out, err
}
// ContractCall implements bind.ContractCaller executing an Ethereum contract
// call with the specified data as the input. The pending flag requests execution
// against the pending block, not the stable head of the chain.
func (b *ContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) {
out, err := b.bcapi.Call(ctx, toCallArgs(msg), rpc.PendingBlockNumber)
return out, err
}
func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs {
args := ethapi.CallArgs{
To: msg.To,
From: msg.From,
Data: msg.Data,
Gas: hexutil.Uint64(msg.Gas),
}
if msg.GasPrice != nil {
args.GasPrice = hexutil.Big(*msg.GasPrice)
}
if msg.Value != nil {
args.Value = hexutil.Big(*msg.Value)
}
return args
}
func toBlockNumber(num *big.Int) rpc.BlockNumber {
if num == nil {
return rpc.LatestBlockNumber
}
return rpc.BlockNumber(num.Int64())
}
// PendingAccountNonce implements bind.ContractTransactor retrieving the current
// pending nonce associated with an account.
func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (nonce uint64, err error) {
out, err := b.txapi.GetTransactionCount(ctx, account, rpc.PendingBlockNumber)
if out != nil {
nonce = uint64(*out)
}
return nonce, err
}
// SuggestGasPrice implements bind.ContractTransactor retrieving the currently
// suggested gas price to allow a timely execution of a transaction.
func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
price, error := b.eapi.GasPrice(ctx)
return price.ToInt(), error
}
// EstimateGasLimit implements bind.ContractTransactor triing to estimate the gas
// needed to execute a specific transaction based on the current pending state of
// the backend blockchain. There is no guarantee that this is the true gas limit
// requirement as other transactions may be added or removed by miners, but it
// should provide a basis for setting a reasonable default.
func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) {
out, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg))
return new(big.Int).SetUint64(uint64(out)), err
}
// SendTransaction implements bind.ContractTransactor injects the transaction
// into the pending pool for execution.
func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
raw, _ := rlp.EncodeToBytes(tx)
_, err := b.txapi.SendRawTransaction(ctx, raw)
return err
}
// PreparePrivateTransaction sends the encoded raw transaction to Constellation,
// returning the encoded commitment transaction.
func (b *ContractBackend) PreparePrivateTransaction(ctx context.Context, encodedTx hexutil.Bytes, privateFrom string, privateFor []string) (hexutil.Bytes, error) {
if len(privateFor) == 0 {
return nil, errors.New("need at least one private for")
}
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return nil, err
}
if private.P == nil {
return nil, errors.New("constellation not set up")
}
data, err := private.P.Send(tx.Data(), privateFrom, privateFor)
if err != nil {
return nil, err
}
tx.SetPrivate()
tx.SetData(data)
newEncoded, err := rlp.EncodeToBytes(tx)
if err != nil {
return nil, err
}
return hexutil.Bytes(newEncoded), nil
}

View File

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/private"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/log"
@ -492,6 +493,35 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er
return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", common.ToHex(data))
}
// PreparePrivateTransaction sends the encoded raw transaction to Constellation,
// returning the encoded commitment transaction.
func (ec *Client) PreparePrivateTransaction(ctx context.Context, encodedTx hexutil.Bytes, privateFrom string, privateFor []string) (hexutil.Bytes, error) {
if len(privateFor) == 0 {
return nil, errors.New("need at least one private for")
}
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return nil, err
}
if private.P == nil {
return nil, errors.New("constellation not set up")
}
data, err := private.P.Send(tx.Data(), privateFrom, privateFor)
if err != nil {
return nil, err
}
tx.SetPrivate()
tx.SetData(data)
newEncoded, err := rlp.EncodeToBytes(tx)
if err != nil {
return nil, err
}
return hexutil.Bytes(newEncoded), nil
}
func toCallArg(msg ethereum.CallMsg) interface{} {
arg := map[string]interface{}{
"from": msg.From,