mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
Merge 9015b958a1 into 9422eec554
This commit is contained in:
commit
29c415c3fa
5 changed files with 328 additions and 144 deletions
87
accounts/contract/contract.go
Normal file
87
accounts/contract/contract.go
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
package contract
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
)
|
||||
|
||||
type Contract struct {
|
||||
backend core.Backend
|
||||
abi.ABI
|
||||
Address common.Address
|
||||
}
|
||||
|
||||
func getAccount(backend core.Backend) *state.StateObject {
|
||||
statedb, _ := state.New(backend.BlockChain().CurrentHeader().Root, backend.ChainDb())
|
||||
accounts, err := backend.AccountManager().Accounts()
|
||||
if err != nil || len(accounts) == 0 {
|
||||
return statedb.GetOrNewStateObject(common.Address{})
|
||||
} else {
|
||||
return statedb.GetOrNewStateObject(accounts[0].Address)
|
||||
}
|
||||
}
|
||||
|
||||
func New(definition string, addr common.Address, backend core.Backend) (*Contract, error) {
|
||||
abi, err := abi.JSON(strings.NewReader(definition))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Contract{
|
||||
backend: backend,
|
||||
ABI: abi,
|
||||
Address: addr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Contract) Call(method string, args ...interface{}) ([]byte, *big.Int, error) {
|
||||
msg := CallMessage{
|
||||
gas: new(big.Int).Set(common.MaxBig),
|
||||
gasPrice: new(big.Int),
|
||||
value: new(big.Int),
|
||||
from: getAccount(c.backend),
|
||||
}
|
||||
return c.CallWithMessage(msg, method, args...)
|
||||
}
|
||||
|
||||
func (c *Contract) CallWithMessage(msg CallMessage, method string, args ...interface{}) ([]byte, *big.Int, error) {
|
||||
input, err := c.ABI.Pack(method, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
msg.data = input
|
||||
msg.to = &c.Address
|
||||
|
||||
header := c.backend.BlockChain().CurrentHeader()
|
||||
statedb, err := state.New(header.Root, c.backend.ChainDb())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
vmenv := core.NewEnv(statedb, c.backend.BlockChain(), msg, header)
|
||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||
|
||||
return core.ApplyMessage(vmenv, msg, gp)
|
||||
}
|
||||
|
||||
// CallMessage is the message type used for call transations.
|
||||
type CallMessage struct {
|
||||
from *state.StateObject
|
||||
to *common.Address
|
||||
gas, gasPrice *big.Int
|
||||
value *big.Int
|
||||
data []byte
|
||||
}
|
||||
|
||||
// accessor boilerplate to implement core.Message
|
||||
func (m CallMessage) From() (common.Address, error) { return m.from.Address(), nil }
|
||||
func (m CallMessage) Nonce() uint64 { return m.from.Nonce() }
|
||||
func (m CallMessage) To() *common.Address { return m.to }
|
||||
func (m CallMessage) GasPrice() *big.Int { return m.gasPrice }
|
||||
func (m CallMessage) Gas() *big.Int { return m.gas }
|
||||
func (m CallMessage) Value() *big.Int { return m.value }
|
||||
func (m CallMessage) Data() []byte { return m.data }
|
||||
|
|
@ -450,7 +450,6 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
|||
Discovery: !ctx.GlobalBool(NoDiscoverFlag.Name),
|
||||
NodeKey: MakeNodeKey(ctx),
|
||||
Shh: ctx.GlobalBool(WhisperEnabledFlag.Name),
|
||||
Dial: true,
|
||||
BootNodes: ctx.GlobalString(BootnodesFlag.Name),
|
||||
GasPrice: common.String2Big(ctx.GlobalString(GasPriceFlag.Name)),
|
||||
GpoMinGasPrice: common.String2Big(ctx.GlobalString(GpoMinGasPriceFlag.Name)),
|
||||
|
|
|
|||
149
eth/backend.go
149
eth/backend.go
|
|
@ -19,10 +19,7 @@ package eth
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -40,7 +37,6 @@ import (
|
|||
"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/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
|
|
@ -49,7 +45,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/miner"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/whisper"
|
||||
)
|
||||
|
|
@ -86,143 +81,6 @@ var (
|
|||
trustedNodes = "trusted-nodes.json" // Path within <datadir> to search for the trusted node list
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
DevMode bool
|
||||
TestNet bool
|
||||
|
||||
Name string
|
||||
NetworkId int
|
||||
GenesisFile string
|
||||
GenesisBlock *types.Block // used by block tests
|
||||
FastSync bool
|
||||
Olympic bool
|
||||
|
||||
BlockChainVersion int
|
||||
SkipBcVersionCheck bool // e.g. blockchain export
|
||||
DatabaseCache int
|
||||
|
||||
DataDir string
|
||||
LogFile string
|
||||
Verbosity int
|
||||
VmDebug bool
|
||||
NatSpec bool
|
||||
DocRoot string
|
||||
AutoDAG bool
|
||||
PowTest bool
|
||||
ExtraData []byte
|
||||
|
||||
MaxPeers int
|
||||
MaxPendingPeers int
|
||||
Discovery bool
|
||||
Port string
|
||||
|
||||
// Space-separated list of discovery node URLs
|
||||
BootNodes string
|
||||
|
||||
// This key is used to identify the node on the network.
|
||||
// If nil, an ephemeral key is used.
|
||||
NodeKey *ecdsa.PrivateKey
|
||||
|
||||
NAT nat.Interface
|
||||
Shh bool
|
||||
Dial bool
|
||||
|
||||
Etherbase common.Address
|
||||
GasPrice *big.Int
|
||||
MinerThreads int
|
||||
AccountManager *accounts.Manager
|
||||
SolcPath string
|
||||
|
||||
GpoMinGasPrice *big.Int
|
||||
GpoMaxGasPrice *big.Int
|
||||
GpoFullBlockRatio int
|
||||
GpobaseStepDown int
|
||||
GpobaseStepUp int
|
||||
GpobaseCorrectionFactor int
|
||||
|
||||
// NewDB is used to create databases.
|
||||
// If nil, the default is to create leveldb databases on disk.
|
||||
NewDB func(path string) (ethdb.Database, error)
|
||||
}
|
||||
|
||||
func (cfg *Config) parseBootNodes() []*discover.Node {
|
||||
if cfg.BootNodes == "" {
|
||||
if cfg.TestNet {
|
||||
return defaultTestNetBootNodes
|
||||
}
|
||||
|
||||
return defaultBootNodes
|
||||
}
|
||||
var ns []*discover.Node
|
||||
for _, url := range strings.Split(cfg.BootNodes, " ") {
|
||||
if url == "" {
|
||||
continue
|
||||
}
|
||||
n, err := discover.ParseNode(url)
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||
continue
|
||||
}
|
||||
ns = append(ns, n)
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// parseNodes parses a list of discovery node URLs loaded from a .json file.
|
||||
func (cfg *Config) parseNodes(file string) []*discover.Node {
|
||||
// Short circuit if no node config is present
|
||||
path := filepath.Join(cfg.DataDir, file)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return nil
|
||||
}
|
||||
// Load the nodes from the config file
|
||||
blob, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Failed to access nodes: %v", err)
|
||||
return nil
|
||||
}
|
||||
nodelist := []string{}
|
||||
if err := json.Unmarshal(blob, &nodelist); err != nil {
|
||||
glog.V(logger.Error).Infof("Failed to load nodes: %v", err)
|
||||
return nil
|
||||
}
|
||||
// Interpret the list as a discovery node array
|
||||
var nodes []*discover.Node
|
||||
for _, url := range nodelist {
|
||||
if url == "" {
|
||||
continue
|
||||
}
|
||||
node, err := discover.ParseNode(url)
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Node URL %s: %v\n", url, err)
|
||||
continue
|
||||
}
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
|
||||
// use explicit key from command line args if set
|
||||
if cfg.NodeKey != nil {
|
||||
return cfg.NodeKey, nil
|
||||
}
|
||||
// use persistent key if present
|
||||
keyfile := filepath.Join(cfg.DataDir, "nodekey")
|
||||
key, err := crypto.LoadECDSA(keyfile)
|
||||
if err == nil {
|
||||
return key, nil
|
||||
}
|
||||
// no persistent key, generate and store a new one
|
||||
if key, err = crypto.GenerateKey(); err != nil {
|
||||
return nil, fmt.Errorf("could not generate server key: %v", err)
|
||||
}
|
||||
if err := crypto.SaveECDSA(keyfile, key); err != nil {
|
||||
glog.V(logger.Error).Infoln("could not persist nodekey: ", err)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
type Ethereum struct {
|
||||
// Channel for shutting down the ethereum
|
||||
shutdownChan chan bool
|
||||
|
|
@ -272,6 +130,11 @@ type Ethereum struct {
|
|||
}
|
||||
|
||||
func New(config *Config) (*Ethereum, error) {
|
||||
if config == nil {
|
||||
config = new(Config)
|
||||
}
|
||||
MakeConfig(config)
|
||||
|
||||
logger.New(config.DataDir, config.LogFile, config.Verbosity)
|
||||
|
||||
// Let the database take 3/4 of the max open files (TODO figure out a way to get the actual limit of the open files)
|
||||
|
|
@ -437,7 +300,7 @@ func New(config *Config) (*Ethereum, error) {
|
|||
Discovery: config.Discovery,
|
||||
Protocols: protocols,
|
||||
NAT: config.NAT,
|
||||
NoDial: !config.Dial,
|
||||
NoDial: config.NoDial,
|
||||
BootstrapNodes: config.parseBootNodes(),
|
||||
StaticNodes: config.parseNodes(staticNodes),
|
||||
TrustedNodes: config.parseNodes(trustedNodes),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/signal"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -65,3 +68,20 @@ func TestMipmapUpgrade(t *testing.T) {
|
|||
t.Error("setting-mipmap-version not written to database")
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleNew() {
|
||||
// Setup ethereum stack; initialising the blockchain, transaction pool
|
||||
// and network stack.
|
||||
ethereum, err := New(&Config{Name: "Ghost"})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
// start all services
|
||||
ethereum.Start()
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, os.Kill)
|
||||
<-c
|
||||
// stop all services
|
||||
ethereum.Stop()
|
||||
}
|
||||
|
|
|
|||
215
eth/config.go
Normal file
215
eth/config.go
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
)
|
||||
|
||||
// Config is the configuration object which holds information about the various
|
||||
// sub system and ethereum's environment and settings.
|
||||
type Config struct {
|
||||
DevMode bool // Developer mode
|
||||
TestNet bool // Testnet mode
|
||||
|
||||
Name string // Name of the instance (visible through p2p)
|
||||
NetworkId int // The network id used for p2p
|
||||
GenesisFile string // genesis file for initialising the genesis block
|
||||
GenesisBlock *types.Block // used by block tests
|
||||
FastSync bool // enble fast sync
|
||||
Olympic bool // enable olympic settings
|
||||
|
||||
BlockChainVersion int // version of the block chain in database
|
||||
SkipBcVersionCheck bool // e.g. blockchain export
|
||||
DatabaseCache int // Max cache for leveldb
|
||||
|
||||
DataDir string // datadir containing leveldb, node settings, etc.
|
||||
LogFile string // file to which logs are written
|
||||
Verbosity int // the level of verbosity
|
||||
VmDebug bool // log debug output during vm execution
|
||||
NatSpec bool // enable natspec
|
||||
DocRoot string // documentation root for natspec
|
||||
AutoDAG bool // pre-generate dags
|
||||
PowTest bool // enabled pow test
|
||||
ExtraData []byte // default extra data to be used for the miner
|
||||
|
||||
MaxPeers int // maximum amount of peers
|
||||
MaxPendingPeers int // maximum amount of pending peers
|
||||
Discovery bool // enable discovery
|
||||
Port string // port to be used for p2p
|
||||
|
||||
BootNodes string // Space-separated list of discovery node URLs
|
||||
|
||||
// This key is used to identify the node on the network.
|
||||
// If nil, an ephemeral key is used.
|
||||
NodeKey *ecdsa.PrivateKey
|
||||
|
||||
NAT nat.Interface // NAT interface
|
||||
Shh bool // enable shh
|
||||
NoDial bool // disable outgoing dials
|
||||
NoConn bool // disable peers
|
||||
|
||||
AccountManager *accounts.Manager // account manager
|
||||
LightKDF bool // enables light KDF
|
||||
|
||||
Etherbase common.Address // default coinbase
|
||||
GasPrice *big.Int // minimum acceptable gas price (tx relay, mining)
|
||||
MinerThreads int // amount of default miner threads to be used during mining
|
||||
SolcPath string // path to solidity executable
|
||||
|
||||
GpoMinGasPrice *big.Int // GPO minimum gas price
|
||||
GpoMaxGasPrice *big.Int // GPO maximum gas price
|
||||
GpoFullBlockRatio int
|
||||
GpobaseStepDown int
|
||||
GpobaseStepUp int
|
||||
GpobaseCorrectionFactor int
|
||||
|
||||
// NewDB is used to create databases.
|
||||
// If nil, the default is to create leveldb databases on disk.
|
||||
NewDB func(path string) (ethdb.Database, error)
|
||||
}
|
||||
|
||||
// MakeConfig sets missing default values
|
||||
func MakeConfig(cfg *Config) {
|
||||
if cfg.BlockChainVersion < 3 {
|
||||
cfg.BlockChainVersion = 3
|
||||
}
|
||||
if len(cfg.Name) == 0 {
|
||||
cfg.Name = "Custom-Ethereum-Client"
|
||||
}
|
||||
if len(cfg.DataDir) == 0 {
|
||||
cfg.DataDir = common.DefaultDataDir()
|
||||
}
|
||||
if cfg.MaxPeers == 0 && !cfg.NoConn {
|
||||
cfg.MaxPeers = 25
|
||||
}
|
||||
if len(cfg.Port) == 0 {
|
||||
cfg.Port = "0" // auto
|
||||
}
|
||||
if cfg.TestNet && cfg.NetworkId == 0 {
|
||||
cfg.NetworkId = 2
|
||||
}
|
||||
if cfg.NAT == nil {
|
||||
cfg.NAT, _ = nat.Parse("any")
|
||||
}
|
||||
if cfg.GasPrice == nil {
|
||||
cfg.GasPrice = new(big.Int).Mul(big.NewInt(10), common.Szabo)
|
||||
}
|
||||
if cfg.GpoMinGasPrice == nil {
|
||||
cfg.GpoMinGasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
|
||||
}
|
||||
if cfg.GpoMaxGasPrice == nil {
|
||||
cfg.GpoMaxGasPrice = new(big.Int).Mul(big.NewInt(500), common.Shannon)
|
||||
}
|
||||
if cfg.GpoFullBlockRatio == 0 && cfg.GpobaseStepDown == 0 && cfg.GpobaseStepUp == 0 && cfg.GpobaseCorrectionFactor == 0 {
|
||||
cfg.GpoFullBlockRatio = 80
|
||||
cfg.GpobaseStepDown = 10
|
||||
cfg.GpobaseStepUp = 100
|
||||
cfg.GpobaseCorrectionFactor = 110
|
||||
}
|
||||
if cfg.AccountManager == nil {
|
||||
scryptN := crypto.StandardScryptN
|
||||
scryptP := crypto.StandardScryptP
|
||||
if cfg.LightKDF {
|
||||
scryptN = crypto.LightScryptN
|
||||
scryptP = crypto.LightScryptP
|
||||
}
|
||||
cfg.AccountManager = accounts.NewManager(crypto.NewKeyStorePassphrase(filepath.Join(cfg.DataDir, "keystore"), scryptN, scryptP))
|
||||
}
|
||||
glog.SetV(cfg.Verbosity)
|
||||
glog.CopyStandardLogTo("INFO")
|
||||
glog.SetToStderr(true)
|
||||
}
|
||||
|
||||
func (cfg *Config) parseBootNodes() []*discover.Node {
|
||||
if cfg.BootNodes == "" {
|
||||
if cfg.TestNet {
|
||||
return defaultTestNetBootNodes
|
||||
}
|
||||
|
||||
return defaultBootNodes
|
||||
}
|
||||
var ns []*discover.Node
|
||||
for _, url := range strings.Split(cfg.BootNodes, " ") {
|
||||
if url == "" {
|
||||
continue
|
||||
}
|
||||
n, err := discover.ParseNode(url)
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||
continue
|
||||
}
|
||||
ns = append(ns, n)
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// parseNodes parses a list of discovery node URLs loaded from a .json file.
|
||||
func (cfg *Config) parseNodes(file string) []*discover.Node {
|
||||
// Short circuit if no node config is present
|
||||
path := filepath.Join(cfg.DataDir, file)
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return nil
|
||||
}
|
||||
// Load the nodes from the config file
|
||||
blob, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Failed to access nodes: %v", err)
|
||||
return nil
|
||||
}
|
||||
nodelist := []string{}
|
||||
if err := json.Unmarshal(blob, &nodelist); err != nil {
|
||||
glog.V(logger.Error).Infof("Failed to load nodes: %v", err)
|
||||
return nil
|
||||
}
|
||||
// Interpret the list as a discovery node array
|
||||
var nodes []*discover.Node
|
||||
for _, url := range nodelist {
|
||||
if url == "" {
|
||||
continue
|
||||
}
|
||||
node, err := discover.ParseNode(url)
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Node URL %s: %v\n", url, err)
|
||||
continue
|
||||
}
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
|
||||
// use explicit key from command line args if set
|
||||
if cfg.NodeKey != nil {
|
||||
return cfg.NodeKey, nil
|
||||
}
|
||||
// use persistent key if present
|
||||
keyfile := filepath.Join(cfg.DataDir, "nodekey")
|
||||
key, err := crypto.LoadECDSA(keyfile)
|
||||
if err == nil {
|
||||
return key, nil
|
||||
}
|
||||
// no persistent key, generate and store a new one
|
||||
if key, err = crypto.GenerateKey(); err != nil {
|
||||
return nil, fmt.Errorf("could not generate server key: %v", err)
|
||||
}
|
||||
if err := crypto.SaveECDSA(keyfile, key); err != nil {
|
||||
glog.V(logger.Error).Infoln("could not persist nodekey: ", err)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
Loading…
Reference in a new issue