mirror of https://github.com/poanetwork/quorum.git
Merge remote-tracking branch 'remotes/saiv/1812MergePerm' into 1812-permission-rpc-api
This commit is contained in:
commit
20b137bfb1
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -7,15 +7,15 @@ import (
|
|||
"github.com/ethereum/go-ethereum/node"
|
||||
)
|
||||
// Create an RPC client for the contract interface
|
||||
func CreateEthClient(stack *node.Node ) (*ethclient.Client, error){
|
||||
func CreateEthClient(stack *node.Node ) (*ethclient.Client, *eth.Ethereum, error){
|
||||
var e *eth.Ethereum
|
||||
if err := stack.Service(&e); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rpcClient, err := stack.Attach()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
return ethclient.NewClient(rpcClient), nil
|
||||
return ethclient.NewClient(rpcClient), e, nil
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
// the permissiones contract deployed as a precompile via genesis.json
|
||||
func ManageOrgKeys(ctx *cli.Context, stack *node.Node ) error {
|
||||
// Create a new ethclient to for interfacing with the contract
|
||||
stateReader, err := controls.CreateEthClient(stack)
|
||||
stateReader, _, err := controls.CreateEthClient(stack)
|
||||
if err != nil {
|
||||
log.Error ("Unable to create ethereum client for cluster check : ", "err" , err)
|
||||
return err
|
||||
|
|
|
@ -30,6 +30,9 @@ contract Permissions {
|
|||
// valid vote count
|
||||
mapping (uint => uint) private voteCount;
|
||||
|
||||
// checks if firts time network boot up has happened or not
|
||||
bool networkBoot = false;
|
||||
|
||||
// node permission events for new node propose
|
||||
event NodeProposed(string _enodeId);
|
||||
event NodeApproved(string _enodeId, string _ipAddrPort, string _discPort, string _raftPort);
|
||||
|
@ -130,22 +133,34 @@ contract Permissions {
|
|||
}
|
||||
|
||||
// state change functions
|
||||
// update the networ boot status as true
|
||||
function updateNetworkBootStatus() external {
|
||||
require (networkBoot == false, "Invalid call: Network boot up completed");
|
||||
networkBoot = true;
|
||||
}
|
||||
|
||||
// propose a new node to the network
|
||||
function proposeNode(string _enodeId, string _ipAddrPort, string _discPort, string _raftPort) external enodeNotInList(_enodeId)
|
||||
{
|
||||
if (checkVotingAccountExist()){
|
||||
// increment node number, add node to the list
|
||||
if (!(networkBoot)){
|
||||
numberOfNodes++;
|
||||
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
|
||||
nodeList.push(NodeDetails(_enodeId, _ipAddrPort,_discPort, _raftPort, NodeStatus.PendingApproval));
|
||||
// add voting status, numberOfNodes is the index of current proposed node
|
||||
for (uint i = 0; i < accountList.length; i++){
|
||||
voteStatus[numberOfNodes][accountList[i]] = false;
|
||||
nodeList.push(NodeDetails(_enodeId, _ipAddrPort,_discPort, _raftPort, NodeStatus.Approved));
|
||||
}
|
||||
else {
|
||||
if (checkVotingAccountExist()){
|
||||
// increment node number, add node to the list
|
||||
numberOfNodes++;
|
||||
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
|
||||
nodeList.push(NodeDetails(_enodeId, _ipAddrPort,_discPort, _raftPort, NodeStatus.PendingApproval));
|
||||
// add voting status, numberOfNodes is the index of current proposed node
|
||||
for (uint i = 0; i < accountList.length; i++){
|
||||
voteStatus[numberOfNodes][accountList[i]] = false;
|
||||
}
|
||||
voteCount[numberOfNodes] = 0;
|
||||
// emit event
|
||||
emit NodeProposed(_enodeId);
|
||||
}
|
||||
voteCount[numberOfNodes] = 0;
|
||||
// emit event
|
||||
emit NodeProposed(_enodeId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,18 +1,23 @@
|
|||
package permissions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"math/big"
|
||||
"os"
|
||||
"sync"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/controls"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
|
@ -40,7 +45,7 @@ func SayHello(n string) string{
|
|||
// the permissiones contract deployed as a precompile via genesis.json
|
||||
func QuorumPermissioning(ctx *cli.Context, stack *node.Node ) error {
|
||||
// Create a new ethclient to for interfacing with the contract
|
||||
stateReader, err := controls.CreateEthClient(stack)
|
||||
stateReader, e, err := controls.CreateEthClient(stack)
|
||||
if err != nil {
|
||||
log.Error ("Unable to create ethereum client for permissions check : ", "err" , err)
|
||||
return err
|
||||
|
@ -56,7 +61,7 @@ func QuorumPermissioning(ctx *cli.Context, stack *node.Node ) error {
|
|||
consensusEngine = RAFT
|
||||
}
|
||||
// Monitors node addition and decativation from network
|
||||
manageNodePermissions(stack, stateReader, consensusEngine);
|
||||
manageNodePermissions(ctx, stack, e, stateReader, consensusEngine);
|
||||
|
||||
// Monitors account level persmissions update from smart contarct
|
||||
manageAccountPermissions(stack, stateReader);
|
||||
|
@ -66,7 +71,11 @@ func QuorumPermissioning(ctx *cli.Context, stack *node.Node ) error {
|
|||
|
||||
|
||||
// Manages node addition and decavtivation from network
|
||||
func manageNodePermissions(stack *node.Node, stateReader *ethclient.Client, consensusEngine string) {
|
||||
func manageNodePermissions(ctx *cli.Context, stack *node.Node, e *eth.Ethereum, stateReader *ethclient.Client, consensusEngine string) {
|
||||
// populate the initial list of nodes into the smart contract
|
||||
// from permissioned-nodes.json
|
||||
populateNodesToContract(ctx, stack, e, stateReader)
|
||||
|
||||
//monitor for new nodes addition via smart contract
|
||||
go monitorNewNodeAdd(stack, stateReader, consensusEngine)
|
||||
|
||||
|
@ -343,10 +352,103 @@ func disconnectNode (stack *node.Node, enodeId, consensusEngine string){
|
|||
}
|
||||
|
||||
// helper function to format EnodeId
|
||||
// This will format the EnodeId and return
|
||||
func formatEnodeId( enodeId , ipAddrPort, discPort, raftPort, consensusEngine string) string {
|
||||
newEnodeId := "enode://" + enodeId + "@" + ipAddrPort + "?discPort=" + discPort
|
||||
if consensusEngine == RAFT {
|
||||
newEnodeId = enodeId + "&raftport=" + raftPort
|
||||
newEnodeId += "&raftport=" + raftPort
|
||||
}
|
||||
return newEnodeId
|
||||
}
|
||||
//populates the nodes list from permissioned-nodes.json into the permissions
|
||||
//smart contract
|
||||
func populateNodesToContract(ctx *cli.Context, stack *node.Node, e *eth.Ethereum, stateReader *ethclient.Client){
|
||||
|
||||
log.Info("SMK - inside populateNodesToContract @363")
|
||||
//Read the key file from key store. SHOULD WE MAKE IT CONFIG value
|
||||
key := getKeyFromKeyStore(ctx)
|
||||
|
||||
permissionsContract, err := NewPermissions(params.QuorumPermissionsContract, stateReader)
|
||||
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to instantiate a Permissions contract: %v", err)
|
||||
}
|
||||
auth, err := bind.NewTransactor(strings.NewReader(key), "")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to create authorized transactor: %v", err)
|
||||
}
|
||||
|
||||
permissionsSession := &PermissionsSession{
|
||||
Contract: permissionsContract,
|
||||
CallOpts: bind.CallOpts{
|
||||
Pending: true,
|
||||
},
|
||||
TransactOpts: bind.TransactOpts{
|
||||
From: auth.From,
|
||||
Signer: auth.Signer,
|
||||
GasLimit: 3558096384,
|
||||
GasPrice: big.NewInt(0),
|
||||
},
|
||||
}
|
||||
|
||||
datadir := ctx.GlobalString(utils.DataDirFlag.Name)
|
||||
|
||||
nodes := p2p.ParsePermissionedNodes(datadir)
|
||||
for _, node := range nodes {
|
||||
enodeID := fmt.Sprintf("%x", node.ID[:])
|
||||
ipAddr := fmt.Sprintf("%v", node.IP)
|
||||
port := fmt.Sprintf("%v", node.TCP)
|
||||
discPort := fmt.Sprintf("%v", node.UDP)
|
||||
raftPort := fmt.Sprintf("%v", node.RaftPort)
|
||||
|
||||
ipAddrPort := ipAddr + ":" + port
|
||||
|
||||
log.Info("SMK-values are : ", "enodeId", enodeID, "ipAddrPort", ipAddrPort, "discPort", discPort, "raftPort", raftPort)
|
||||
|
||||
log.Trace("Adding node to permissions contract", "enodeID", enodeID)
|
||||
|
||||
nonce := e.TxPool().Nonce(permissionsSession.TransactOpts.From)
|
||||
permissionsSession.TransactOpts.Nonce = new(big.Int).SetUint64(nonce)
|
||||
|
||||
tx, err := permissionsSession.ProposeNode(enodeID, ipAddrPort, discPort, raftPort)
|
||||
if err != nil {
|
||||
log.Warn("Failed to propose node", "err", err)
|
||||
}
|
||||
log.Debug("Transaction pending", "tx hash", tx.Hash())
|
||||
}
|
||||
// update the network boot status to true
|
||||
nonce := e.TxPool().Nonce(permissionsSession.TransactOpts.From)
|
||||
permissionsSession.TransactOpts.Nonce = new(big.Int).SetUint64(nonce)
|
||||
|
||||
tx, err := permissionsSession.UpdateNetworkBootStatus()
|
||||
if err != nil {
|
||||
log.Warn("Failed to udpate network boot status ", "err", err)
|
||||
}
|
||||
log.Debug("Transaction pending", "tx hash", tx.Hash())
|
||||
}
|
||||
|
||||
//This functions reads the first file in key store directory, reads the key
|
||||
//value and returns the same
|
||||
func getKeyFromKeyStore(ctx *cli.Context) string {
|
||||
datadir := ctx.GlobalString(utils.DataDirFlag.Name)
|
||||
|
||||
files, err := ioutil.ReadDir(filepath.Join(datadir, "keystore"))
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read keystore directory: %v", err)
|
||||
}
|
||||
|
||||
// HACK: here we always use the first key as transactor
|
||||
var keyPath string
|
||||
for _, f := range files {
|
||||
keyPath = filepath.Join(datadir, "keystore", f.Name())
|
||||
break
|
||||
}
|
||||
keyBlob, err := ioutil.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read key file: %v", err)
|
||||
}
|
||||
// n := bytes.IndexByte(keyBlob, 0)
|
||||
n := len(keyBlob)
|
||||
|
||||
return string(keyBlob[:n])
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -6,6 +6,7 @@ package notify
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -70,11 +71,7 @@ Traverse:
|
|||
case errSkip:
|
||||
continue Traverse
|
||||
default:
|
||||
return &os.PathError{
|
||||
Op: "error while traversing",
|
||||
Path: nd.Name,
|
||||
Err: err,
|
||||
}
|
||||
return fmt.Errorf("error while traversing %q: %v", nd.Name, err)
|
||||
}
|
||||
// TODO(rjeczalik): tolerate open failures - add failed names to
|
||||
// AddDirError and notify users which names are not added to the tree.
|
||||
|
|
|
@ -26,9 +26,9 @@ import "C"
|
|||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -48,7 +48,7 @@ var wg sync.WaitGroup // used to wait until the runloop starts
|
|||
// started and is ready via the wg. It also serves purpose of a dummy source,
|
||||
// thanks to it the runloop does not return as it also has at least one source
|
||||
// registered.
|
||||
var source = C.CFRunLoopSourceCreate(nil, 0, &C.CFRunLoopSourceContext{
|
||||
var source = C.CFRunLoopSourceCreate(refZero, 0, &C.CFRunLoopSourceContext{
|
||||
perform: (C.CFRunLoopPerformCallBack)(C.gosource),
|
||||
})
|
||||
|
||||
|
@ -63,10 +63,6 @@ var (
|
|||
func init() {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
// There is exactly one run loop per thread. Lock this goroutine to its
|
||||
// thread to ensure that it's not rescheduled on a different thread while
|
||||
// setting up the run loop.
|
||||
runtime.LockOSThread()
|
||||
runloop = C.CFRunLoopGetCurrent()
|
||||
C.CFRunLoopAddSource(runloop, source, C.kCFRunLoopDefaultMode)
|
||||
C.CFRunLoopRun()
|
||||
|
@ -77,6 +73,7 @@ func init() {
|
|||
|
||||
//export gosource
|
||||
func gosource(unsafe.Pointer) {
|
||||
time.Sleep(time.Second)
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
|
@ -162,8 +159,8 @@ func (s *stream) Start() error {
|
|||
return nil
|
||||
}
|
||||
wg.Wait()
|
||||
p := C.CFStringCreateWithCStringNoCopy(nil, C.CString(s.path), C.kCFStringEncodingUTF8, nil)
|
||||
path := C.CFArrayCreate(nil, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil)
|
||||
p := C.CFStringCreateWithCStringNoCopy(refZero, C.CString(s.path), C.kCFStringEncodingUTF8, refZero)
|
||||
path := C.CFArrayCreate(refZero, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil)
|
||||
ctx := C.FSEventStreamContext{}
|
||||
ref := C.EventStreamCreate(&ctx, C.uintptr_t(s.info), path, C.FSEventStreamEventId(atomic.LoadUint64(&since)), latency, flags)
|
||||
if ref == nilstream {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2017 The Notify Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// +build darwin,!kqueue,go1.10
|
||||
|
||||
package notify
|
||||
|
||||
const refZero = 0
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2017 The Notify Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// +build darwin,!kqueue,cgo,!go1.10
|
||||
|
||||
package notify
|
||||
|
||||
/*
|
||||
#include <CoreServices/CoreServices.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
var refZero = (*C.struct___CFAllocator)(nil)
|
|
@ -346,10 +346,10 @@
|
|||
"revisionTime": "2017-08-14T17:01:13Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "28UVHMmHx0iqO0XiJsjx+fwILyI=",
|
||||
"checksumSHA1": "d2rQHpL6cSf3NQiWJCVoEiJhsOI=",
|
||||
"path": "github.com/rjeczalik/notify",
|
||||
"revision": "c31e5f2cb22b3e4ef3f882f413847669bf2652b9",
|
||||
"revisionTime": "2018-02-03T14:01:15Z"
|
||||
"revision": "ff2d4d2cedc09db23cc46d3eeb8b402bca6d819d",
|
||||
"revisionTime": "2017-12-09T07:29:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "5uqO4ITTDMklKi3uNaE/D9LQ5nM=",
|
||||
|
|
Loading…
Reference in New Issue