diff options
212 files changed, 21445 insertions, 3245 deletions
@@ -8,7 +8,7 @@ .PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64 .PHONY: geth-windows geth-windows-386 geth-windows-amd64 -GOBIN = build/bin +GOBIN = $(shell pwd)/build/bin GO ?= latest geth: @@ -21,11 +21,6 @@ swarm: @echo "Done building." @echo "Run \"$(GOBIN)/swarm\" to launch swarm." -evm: - build/env.sh go run build/ci.go install ./cmd/evm - @echo "Done building." - @echo "Run \"$(GOBIN)/evm\" to start the evm." - all: build/env.sh go run build/ci.go install @@ -35,11 +35,11 @@ The go-ethereum project comes with several wrappers/executables found in the `cm | **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default) archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) for command line options. | | `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. | | `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | -| `disasm` | Bytecode disassembler to convert EVM (Ethereum Virtual Machine) bytecode into more user friendly assembly-like opcodes (e.g. `echo "6001" | disasm`). For details on the individual opcodes, please see pages 22-30 of the [Ethereum Yellow Paper](http://gavwood.com/paper.pdf). | | `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). | | `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. | | `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | | `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. | +| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. | ## Running geth diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index 64dd598c0..d07610e7c 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -52,8 +52,8 @@ var tmplSource = map[Lang]string{ // tmplSourceGo is the Go source template use to generate the contract binding // based on. const tmplSourceGo = ` -// This file is an automatically generated Go binding. Do not modify as any -// change will likely be lost upon the next re-generation! +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. package {{.Package}} diff --git a/accounts/accounts.go b/accounts/accounts.go index 640de5220..76951e1a4 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -42,8 +42,9 @@ type Wallet interface { URL() URL // Status returns a textual status to aid the user in the current state of the - // wallet. - Status() string + // wallet. It also returns an error indicating any failure the wallet might have + // encountered. + Status() (string, error) // Open initializes access to a wallet instance. It is not meant to unlock or // decrypt account keys, rather simply to establish a connection to hardware @@ -147,9 +148,26 @@ type Backend interface { Subscribe(sink chan<- WalletEvent) event.Subscription } +// WalletEventType represents the different event types that can be fired by +// the wallet subscription subsystem. +type WalletEventType int + +const ( + // WalletArrived is fired when a new wallet is detected either via USB or via + // a filesystem event in the keystore. + WalletArrived WalletEventType = iota + + // WalletOpened is fired when a wallet is successfully opened with the purpose + // of starting any background processes such as automatic key derivation. + WalletOpened + + // WalletDropped + WalletDropped +) + // WalletEvent is an event fired by an account backend when a wallet arrival or // departure is detected. type WalletEvent struct { - Wallet Wallet // Wallet instance arrived or departed - Arrive bool // Whether the wallet was added or removed + Wallet Wallet // Wallet instance arrived or departed + Kind WalletEventType // Event type that happened in the system } diff --git a/accounts/hd.go b/accounts/hd.go index e8bc191af..277f688e4 100644 --- a/accounts/hd.go +++ b/accounts/hd.go @@ -27,12 +27,17 @@ import ( // DefaultRootDerivationPath is the root path to which custom derivation endpoints // are appended. As such, the first account will be at m/44'/60'/0'/0, the second // at m/44'/60'/0'/1, etc. -var DefaultRootDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0} +var DefaultRootDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0} // DefaultBaseDerivationPath is the base path from which custom derivation endpoints // are incremented. As such, the first account will be at m/44'/60'/0'/0, the second // at m/44'/60'/0'/1, etc. -var DefaultBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0} +var DefaultBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0} + +// DefaultLedgerBaseDerivationPath is the base path from which custom derivation endpoints +// are incremented. As such, the first account will be at m/44'/60'/0'/0, the second +// at m/44'/60'/0'/1, etc. +var DefaultLedgerBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0} // DerivationPath represents the computer friendly version of a hierarchical // deterministic wallet account derivaion path. diff --git a/accounts/hd_test.go b/accounts/hd_test.go index 83ec34adb..b6b23230d 100644 --- a/accounts/hd_test.go +++ b/accounts/hd_test.go @@ -37,11 +37,11 @@ func TestHDPathParsing(t *testing.T) { {"m/2147483692/2147483708/2147483648/2147483648", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}}, // Plain relative derivation paths - {"0", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}}, - {"128", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 128}}, - {"0'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}}, - {"128'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 128}}, - {"2147483648", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}}, + {"0", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0}}, + {"128", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 128}}, + {"0'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 0}}, + {"128'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 128}}, + {"2147483648", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 0}}, // Hexadecimal absolute derivation paths {"m/0x2C'/0x3c'/0x00'/0x00", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}}, @@ -52,11 +52,11 @@ func TestHDPathParsing(t *testing.T) { {"m/0x8000002C/0x8000003c/0x80000000/0x80000000", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}}, // Hexadecimal relative derivation paths - {"0x00", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}}, - {"0x80", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 128}}, - {"0x00'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}}, - {"0x80'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 128}}, - {"0x80000000", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0x80000000 + 0}}, + {"0x00", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0}}, + {"0x80", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 128}}, + {"0x00'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 0}}, + {"0x80'", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 128}}, + {"0x80000000", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0x80000000 + 0}}, // Weird inputs just to ensure they work {" m / 44 '\n/\n 60 \n\n\t' /\n0 ' /\t\t 0", DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0}}, diff --git a/accounts/keystore/key.go b/accounts/keystore/key.go index ecc955d74..211fa863d 100644 --- a/accounts/keystore/key.go +++ b/accounts/keystore/key.go @@ -91,14 +91,6 @@ type cipherparamsJSON struct { IV string `json:"iv"` } -type scryptParamsJSON struct { - N int `json:"n"` - R int `json:"r"` - P int `json:"p"` - DkLen int `json:"dklen"` - Salt string `json:"salt"` -} - func (k *Key) MarshalJSON() (j []byte, err error) { jStruct := plainKeyJSON{ hex.EncodeToString(k.Address[:]), diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 9df7f2dd9..80ccd3741 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -143,14 +143,14 @@ func (ks *KeyStore) refreshWallets() { for _, account := range accs { // Drop wallets while they were in front of the next account for len(ks.wallets) > 0 && ks.wallets[0].URL().Cmp(account.URL) < 0 { - events = append(events, accounts.WalletEvent{Wallet: ks.wallets[0], Arrive: false}) + events = append(events, accounts.WalletEvent{Wallet: ks.wallets[0], Kind: accounts.WalletDropped}) ks.wallets = ks.wallets[1:] } // If there are no more wallets or the account is before the next, wrap new wallet if len(ks.wallets) == 0 || ks.wallets[0].URL().Cmp(account.URL) > 0 { wallet := &keystoreWallet{account: account, keystore: ks} - events = append(events, accounts.WalletEvent{Wallet: wallet, Arrive: true}) + events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived}) wallets = append(wallets, wallet) continue } @@ -163,7 +163,7 @@ func (ks *KeyStore) refreshWallets() { } // Drop any leftover wallets and set the new batch for _, wallet := range ks.wallets { - events = append(events, accounts.WalletEvent{Wallet: wallet, Arrive: false}) + events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletDropped}) } ks.wallets = wallets ks.mu.Unlock() diff --git a/accounts/keystore/keystore_passphrase.go b/accounts/keystore/keystore_passphrase.go index 679fc15d6..535608a60 100644 --- a/accounts/keystore/keystore_passphrase.go +++ b/accounts/keystore/keystore_passphrase.go @@ -140,7 +140,7 @@ func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { Cipher: "aes-128-ctr", CipherText: hex.EncodeToString(cipherText), CipherParams: cipherParamsJSON, - KDF: "scrypt", + KDF: keyHeaderKDF, KDFParams: scryptParamsJSON, MAC: hex.EncodeToString(mac), } @@ -275,7 +275,7 @@ func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) { } dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) - if cryptoJSON.KDF == "scrypt" { + if cryptoJSON.KDF == keyHeaderKDF { n := ensureInt(cryptoJSON.KDFParams["n"]) r := ensureInt(cryptoJSON.KDFParams["r"]) p := ensureInt(cryptoJSON.KDFParams["p"]) diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go index 5d89a4dbb..132b74439 100644 --- a/accounts/keystore/keystore_test.go +++ b/accounts/keystore/keystore_test.go @@ -296,8 +296,8 @@ func TestWalletNotifications(t *testing.T) { } select { case event := <-updates: - if !event.Arrive { - t.Errorf("departure event on account creation") + if event.Kind != accounts.WalletArrived { + t.Errorf("non-arrival event on account creation") } if event.Wallet.Accounts()[0] != account { t.Errorf("account mismatch on created wallet: have %v, want %v", event.Wallet.Accounts()[0], account) @@ -319,8 +319,8 @@ func TestWalletNotifications(t *testing.T) { } select { case event := <-updates: - if event.Arrive { - t.Errorf("arrival event on account deletion") + if event.Kind != accounts.WalletDropped { + t.Errorf("non-drop event on account deletion") } if event.Wallet.Accounts()[0] != account { t.Errorf("account mismatch on deleted wallet: have %v, want %v", event.Wallet.Accounts()[0], account) diff --git a/accounts/keystore/keystore_wallet.go b/accounts/keystore/keystore_wallet.go index 7165d2821..758fdfe36 100644 --- a/accounts/keystore/keystore_wallet.go +++ b/accounts/keystore/keystore_wallet.go @@ -36,16 +36,16 @@ func (w *keystoreWallet) URL() accounts.URL { return w.account.URL } -// Status implements accounts.Wallet, always returning "open", since there is no -// concept of open/close for plain keystore accounts. -func (w *keystoreWallet) Status() string { +// Status implements accounts.Wallet, returning whether the account held by the +// keystore wallet is unlocked or not. +func (w *keystoreWallet) Status() (string, error) { w.keystore.mu.RLock() defer w.keystore.mu.RUnlock() if _, ok := w.keystore.unlocked[w.account.Address]; ok { - return "Unlocked" + return "Unlocked", nil } - return "Locked" + return "Locked", nil } // Open implements accounts.Wallet, but is a noop for plain wallets since there diff --git a/accounts/manager.go b/accounts/manager.go index 12a5bfcd9..78ddb1368 100644 --- a/accounts/manager.go +++ b/accounts/manager.go @@ -96,9 +96,10 @@ func (am *Manager) update() { case event := <-am.updates: // Wallet event arrived, update local cache am.lock.Lock() - if event.Arrive { + switch event.Kind { + case WalletArrived: am.wallets = merge(am.wallets, event.Wallet) - } else { + case WalletDropped: am.wallets = drop(am.wallets, event.Wallet) } am.lock.Unlock() diff --git a/accounts/usbwallet/ledger_hub.go b/accounts/usbwallet/hub.go index fcbc24c0f..7069d2531 100644 --- a/accounts/usbwallet/ledger_hub.go +++ b/accounts/usbwallet/hub.go @@ -14,10 +14,6 @@ // 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/>. -// This file contains the implementation for interacting with the Ledger hardware -// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo: -// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc - package usbwallet import ( @@ -33,24 +29,28 @@ import ( ) // LedgerScheme is the protocol scheme prefixing account and wallet URLs. -var LedgerScheme = "ledger" +const LedgerScheme = "ledger" -// ledgerDeviceIDs are the known device IDs that Ledger wallets use. -var ledgerDeviceIDs = []deviceID{ - {Vendor: 0x2c97, Product: 0x0000}, // Ledger Blue - {Vendor: 0x2c97, Product: 0x0001}, // Ledger Nano S -} +// TrezorScheme is the protocol scheme prefixing account and wallet URLs. +const TrezorScheme = "trezor" + +// refreshCycle is the maximum time between wallet refreshes (if USB hotplug +// notifications don't work). +const refreshCycle = time.Second -// Maximum time between wallet refreshes (if USB hotplug notifications don't work). -const ledgerRefreshCycle = time.Second +// refreshThrottling is the minimum time between wallet refreshes to avoid USB +// trashing. +const refreshThrottling = 500 * time.Millisecond -// Minimum time between wallet refreshes to avoid USB trashing. -const ledgerRefreshThrottling = 500 * time.Millisecond +// Hub is a accounts.Backend that can find and handle generic USB hardware wallets. +type Hub struct { + scheme string // Protocol scheme prefixing account and wallet URLs. + vendorID uint16 // USB vendor identifier used for device discovery + productIDs []uint16 // USB product identifiers used for device discovery + makeDriver func(log.Logger) driver // Factory method to construct a vendor specific driver -// LedgerHub is a accounts.Backend that can find and handle Ledger hardware wallets. -type LedgerHub struct { refreshed time.Time // Time instance when the list of wallets was last refreshed - wallets []accounts.Wallet // List of Ledger devices currently tracking + wallets []accounts.Wallet // List of USB wallet devices currently tracking updateFeed event.Feed // Event feed to notify wallet additions/removals updateScope event.SubscriptionScope // Subscription scope tracking current live listeners updating bool // Whether the event notification loop is running @@ -65,20 +65,34 @@ type LedgerHub struct { } // NewLedgerHub creates a new hardware wallet manager for Ledger devices. -func NewLedgerHub() (*LedgerHub, error) { +func NewLedgerHub() (*Hub, error) { + return newHub(LedgerScheme, 0x2c97, []uint16{0x0000 /* Ledger Blue */, 0x0001 /* Ledger Nano S */}, newLedgerDriver) +} + +// NewTrezorHub creates a new hardware wallet manager for Trezor devices. +func NewTrezorHub() (*Hub, error) { + return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor 1 */}, newTrezorDriver) +} + +// newHub creates a new hardware wallet manager for generic USB devices. +func newHub(scheme string, vendorID uint16, productIDs []uint16, makeDriver func(log.Logger) driver) (*Hub, error) { if !hid.Supported() { return nil, errors.New("unsupported platform") } - hub := &LedgerHub{ - quit: make(chan chan error), + hub := &Hub{ + scheme: scheme, + vendorID: vendorID, + productIDs: productIDs, + makeDriver: makeDriver, + quit: make(chan chan error), } hub.refreshWallets() return hub, nil } // Wallets implements accounts.Backend, returning all the currently tracked USB -// devices that appear to be Ledger hardware wallets. -func (hub *LedgerHub) Wallets() []accounts.Wallet { +// devices that appear to be hardware wallets. +func (hub *Hub) Wallets() []accounts.Wallet { // Make sure the list of wallets is up to date hub.refreshWallets() @@ -92,17 +106,17 @@ func (hub *LedgerHub) Wallets() []accounts.Wallet { // refreshWallets scans the USB devices attached to the machine and updates the // list of wallets based on the found devices. -func (hub *LedgerHub) refreshWallets() { +func (hub *Hub) refreshWallets() { // Don't scan the USB like crazy it the user fetches wallets in a loop hub.stateLock.RLock() elapsed := time.Since(hub.refreshed) hub.stateLock.RUnlock() - if elapsed < ledgerRefreshThrottling { + if elapsed < refreshThrottling { return } - // Retrieve the current list of Ledger devices - var ledgers []hid.DeviceInfo + // Retrieve the current list of USB wallet devices + var devices []hid.DeviceInfo if runtime.GOOS == "linux" { // hidapi on Linux opens the device during enumeration to retrieve some infos, @@ -117,10 +131,10 @@ func (hub *LedgerHub) refreshWallets() { return } } - for _, info := range hid.Enumerate(0, 0) { // Can't enumerate directly, one valid ID is the 0 wildcard - for _, id := range ledgerDeviceIDs { - if info.VendorID == id.Vendor && info.ProductID == id.Product { - ledgers = append(ledgers, info) + for _, info := range hid.Enumerate(hub.vendorID, 0) { + for _, id := range hub.productIDs { + if info.ProductID == id && info.Interface == 0 { + devices = append(devices, info) break } } @@ -132,22 +146,29 @@ func (hub *LedgerHub) refreshWallets() { // Transform the current list of wallets into the new one hub.stateLock.Lock() - wallets := make([]accounts.Wallet, 0, len(ledgers)) + wallets := make([]accounts.Wallet, 0, len(devices)) events := []accounts.WalletEvent{} - for _, ledger := range ledgers { - url := accounts.URL{Scheme: LedgerScheme, Path: ledger.Path} + for _, device := range devices { + url := accounts.URL{Scheme: hub.scheme, Path: device.Path} // Drop wallets in front of the next device or those that failed for some reason - for len(hub.wallets) > 0 && (hub.wallets[0].URL().Cmp(url) < 0 || hub.wallets[0].(*ledgerWallet).failed()) { - events = append(events, accounts.WalletEvent{Wallet: hub.wallets[0], Arrive: false}) + for len(hub.wallets) > 0 { + // Abort if we're past the current device and found an operational one + _, failure := hub.wallets[0].Status() + if hub.wallets[0].URL().Cmp(url) >= 0 || failure == nil { + break + } + // Drop the stale and failed devices + events = append(events, accounts.WalletEvent{Wallet: hub.wallets[0], Kind: accounts.WalletDropped}) hub.wallets = hub.wallets[1:] } // If there are no more wallets or the device is before the next, wrap new wallet if len(hub.wallets) == 0 || hub.wallets[0].URL().Cmp(url) > 0 { - wallet := &ledgerWallet{hub: hub, url: &url, info: ledger, log: log.New("url", url)} + logger := log.New("url", url) + wallet := &wallet{hub: hub, driver: hub.makeDriver(logger), url: &url, info: device, log: logger} - events = append(events, accounts.WalletEvent{Wallet: wallet, Arrive: true}) + events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived}) wallets = append(wallets, wallet) continue } @@ -160,7 +181,7 @@ func (hub *LedgerHub) refreshWallets() { } // Drop any leftover wallets and set the new batch for _, wallet := range hub.wallets { - events = append(events, accounts.WalletEvent{Wallet: wallet, Arrive: false}) + events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletDropped}) } hub.refreshed = time.Now() hub.wallets = wallets @@ -173,8 +194,8 @@ func (hub *LedgerHub) refreshWallets() { } // Subscribe implements accounts.Backend, creating an async subscription to -// receive notifications on the addition or removal of Ledger wallets. -func (hub *LedgerHub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription { +// receive notifications on the addition or removal of USB wallets. +func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription { // We need the mutex to reliably start/stop the update loop hub.stateLock.Lock() defer hub.stateLock.Unlock() @@ -190,18 +211,14 @@ func (hub *LedgerHub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscrip return sub } -// updater is responsible for maintaining an up-to-date list of wallets stored in -// the keystore, and for firing wallet addition/removal events. It listens for -// account change events from the underlying account cache, and also periodically -// forces a manual refresh (only triggers for systems where the filesystem notifier -// is not running). -func (hub *LedgerHub) updater() { +// updater is responsible for maintaining an up-to-date list of wallets managed +// by the USB hub, and for firing wallet addition/removal events. +func (hub *Hub) updater() { for { - // Wait for a USB hotplug event (not supported yet) or a refresh timeout - select { - //case <-hub.changes: // reenable on hutplug implementation - case <-time.After(ledgerRefreshCycle): - } + // TODO: Wait for a USB hotplug event (not supported yet) or a refresh timeout + // <-hub.changes + time.Sleep(refreshCycle) + // Run the wallet refresher hub.refreshWallets() diff --git a/accounts/usbwallet/internal/trezor/messages.pb.go b/accounts/usbwallet/internal/trezor/messages.pb.go new file mode 100644 index 000000000..15bb6fb73 --- /dev/null +++ b/accounts/usbwallet/internal/trezor/messages.pb.go @@ -0,0 +1,3081 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: messages.proto + +package trezor + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// * +// Mapping between Trezor wire identifier (uint) and a protobuf message +type MessageType int32 + +const ( + MessageType_MessageType_Initialize MessageType = 0 + MessageType_MessageType_Ping MessageType = 1 + MessageType_MessageType_Success MessageType = 2 + MessageType_MessageType_Failure MessageType = 3 + MessageType_MessageType_ChangePin MessageType = 4 + MessageType_MessageType_WipeDevice MessageType = 5 + MessageType_MessageType_FirmwareErase MessageType = 6 + MessageType_MessageType_FirmwareUpload MessageType = 7 + MessageType_MessageType_FirmwareRequest MessageType = 8 + MessageType_MessageType_GetEntropy MessageType = 9 + MessageType_MessageType_Entropy MessageType = 10 + MessageType_MessageType_GetPublicKey MessageType = 11 + MessageType_MessageType_PublicKey MessageType = 12 + MessageType_MessageType_LoadDevice MessageType = 13 + MessageType_MessageType_ResetDevice MessageType = 14 + MessageType_MessageType_SignTx MessageType = 15 + MessageType_MessageType_SimpleSignTx MessageType = 16 + MessageType_MessageType_Features MessageType = 17 + MessageType_MessageType_PinMatrixRequest MessageType = 18 + MessageType_MessageType_PinMatrixAck MessageType = 19 + MessageType_MessageType_Cancel MessageType = 20 + MessageType_MessageType_TxRequest MessageType = 21 + MessageType_MessageType_TxAck MessageType = 22 + MessageType_MessageType_CipherKeyValue MessageType = 23 + MessageType_MessageType_ClearSession MessageType = 24 + MessageType_MessageType_ApplySettings MessageType = 25 + MessageType_MessageType_ButtonRequest MessageType = 26 + MessageType_MessageType_ButtonAck MessageType = 27 + MessageType_MessageType_ApplyFlags MessageType = 28 + MessageType_MessageType_GetAddress MessageType = 29 + MessageType_MessageType_Address MessageType = 30 + MessageType_MessageType_SelfTest MessageType = 32 + MessageType_MessageType_BackupDevice MessageType = 34 + MessageType_MessageType_EntropyRequest MessageType = 35 + MessageType_MessageType_EntropyAck MessageType = 36 + MessageType_MessageType_SignMessage MessageType = 38 + MessageType_MessageType_VerifyMessage MessageType = 39 + MessageType_MessageType_MessageSignature MessageType = 40 + MessageType_MessageType_PassphraseRequest MessageType = 41 + MessageType_MessageType_PassphraseAck MessageType = 42 + MessageType_MessageType_EstimateTxSize MessageType = 43 + MessageType_MessageType_TxSize MessageType = 44 + MessageType_MessageType_RecoveryDevice MessageType = 45 + MessageType_MessageType_WordRequest MessageType = 46 + MessageType_MessageType_WordAck MessageType = 47 + MessageType_MessageType_CipheredKeyValue MessageType = 48 + MessageType_MessageType_EncryptMessage MessageType = 49 + MessageType_MessageType_EncryptedMessage MessageType = 50 + MessageType_MessageType_DecryptMessage MessageType = 51 + MessageType_MessageType_DecryptedMessage MessageType = 52 + MessageType_MessageType_SignIdentity MessageType = 53 + MessageType_MessageType_SignedIdentity MessageType = 54 + MessageType_MessageType_GetFeatures MessageType = 55 + MessageType_MessageType_EthereumGetAddress MessageType = 56 + MessageType_MessageType_EthereumAddress MessageType = 57 + MessageType_MessageType_EthereumSignTx MessageType = 58 + MessageType_MessageType_EthereumTxRequest MessageType = 59 + MessageType_MessageType_EthereumTxAck MessageType = 60 + MessageType_MessageType_GetECDHSessionKey MessageType = 61 + MessageType_MessageType_ECDHSessionKey MessageType = 62 + MessageType_MessageType_SetU2FCounter MessageType = 63 + MessageType_MessageType_EthereumSignMessage MessageType = 64 + MessageType_MessageType_EthereumVerifyMessage MessageType = 65 + MessageType_MessageType_EthereumMessageSignature MessageType = 66 + MessageType_MessageType_DebugLinkDecision MessageType = 100 + MessageType_MessageType_DebugLinkGetState MessageType = 101 + MessageType_MessageType_DebugLinkState MessageType = 102 + MessageType_MessageType_DebugLinkStop MessageType = 103 + MessageType_MessageType_DebugLinkLog MessageType = 104 + MessageType_MessageType_DebugLinkMemoryRead MessageType = 110 + MessageType_MessageType_DebugLinkMemory MessageType = 111 + MessageType_MessageType_DebugLinkMemoryWrite MessageType = 112 + MessageType_MessageType_DebugLinkFlashErase MessageType = 113 +) + +var MessageType_name = map[int32]string{ + 0: "MessageType_Initialize", + 1: "MessageType_Ping", + 2: "MessageType_Success", + 3: "MessageType_Failure", + 4: "MessageType_ChangePin", + 5: "MessageType_WipeDevice", + 6: "MessageType_FirmwareErase", + 7: "MessageType_FirmwareUpload", + 8: "MessageType_FirmwareRequest", + 9: "MessageType_GetEntropy", + 10: "MessageType_Entropy", + 11: "MessageType_GetPublicKey", + 12: "MessageType_PublicKey", + 13: "MessageType_LoadDevice", + 14: "MessageType_ResetDevice", + 15: "MessageType_SignTx", + 16: "MessageType_SimpleSignTx", + 17: "MessageType_Features", + 18: "MessageType_PinMatrixRequest", + 19: "MessageType_PinMatrixAck", + 20: "MessageType_Cancel", + 21: "MessageType_TxRequest", + 22: "MessageType_TxAck", + 23: "MessageType_CipherKeyValue", + 24: "MessageType_ClearSession", + 25: "MessageType_ApplySettings", + 26: "MessageType_ButtonRequest", + 27: "MessageType_ButtonAck", + 28: "MessageType_ApplyFlags", + 29: "MessageType_GetAddress", + 30: "MessageType_Address", + 32: "MessageType_SelfTest", + 34: "MessageType_BackupDevice", + 35: "MessageType_EntropyRequest", + 36: "MessageType_EntropyAck", + 38: "MessageType_SignMessage", + 39: "MessageType_VerifyMessage", + 40: "MessageType_MessageSignature", + 41: "MessageType_PassphraseRequest", + 42: "MessageType_PassphraseAck", + 43: "MessageType_EstimateTxSize", + 44: "MessageType_TxSize", + 45: "MessageType_RecoveryDevice", + 46: "MessageType_WordRequest", + 47: "MessageType_WordAck", + 48: "MessageType_CipheredKeyValue", + 49: "MessageType_EncryptMessage", + 50: "MessageType_EncryptedMessage", + 51: "MessageType_DecryptMessage", + 52: "MessageType_DecryptedMessage", + 53: "MessageType_SignIdentity", + 54: "MessageType_SignedIdentity", + 55: "MessageType_GetFeatures", + 56: "MessageType_EthereumGetAddress", + 57: "MessageType_EthereumAddress", + 58: "MessageType_EthereumSignTx", + 59: "MessageType_EthereumTxRequest", + 60: "MessageType_EthereumTxAck", + 61: "MessageType_GetECDHSessionKey", + 62: "MessageType_ECDHSessionKey", + 63: "MessageType_SetU2FCounter", + 64: "MessageType_EthereumSignMessage", + 65: "MessageType_EthereumVerifyMessage", + 66: "MessageType_EthereumMessageSignature", + 100: "MessageType_DebugLinkDecision", + 101: "MessageType_DebugLinkGetState", + 102: "MessageType_DebugLinkState", + 103: "MessageType_DebugLinkStop", + 104: "MessageType_DebugLinkLog", + 110: "MessageType_DebugLinkMemoryRead", + 111: "MessageType_DebugLinkMemory", + 112: "MessageType_DebugLinkMemoryWrite", + 113: "MessageType_DebugLinkFlashErase", +} +var MessageType_value = map[string]int32{ + "MessageType_Initialize": 0, + "MessageType_Ping": 1, + "MessageType_Success": 2, + "MessageType_Failure": 3, + "MessageType_ChangePin": 4, + "MessageType_WipeDevice": 5, + "MessageType_FirmwareErase": 6, + "MessageType_FirmwareUpload": 7, + "MessageType_FirmwareRequest": 8, + "MessageType_GetEntropy": 9, + "MessageType_Entropy": 10, + "MessageType_GetPublicKey": 11, + "MessageType_PublicKey": 12, + "MessageType_LoadDevice": 13, + "MessageType_ResetDevice": 14, + "MessageType_SignTx": 15, + "MessageType_SimpleSignTx": 16, + "MessageType_Features": 17, + "MessageType_PinMatrixRequest": 18, + "MessageType_PinMatrixAck": 19, + "MessageType_Cancel": 20, + "MessageType_TxRequest": 21, + "MessageType_TxAck": 22, + "MessageType_CipherKeyValue": 23, + "MessageType_ClearSession": 24, + "MessageType_ApplySettings": 25, + "MessageType_ButtonRequest": 26, + "MessageType_ButtonAck": 27, + "MessageType_ApplyFlags": 28, + "MessageType_GetAddress": 29, + "MessageType_Address": 30, + "MessageType_SelfTest": 32, + "MessageType_BackupDevice": 34, + "MessageType_EntropyRequest": 35, + "MessageType_EntropyAck": 36, + "MessageType_SignMessage": 38, + "MessageType_VerifyMessage": 39, + "MessageType_MessageSignature": 40, + "MessageType_PassphraseRequest": 41, + "MessageType_PassphraseAck": 42, + "MessageType_EstimateTxSize": 43, + "MessageType_TxSize": 44, + "MessageType_RecoveryDevice": 45, + "MessageType_WordRequest": 46, + "MessageType_WordAck": 47, + "MessageType_CipheredKeyValue": 48, + "MessageType_EncryptMessage": 49, + "MessageType_EncryptedMessage": 50, + "MessageType_DecryptMessage": 51, + "MessageType_DecryptedMessage": 52, + "MessageType_SignIdentity": 53, + "MessageType_SignedIdentity": 54, + "MessageType_GetFeatures": 55, + "MessageType_EthereumGetAddress": 56, + "MessageType_EthereumAddress": 57, + "MessageType_EthereumSignTx": 58, + "MessageType_EthereumTxRequest": 59, + "MessageType_EthereumTxAck": 60, + "MessageType_GetECDHSessionKey": 61, + "MessageType_ECDHSessionKey": 62, + "MessageType_SetU2FCounter": 63, + "MessageType_EthereumSignMessage": 64, + "MessageType_EthereumVerifyMessage": 65, + "MessageType_EthereumMessageSignature": 66, + "MessageType_DebugLinkDecision": 100, + "MessageType_DebugLinkGetState": 101, + "MessageType_DebugLinkState": 102, + "MessageType_DebugLinkStop": 103, + "MessageType_DebugLinkLog": 104, + "MessageType_DebugLinkMemoryRead": 110, + "MessageType_DebugLinkMemory": 111, + "MessageType_DebugLinkMemoryWrite": 112, + "MessageType_DebugLinkFlashErase": 113, +} + +func (x MessageType) Enum() *MessageType { + p := new(MessageType) + *p = x + return p +} +func (x MessageType) String() string { + return proto.EnumName(MessageType_name, int32(x)) +} +func (x *MessageType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(MessageType_value, data, "MessageType") + if err != nil { + return err + } + *x = MessageType(value) + return nil +} +func (MessageType) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } + +// * +// Request: Reset device to default state and ask for device details +// @next Features +type Initialize struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *Initialize) Reset() { *m = Initialize{} } +func (m *Initialize) String() string { return proto.CompactTextString(m) } +func (*Initialize) ProtoMessage() {} +func (*Initialize) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } + +// * +// Request: Ask for device details (no device reset) +// @next Features +type GetFeatures struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *GetFeatures) Reset() { *m = GetFeatures{} } +func (m *GetFeatures) String() string { return proto.CompactTextString(m) } +func (*GetFeatures) ProtoMessage() {} +func (*GetFeatures) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } + +// * +// Response: Reports various information about the device +// @prev Initialize +// @prev GetFeatures +type Features struct { + Vendor *string `protobuf:"bytes,1,opt,name=vendor" json:"vendor,omitempty"` + MajorVersion *uint32 `protobuf:"varint,2,opt,name=major_version,json=majorVersion" json:"major_version,omitempty"` + MinorVersion *uint32 `protobuf:"varint,3,opt,name=minor_version,json=minorVersion" json:"minor_version,omitempty"` + PatchVersion *uint32 `protobuf:"varint,4,opt,name=patch_version,json=patchVersion" json:"patch_version,omitempty"` + BootloaderMode *bool `protobuf:"varint,5,opt,name=bootloader_mode,json=bootloaderMode" json:"bootloader_mode,omitempty"` + DeviceId *string `protobuf:"bytes,6,opt,name=device_id,json=deviceId" json:"device_id,omitempty"` + PinProtection *bool `protobuf:"varint,7,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` + PassphraseProtection *bool `protobuf:"varint,8,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + Language *string `protobuf:"bytes,9,opt,name=language" json:"language,omitempty"` + Label *string `protobuf:"bytes,10,opt,name=label" json:"label,omitempty"` + Coins []*CoinType `protobuf:"bytes,11,rep,name=coins" json:"coins,omitempty"` + Initialized *bool `protobuf:"varint,12,opt,name=initialized" json:"initialized,omitempty"` + Revision []byte `protobuf:"bytes,13,opt,name=revision" json:"revision,omitempty"` + BootloaderHash []byte `protobuf:"bytes,14,opt,name=bootloader_hash,json=bootloaderHash" json:"bootloader_hash,omitempty"` + Imported *bool `protobuf:"varint,15,opt,name=imported" json:"imported,omitempty"` + PinCached *bool `protobuf:"varint,16,opt,name=pin_cached,json=pinCached" json:"pin_cached,omitempty"` + PassphraseCached *bool `protobuf:"varint,17,opt,name=passphrase_cached,json=passphraseCached" json:"passphrase_cached,omitempty"` + FirmwarePresent *bool `protobuf:"varint,18,opt,name=firmware_present,json=firmwarePresent" json:"firmware_present,omitempty"` + NeedsBackup *bool `protobuf:"varint,19,opt,name=needs_backup,json=needsBackup" json:"needs_backup,omitempty"` + Flags *uint32 `protobuf:"varint,20,opt,name=flags" json:"flags,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Features) Reset() { *m = Features{} } +func (m *Features) String() string { return proto.CompactTextString(m) } +func (*Features) ProtoMessage() {} +func (*Features) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } + +func (m *Features) GetVendor() string { + if m != nil && m.Vendor != nil { + return *m.Vendor + } + return "" +} + +func (m *Features) GetMajorVersion() uint32 { + if m != nil && m.MajorVersion != nil { + return *m.MajorVersion + } + return 0 +} + +func (m *Features) GetMinorVersion() uint32 { + if m != nil && m.MinorVersion != nil { + return *m.MinorVersion + } + return 0 +} + +func (m *Features) GetPatchVersion() uint32 { + if m != nil && m.PatchVersion != nil { + return *m.PatchVersion + } + return 0 +} + +func (m *Features) GetBootloaderMode() bool { + if m != nil && m.BootloaderMode != nil { + return *m.BootloaderMode + } + return false +} + +func (m *Features) GetDeviceId() string { + if m != nil && m.DeviceId != nil { + return *m.DeviceId + } + return "" +} + +func (m *Features) GetPinProtection() bool { + if m != nil && m.PinProtection != nil { + return *m.PinProtection + } + return false +} + +func (m *Features) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *Features) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return "" +} + +func (m *Features) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *Features) GetCoins() []*CoinType { + if m != nil { + return m.Coins + } + return nil +} + +func (m *Features) GetInitialized() bool { + if m != nil && m.Initialized != nil { + return *m.Initialized + } + return false +} + +func (m *Features) GetRevision() []byte { + if m != nil { + return m.Revision + } + return nil +} + +func (m *Features) GetBootloaderHash() []byte { + if m != nil { + return m.BootloaderHash + } + return nil +} + +func (m *Features) GetImported() bool { + if m != nil && m.Imported != nil { + return *m.Imported + } + return false +} + +func (m *Features) GetPinCached() bool { + if m != nil && m.PinCached != nil { + return *m.PinCached + } + return false +} + +func (m *Features) GetPassphraseCached() bool { + if m != nil && m.PassphraseCached != nil { + return *m.PassphraseCached + } + return false +} + +func (m *Features) GetFirmwarePresent() bool { + if m != nil && m.FirmwarePresent != nil { + return *m.FirmwarePresent + } + return false +} + +func (m *Features) GetNeedsBackup() bool { + if m != nil && m.NeedsBackup != nil { + return *m.NeedsBackup + } + return false +} + +func (m *Features) GetFlags() uint32 { + if m != nil && m.Flags != nil { + return *m.Flags + } + return 0 +} + +// * +// Request: clear session (removes cached PIN, passphrase, etc). +// @next Success +type ClearSession struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *ClearSession) Reset() { *m = ClearSession{} } +func (m *ClearSession) String() string { return proto.CompactTextString(m) } +func (*ClearSession) ProtoMessage() {} +func (*ClearSession) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } + +// * +// Request: change language and/or label of the device +// @next Success +// @next Failure +// @next ButtonRequest +// @next PinMatrixRequest +type ApplySettings struct { + Language *string `protobuf:"bytes,1,opt,name=language" json:"language,omitempty"` + Label *string `protobuf:"bytes,2,opt,name=label" json:"label,omitempty"` + UsePassphrase *bool `protobuf:"varint,3,opt,name=use_passphrase,json=usePassphrase" json:"use_passphrase,omitempty"` + Homescreen []byte `protobuf:"bytes,4,opt,name=homescreen" json:"homescreen,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ApplySettings) Reset() { *m = ApplySettings{} } +func (m *ApplySettings) String() string { return proto.CompactTextString(m) } +func (*ApplySettings) ProtoMessage() {} +func (*ApplySettings) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{4} } + +func (m *ApplySettings) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return "" +} + +func (m *ApplySettings) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *ApplySettings) GetUsePassphrase() bool { + if m != nil && m.UsePassphrase != nil { + return *m.UsePassphrase + } + return false +} + +func (m *ApplySettings) GetHomescreen() []byte { + if m != nil { + return m.Homescreen + } + return nil +} + +// * +// Request: set flags of the device +// @next Success +// @next Failure +type ApplyFlags struct { + Flags *uint32 `protobuf:"varint,1,opt,name=flags" json:"flags,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ApplyFlags) Reset() { *m = ApplyFlags{} } +func (m *ApplyFlags) String() string { return proto.CompactTextString(m) } +func (*ApplyFlags) ProtoMessage() {} +func (*ApplyFlags) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{5} } + +func (m *ApplyFlags) GetFlags() uint32 { + if m != nil && m.Flags != nil { + return *m.Flags + } + return 0 +} + +// * +// Request: Starts workflow for setting/changing/removing the PIN +// @next ButtonRequest +// @next PinMatrixRequest +type ChangePin struct { + Remove *bool `protobuf:"varint,1,opt,name=remove" json:"remove,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ChangePin) Reset() { *m = ChangePin{} } +func (m *ChangePin) String() string { return proto.CompactTextString(m) } +func (*ChangePin) ProtoMessage() {} +func (*ChangePin) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{6} } + +func (m *ChangePin) GetRemove() bool { + if m != nil && m.Remove != nil { + return *m.Remove + } + return false +} + +// * +// Request: Test if the device is alive, device sends back the message in Success response +// @next Success +type Ping struct { + Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + ButtonProtection *bool `protobuf:"varint,2,opt,name=button_protection,json=buttonProtection" json:"button_protection,omitempty"` + PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` + PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Ping) Reset() { *m = Ping{} } +func (m *Ping) String() string { return proto.CompactTextString(m) } +func (*Ping) ProtoMessage() {} +func (*Ping) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{7} } + +func (m *Ping) GetMessage() string { + if m != nil && m.Message != nil { + return *m.Message + } + return "" +} + +func (m *Ping) GetButtonProtection() bool { + if m != nil && m.ButtonProtection != nil { + return *m.ButtonProtection + } + return false +} + +func (m *Ping) GetPinProtection() bool { + if m != nil && m.PinProtection != nil { + return *m.PinProtection + } + return false +} + +func (m *Ping) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +// * +// Response: Success of the previous request +type Success struct { + Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Success) Reset() { *m = Success{} } +func (m *Success) String() string { return proto.CompactTextString(m) } +func (*Success) ProtoMessage() {} +func (*Success) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{8} } + +func (m *Success) GetMessage() string { + if m != nil && m.Message != nil { + return *m.Message + } + return "" +} + +// * +// Response: Failure of the previous request +type Failure struct { + Code *FailureType `protobuf:"varint,1,opt,name=code,enum=FailureType" json:"code,omitempty"` + Message *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Failure) Reset() { *m = Failure{} } +func (m *Failure) String() string { return proto.CompactTextString(m) } +func (*Failure) ProtoMessage() {} +func (*Failure) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{9} } + +func (m *Failure) GetCode() FailureType { + if m != nil && m.Code != nil { + return *m.Code + } + return FailureType_Failure_UnexpectedMessage +} + +func (m *Failure) GetMessage() string { + if m != nil && m.Message != nil { + return *m.Message + } + return "" +} + +// * +// Response: Device is waiting for HW button press. +// @next ButtonAck +// @next Cancel +type ButtonRequest struct { + Code *ButtonRequestType `protobuf:"varint,1,opt,name=code,enum=ButtonRequestType" json:"code,omitempty"` + Data *string `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ButtonRequest) Reset() { *m = ButtonRequest{} } +func (m *ButtonRequest) String() string { return proto.CompactTextString(m) } +func (*ButtonRequest) ProtoMessage() {} +func (*ButtonRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{10} } + +func (m *ButtonRequest) GetCode() ButtonRequestType { + if m != nil && m.Code != nil { + return *m.Code + } + return ButtonRequestType_ButtonRequest_Other +} + +func (m *ButtonRequest) GetData() string { + if m != nil && m.Data != nil { + return *m.Data + } + return "" +} + +// * +// Request: Computer agrees to wait for HW button press +// @prev ButtonRequest +type ButtonAck struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *ButtonAck) Reset() { *m = ButtonAck{} } +func (m *ButtonAck) String() string { return proto.CompactTextString(m) } +func (*ButtonAck) ProtoMessage() {} +func (*ButtonAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{11} } + +// * +// Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme +// @next PinMatrixAck +// @next Cancel +type PinMatrixRequest struct { + Type *PinMatrixRequestType `protobuf:"varint,1,opt,name=type,enum=PinMatrixRequestType" json:"type,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *PinMatrixRequest) Reset() { *m = PinMatrixRequest{} } +func (m *PinMatrixRequest) String() string { return proto.CompactTextString(m) } +func (*PinMatrixRequest) ProtoMessage() {} +func (*PinMatrixRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{12} } + +func (m *PinMatrixRequest) GetType() PinMatrixRequestType { + if m != nil && m.Type != nil { + return *m.Type + } + return PinMatrixRequestType_PinMatrixRequestType_Current +} + +// * +// Request: Computer responds with encoded PIN +// @prev PinMatrixRequest +type PinMatrixAck struct { + Pin *string `protobuf:"bytes,1,req,name=pin" json:"pin,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *PinMatrixAck) Reset() { *m = PinMatrixAck{} } +func (m *PinMatrixAck) String() string { return proto.CompactTextString(m) } +func (*PinMatrixAck) ProtoMessage() {} +func (*PinMatrixAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{13} } + +func (m *PinMatrixAck) GetPin() string { + if m != nil && m.Pin != nil { + return *m.Pin + } + return "" +} + +// * +// Request: Abort last operation that required user interaction +// @prev ButtonRequest +// @prev PinMatrixRequest +// @prev PassphraseRequest +type Cancel struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *Cancel) Reset() { *m = Cancel{} } +func (m *Cancel) String() string { return proto.CompactTextString(m) } +func (*Cancel) ProtoMessage() {} +func (*Cancel) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{14} } + +// * +// Response: Device awaits encryption passphrase +// @next PassphraseAck +// @next Cancel +type PassphraseRequest struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *PassphraseRequest) Reset() { *m = PassphraseRequest{} } +func (m *PassphraseRequest) String() string { return proto.CompactTextString(m) } +func (*PassphraseRequest) ProtoMessage() {} +func (*PassphraseRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{15} } + +// * +// Request: Send passphrase back +// @prev PassphraseRequest +type PassphraseAck struct { + Passphrase *string `protobuf:"bytes,1,req,name=passphrase" json:"passphrase,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *PassphraseAck) Reset() { *m = PassphraseAck{} } +func (m *PassphraseAck) String() string { return proto.CompactTextString(m) } +func (*PassphraseAck) ProtoMessage() {} +func (*PassphraseAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{16} } + +func (m *PassphraseAck) GetPassphrase() string { + if m != nil && m.Passphrase != nil { + return *m.Passphrase + } + return "" +} + +// * +// Request: Request a sample of random data generated by hardware RNG. May be used for testing. +// @next ButtonRequest +// @next Entropy +// @next Failure +type GetEntropy struct { + Size *uint32 `protobuf:"varint,1,req,name=size" json:"size,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GetEntropy) Reset() { *m = GetEntropy{} } +func (m *GetEntropy) String() string { return proto.CompactTextString(m) } +func (*GetEntropy) ProtoMessage() {} +func (*GetEntropy) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{17} } + +func (m *GetEntropy) GetSize() uint32 { + if m != nil && m.Size != nil { + return *m.Size + } + return 0 +} + +// * +// Response: Reply with random data generated by internal RNG +// @prev GetEntropy +type Entropy struct { + Entropy []byte `protobuf:"bytes,1,req,name=entropy" json:"entropy,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Entropy) Reset() { *m = Entropy{} } +func (m *Entropy) String() string { return proto.CompactTextString(m) } +func (*Entropy) ProtoMessage() {} +func (*Entropy) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{18} } + +func (m *Entropy) GetEntropy() []byte { + if m != nil { + return m.Entropy + } + return nil +} + +// * +// Request: Ask device for public key corresponding to address_n path +// @next PassphraseRequest +// @next PublicKey +// @next Failure +type GetPublicKey struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + EcdsaCurveName *string `protobuf:"bytes,2,opt,name=ecdsa_curve_name,json=ecdsaCurveName" json:"ecdsa_curve_name,omitempty"` + ShowDisplay *bool `protobuf:"varint,3,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` + CoinName *string `protobuf:"bytes,4,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GetPublicKey) Reset() { *m = GetPublicKey{} } +func (m *GetPublicKey) String() string { return proto.CompactTextString(m) } +func (*GetPublicKey) ProtoMessage() {} +func (*GetPublicKey) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{19} } + +const Default_GetPublicKey_CoinName string = "Bitcoin" + +func (m *GetPublicKey) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *GetPublicKey) GetEcdsaCurveName() string { + if m != nil && m.EcdsaCurveName != nil { + return *m.EcdsaCurveName + } + return "" +} + +func (m *GetPublicKey) GetShowDisplay() bool { + if m != nil && m.ShowDisplay != nil { + return *m.ShowDisplay + } + return false +} + +func (m *GetPublicKey) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return Default_GetPublicKey_CoinName +} + +// * +// Response: Contains public key derived from device private seed +// @prev GetPublicKey +type PublicKey struct { + Node *HDNodeType `protobuf:"bytes,1,req,name=node" json:"node,omitempty"` + Xpub *string `protobuf:"bytes,2,opt,name=xpub" json:"xpub,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *PublicKey) Reset() { *m = PublicKey{} } +func (m *PublicKey) String() string { return proto.CompactTextString(m) } +func (*PublicKey) ProtoMessage() {} +func (*PublicKey) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{20} } + +func (m *PublicKey) GetNode() *HDNodeType { + if m != nil { + return m.Node + } + return nil +} + +func (m *PublicKey) GetXpub() string { + if m != nil && m.Xpub != nil { + return *m.Xpub + } + return "" +} + +// * +// Request: Ask device for address corresponding to address_n path +// @next PassphraseRequest +// @next Address +// @next Failure +type GetAddress struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + CoinName *string `protobuf:"bytes,2,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` + ShowDisplay *bool `protobuf:"varint,3,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` + Multisig *MultisigRedeemScriptType `protobuf:"bytes,4,opt,name=multisig" json:"multisig,omitempty"` + ScriptType *InputScriptType `protobuf:"varint,5,opt,name=script_type,json=scriptType,enum=InputScriptType,def=0" json:"script_type,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GetAddress) Reset() { *m = GetAddress{} } +func (m *GetAddress) String() string { return proto.CompactTextString(m) } +func (*GetAddress) ProtoMessage() {} +func (*GetAddress) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{21} } + +const Default_GetAddress_CoinName string = "Bitcoin" +const Default_GetAddress_ScriptType InputScriptType = InputScriptType_SPENDADDRESS + +func (m *GetAddress) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *GetAddress) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return Default_GetAddress_CoinName +} + +func (m *GetAddress) GetShowDisplay() bool { + if m != nil && m.ShowDisplay != nil { + return *m.ShowDisplay + } + return false +} + +func (m *GetAddress) GetMultisig() *MultisigRedeemScriptType { + if m != nil { + return m.Multisig + } + return nil +} + +func (m *GetAddress) GetScriptType() InputScriptType { + if m != nil && m.ScriptType != nil { + return *m.ScriptType + } + return Default_GetAddress_ScriptType +} + +// * +// Request: Ask device for Ethereum address corresponding to address_n path +// @next PassphraseRequest +// @next EthereumAddress +// @next Failure +type EthereumGetAddress struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EthereumGetAddress) Reset() { *m = EthereumGetAddress{} } +func (m *EthereumGetAddress) String() string { return proto.CompactTextString(m) } +func (*EthereumGetAddress) ProtoMessage() {} +func (*EthereumGetAddress) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{22} } + +func (m *EthereumGetAddress) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *EthereumGetAddress) GetShowDisplay() bool { + if m != nil && m.ShowDisplay != nil { + return *m.ShowDisplay + } + return false +} + +// * +// Response: Contains address derived from device private seed +// @prev GetAddress +type Address struct { + Address *string `protobuf:"bytes,1,req,name=address" json:"address,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Address) Reset() { *m = Address{} } +func (m *Address) String() string { return proto.CompactTextString(m) } +func (*Address) ProtoMessage() {} +func (*Address) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{23} } + +func (m *Address) GetAddress() string { + if m != nil && m.Address != nil { + return *m.Address + } + return "" +} + +// * +// Response: Contains an Ethereum address derived from device private seed +// @prev EthereumGetAddress +type EthereumAddress struct { + Address []byte `protobuf:"bytes,1,req,name=address" json:"address,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EthereumAddress) Reset() { *m = EthereumAddress{} } +func (m *EthereumAddress) String() string { return proto.CompactTextString(m) } +func (*EthereumAddress) ProtoMessage() {} +func (*EthereumAddress) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{24} } + +func (m *EthereumAddress) GetAddress() []byte { + if m != nil { + return m.Address + } + return nil +} + +// * +// Request: Request device to wipe all sensitive data and settings +// @next ButtonRequest +type WipeDevice struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *WipeDevice) Reset() { *m = WipeDevice{} } +func (m *WipeDevice) String() string { return proto.CompactTextString(m) } +func (*WipeDevice) ProtoMessage() {} +func (*WipeDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{25} } + +// * +// Request: Load seed and related internal settings from the computer +// @next ButtonRequest +// @next Success +// @next Failure +type LoadDevice struct { + Mnemonic *string `protobuf:"bytes,1,opt,name=mnemonic" json:"mnemonic,omitempty"` + Node *HDNodeType `protobuf:"bytes,2,opt,name=node" json:"node,omitempty"` + Pin *string `protobuf:"bytes,3,opt,name=pin" json:"pin,omitempty"` + PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` + Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` + SkipChecksum *bool `protobuf:"varint,7,opt,name=skip_checksum,json=skipChecksum" json:"skip_checksum,omitempty"` + U2FCounter *uint32 `protobuf:"varint,8,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *LoadDevice) Reset() { *m = LoadDevice{} } +func (m *LoadDevice) String() string { return proto.CompactTextString(m) } +func (*LoadDevice) ProtoMessage() {} +func (*LoadDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{26} } + +const Default_LoadDevice_Language string = "english" + +func (m *LoadDevice) GetMnemonic() string { + if m != nil && m.Mnemonic != nil { + return *m.Mnemonic + } + return "" +} + +func (m *LoadDevice) GetNode() *HDNodeType { + if m != nil { + return m.Node + } + return nil +} + +func (m *LoadDevice) GetPin() string { + if m != nil && m.Pin != nil { + return *m.Pin + } + return "" +} + +func (m *LoadDevice) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *LoadDevice) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return Default_LoadDevice_Language +} + +func (m *LoadDevice) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *LoadDevice) GetSkipChecksum() bool { + if m != nil && m.SkipChecksum != nil { + return *m.SkipChecksum + } + return false +} + +func (m *LoadDevice) GetU2FCounter() uint32 { + if m != nil && m.U2FCounter != nil { + return *m.U2FCounter + } + return 0 +} + +// * +// Request: Ask device to do initialization involving user interaction +// @next EntropyRequest +// @next Failure +type ResetDevice struct { + DisplayRandom *bool `protobuf:"varint,1,opt,name=display_random,json=displayRandom" json:"display_random,omitempty"` + Strength *uint32 `protobuf:"varint,2,opt,name=strength,def=256" json:"strength,omitempty"` + PassphraseProtection *bool `protobuf:"varint,3,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + PinProtection *bool `protobuf:"varint,4,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` + Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` + Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` + U2FCounter *uint32 `protobuf:"varint,7,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` + SkipBackup *bool `protobuf:"varint,8,opt,name=skip_backup,json=skipBackup" json:"skip_backup,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ResetDevice) Reset() { *m = ResetDevice{} } +func (m *ResetDevice) String() string { return proto.CompactTextString(m) } +func (*ResetDevice) ProtoMessage() {} +func (*ResetDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{27} } + +const Default_ResetDevice_Strength uint32 = 256 +const Default_ResetDevice_Language string = "english" + +func (m *ResetDevice) GetDisplayRandom() bool { + if m != nil && m.DisplayRandom != nil { + return *m.DisplayRandom + } + return false +} + +func (m *ResetDevice) GetStrength() uint32 { + if m != nil && m.Strength != nil { + return *m.Strength + } + return Default_ResetDevice_Strength +} + +func (m *ResetDevice) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *ResetDevice) GetPinProtection() bool { + if m != nil && m.PinProtection != nil { + return *m.PinProtection + } + return false +} + +func (m *ResetDevice) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return Default_ResetDevice_Language +} + +func (m *ResetDevice) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *ResetDevice) GetU2FCounter() uint32 { + if m != nil && m.U2FCounter != nil { + return *m.U2FCounter + } + return 0 +} + +func (m *ResetDevice) GetSkipBackup() bool { + if m != nil && m.SkipBackup != nil { + return *m.SkipBackup + } + return false +} + +// * +// Request: Perform backup of the device seed if not backed up using ResetDevice +// @next ButtonRequest +type BackupDevice struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *BackupDevice) Reset() { *m = BackupDevice{} } +func (m *BackupDevice) String() string { return proto.CompactTextString(m) } +func (*BackupDevice) ProtoMessage() {} +func (*BackupDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{28} } + +// * +// Response: Ask for additional entropy from host computer +// @prev ResetDevice +// @next EntropyAck +type EntropyRequest struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *EntropyRequest) Reset() { *m = EntropyRequest{} } +func (m *EntropyRequest) String() string { return proto.CompactTextString(m) } +func (*EntropyRequest) ProtoMessage() {} +func (*EntropyRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{29} } + +// * +// Request: Provide additional entropy for seed generation function +// @prev EntropyRequest +// @next ButtonRequest +type EntropyAck struct { + Entropy []byte `protobuf:"bytes,1,opt,name=entropy" json:"entropy,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EntropyAck) Reset() { *m = EntropyAck{} } +func (m *EntropyAck) String() string { return proto.CompactTextString(m) } +func (*EntropyAck) ProtoMessage() {} +func (*EntropyAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{30} } + +func (m *EntropyAck) GetEntropy() []byte { + if m != nil { + return m.Entropy + } + return nil +} + +// * +// Request: Start recovery workflow asking user for specific words of mnemonic +// Used to recovery device safely even on untrusted computer. +// @next WordRequest +type RecoveryDevice struct { + WordCount *uint32 `protobuf:"varint,1,opt,name=word_count,json=wordCount" json:"word_count,omitempty"` + PassphraseProtection *bool `protobuf:"varint,2,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` + Language *string `protobuf:"bytes,4,opt,name=language,def=english" json:"language,omitempty"` + Label *string `protobuf:"bytes,5,opt,name=label" json:"label,omitempty"` + EnforceWordlist *bool `protobuf:"varint,6,opt,name=enforce_wordlist,json=enforceWordlist" json:"enforce_wordlist,omitempty"` + // 7 reserved for unused recovery method + Type *uint32 `protobuf:"varint,8,opt,name=type" json:"type,omitempty"` + U2FCounter *uint32 `protobuf:"varint,9,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` + DryRun *bool `protobuf:"varint,10,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *RecoveryDevice) Reset() { *m = RecoveryDevice{} } +func (m *RecoveryDevice) String() string { return proto.CompactTextString(m) } +func (*RecoveryDevice) ProtoMessage() {} +func (*RecoveryDevice) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{31} } + +const Default_RecoveryDevice_Language string = "english" + +func (m *RecoveryDevice) GetWordCount() uint32 { + if m != nil && m.WordCount != nil { + return *m.WordCount + } + return 0 +} + +func (m *RecoveryDevice) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *RecoveryDevice) GetPinProtection() bool { + if m != nil && m.PinProtection != nil { + return *m.PinProtection + } + return false +} + +func (m *RecoveryDevice) GetLanguage() string { + if m != nil && m.Language != nil { + return *m.Language + } + return Default_RecoveryDevice_Language +} + +func (m *RecoveryDevice) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" +} + +func (m *RecoveryDevice) GetEnforceWordlist() bool { + if m != nil && m.EnforceWordlist != nil { + return *m.EnforceWordlist + } + return false +} + +func (m *RecoveryDevice) GetType() uint32 { + if m != nil && m.Type != nil { + return *m.Type + } + return 0 +} + +func (m *RecoveryDevice) GetU2FCounter() uint32 { + if m != nil && m.U2FCounter != nil { + return *m.U2FCounter + } + return 0 +} + +func (m *RecoveryDevice) GetDryRun() bool { + if m != nil && m.DryRun != nil { + return *m.DryRun + } + return false +} + +// * +// Response: Device is waiting for user to enter word of the mnemonic +// Its position is shown only on device's internal display. +// @prev RecoveryDevice +// @prev WordAck +type WordRequest struct { + Type *WordRequestType `protobuf:"varint,1,opt,name=type,enum=WordRequestType" json:"type,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *WordRequest) Reset() { *m = WordRequest{} } +func (m *WordRequest) String() string { return proto.CompactTextString(m) } +func (*WordRequest) ProtoMessage() {} +func (*WordRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{32} } + +func (m *WordRequest) GetType() WordRequestType { + if m != nil && m.Type != nil { + return *m.Type + } + return WordRequestType_WordRequestType_Plain +} + +// * +// Request: Computer replies with word from the mnemonic +// @prev WordRequest +// @next WordRequest +// @next Success +// @next Failure +type WordAck struct { + Word *string `protobuf:"bytes,1,req,name=word" json:"word,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *WordAck) Reset() { *m = WordAck{} } +func (m *WordAck) String() string { return proto.CompactTextString(m) } +func (*WordAck) ProtoMessage() {} +func (*WordAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{33} } + +func (m *WordAck) GetWord() string { + if m != nil && m.Word != nil { + return *m.Word + } + return "" +} + +// * +// Request: Ask device to sign message +// @next MessageSignature +// @next Failure +type SignMessage struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + Message []byte `protobuf:"bytes,2,req,name=message" json:"message,omitempty"` + CoinName *string `protobuf:"bytes,3,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` + ScriptType *InputScriptType `protobuf:"varint,4,opt,name=script_type,json=scriptType,enum=InputScriptType,def=0" json:"script_type,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SignMessage) Reset() { *m = SignMessage{} } +func (m *SignMessage) String() string { return proto.CompactTextString(m) } +func (*SignMessage) ProtoMessage() {} +func (*SignMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{34} } + +const Default_SignMessage_CoinName string = "Bitcoin" +const Default_SignMessage_ScriptType InputScriptType = InputScriptType_SPENDADDRESS + +func (m *SignMessage) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *SignMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +func (m *SignMessage) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return Default_SignMessage_CoinName +} + +func (m *SignMessage) GetScriptType() InputScriptType { + if m != nil && m.ScriptType != nil { + return *m.ScriptType + } + return Default_SignMessage_ScriptType +} + +// * +// Request: Ask device to verify message +// @next Success +// @next Failure +type VerifyMessage struct { + Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` + CoinName *string `protobuf:"bytes,4,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *VerifyMessage) Reset() { *m = VerifyMessage{} } +func (m *VerifyMessage) String() string { return proto.CompactTextString(m) } +func (*VerifyMessage) ProtoMessage() {} +func (*VerifyMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{35} } + +const Default_VerifyMessage_CoinName string = "Bitcoin" + +func (m *VerifyMessage) GetAddress() string { + if m != nil && m.Address != nil { + return *m.Address + } + return "" +} + +func (m *VerifyMessage) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func (m *VerifyMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +func (m *VerifyMessage) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return Default_VerifyMessage_CoinName +} + +// * +// Response: Signed message +// @prev SignMessage +type MessageSignature struct { + Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MessageSignature) Reset() { *m = MessageSignature{} } +func (m *MessageSignature) String() string { return proto.CompactTextString(m) } +func (*MessageSignature) ProtoMessage() {} +func (*MessageSignature) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{36} } + +func (m *MessageSignature) GetAddress() string { + if m != nil && m.Address != nil { + return *m.Address + } + return "" +} + +func (m *MessageSignature) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +// * +// Request: Ask device to encrypt message +// @next EncryptedMessage +// @next Failure +type EncryptMessage struct { + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey" json:"pubkey,omitempty"` + Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` + DisplayOnly *bool `protobuf:"varint,3,opt,name=display_only,json=displayOnly" json:"display_only,omitempty"` + AddressN []uint32 `protobuf:"varint,4,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + CoinName *string `protobuf:"bytes,5,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EncryptMessage) Reset() { *m = EncryptMessage{} } +func (m *EncryptMessage) String() string { return proto.CompactTextString(m) } +func (*EncryptMessage) ProtoMessage() {} +func (*EncryptMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{37} } + +const Default_EncryptMessage_CoinName string = "Bitcoin" + +func (m *EncryptMessage) GetPubkey() []byte { + if m != nil { + return m.Pubkey + } + return nil +} + +func (m *EncryptMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +func (m *EncryptMessage) GetDisplayOnly() bool { + if m != nil && m.DisplayOnly != nil { + return *m.DisplayOnly + } + return false +} + +func (m *EncryptMessage) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *EncryptMessage) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return Default_EncryptMessage_CoinName +} + +// * +// Response: Encrypted message +// @prev EncryptMessage +type EncryptedMessage struct { + Nonce []byte `protobuf:"bytes,1,opt,name=nonce" json:"nonce,omitempty"` + Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` + Hmac []byte `protobuf:"bytes,3,opt,name=hmac" json:"hmac,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EncryptedMessage) Reset() { *m = EncryptedMessage{} } +func (m *EncryptedMessage) String() string { return proto.CompactTextString(m) } +func (*EncryptedMessage) ProtoMessage() {} +func (*EncryptedMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{38} } + +func (m *EncryptedMessage) GetNonce() []byte { + if m != nil { + return m.Nonce + } + return nil +} + +func (m *EncryptedMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +func (m *EncryptedMessage) GetHmac() []byte { + if m != nil { + return m.Hmac + } + return nil +} + +// * +// Request: Ask device to decrypt message +// @next Success +// @next Failure +type DecryptMessage struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + Nonce []byte `protobuf:"bytes,2,opt,name=nonce" json:"nonce,omitempty"` + Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` + Hmac []byte `protobuf:"bytes,4,opt,name=hmac" json:"hmac,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DecryptMessage) Reset() { *m = DecryptMessage{} } +func (m *DecryptMessage) String() string { return proto.CompactTextString(m) } +func (*DecryptMessage) ProtoMessage() {} +func (*DecryptMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{39} } + +func (m *DecryptMessage) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *DecryptMessage) GetNonce() []byte { + if m != nil { + return m.Nonce + } + return nil +} + +func (m *DecryptMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +func (m *DecryptMessage) GetHmac() []byte { + if m != nil { + return m.Hmac + } + return nil +} + +// * +// Response: Decrypted message +// @prev DecryptedMessage +type DecryptedMessage struct { + Message []byte `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + Address *string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DecryptedMessage) Reset() { *m = DecryptedMessage{} } +func (m *DecryptedMessage) String() string { return proto.CompactTextString(m) } +func (*DecryptedMessage) ProtoMessage() {} +func (*DecryptedMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{40} } + +func (m *DecryptedMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +func (m *DecryptedMessage) GetAddress() string { + if m != nil && m.Address != nil { + return *m.Address + } + return "" +} + +// * +// Request: Ask device to encrypt or decrypt value of given key +// @next CipheredKeyValue +// @next Failure +type CipherKeyValue struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + Key *string `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"` + Value []byte `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"` + Encrypt *bool `protobuf:"varint,4,opt,name=encrypt" json:"encrypt,omitempty"` + AskOnEncrypt *bool `protobuf:"varint,5,opt,name=ask_on_encrypt,json=askOnEncrypt" json:"ask_on_encrypt,omitempty"` + AskOnDecrypt *bool `protobuf:"varint,6,opt,name=ask_on_decrypt,json=askOnDecrypt" json:"ask_on_decrypt,omitempty"` + Iv []byte `protobuf:"bytes,7,opt,name=iv" json:"iv,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *CipherKeyValue) Reset() { *m = CipherKeyValue{} } +func (m *CipherKeyValue) String() string { return proto.CompactTextString(m) } +func (*CipherKeyValue) ProtoMessage() {} +func (*CipherKeyValue) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{41} } + +func (m *CipherKeyValue) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *CipherKeyValue) GetKey() string { + if m != nil && m.Key != nil { + return *m.Key + } + return "" +} + +func (m *CipherKeyValue) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func (m *CipherKeyValue) GetEncrypt() bool { + if m != nil && m.Encrypt != nil { + return *m.Encrypt + } + return false +} + +func (m *CipherKeyValue) GetAskOnEncrypt() bool { + if m != nil && m.AskOnEncrypt != nil { + return *m.AskOnEncrypt + } + return false +} + +func (m *CipherKeyValue) GetAskOnDecrypt() bool { + if m != nil && m.AskOnDecrypt != nil { + return *m.AskOnDecrypt + } + return false +} + +func (m *CipherKeyValue) GetIv() []byte { + if m != nil { + return m.Iv + } + return nil +} + +// * +// Response: Return ciphered/deciphered value +// @prev CipherKeyValue +type CipheredKeyValue struct { + Value []byte `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *CipheredKeyValue) Reset() { *m = CipheredKeyValue{} } +func (m *CipheredKeyValue) String() string { return proto.CompactTextString(m) } +func (*CipheredKeyValue) ProtoMessage() {} +func (*CipheredKeyValue) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{42} } + +func (m *CipheredKeyValue) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +// * +// Request: Estimated size of the transaction +// This behaves exactly like SignTx, which means that it can ask using TxRequest +// This call is non-blocking (except possible PassphraseRequest to unlock the seed) +// @next TxSize +// @next Failure +type EstimateTxSize struct { + OutputsCount *uint32 `protobuf:"varint,1,req,name=outputs_count,json=outputsCount" json:"outputs_count,omitempty"` + InputsCount *uint32 `protobuf:"varint,2,req,name=inputs_count,json=inputsCount" json:"inputs_count,omitempty"` + CoinName *string `protobuf:"bytes,3,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EstimateTxSize) Reset() { *m = EstimateTxSize{} } +func (m *EstimateTxSize) String() string { return proto.CompactTextString(m) } +func (*EstimateTxSize) ProtoMessage() {} +func (*EstimateTxSize) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{43} } + +const Default_EstimateTxSize_CoinName string = "Bitcoin" + +func (m *EstimateTxSize) GetOutputsCount() uint32 { + if m != nil && m.OutputsCount != nil { + return *m.OutputsCount + } + return 0 +} + +func (m *EstimateTxSize) GetInputsCount() uint32 { + if m != nil && m.InputsCount != nil { + return *m.InputsCount + } + return 0 +} + +func (m *EstimateTxSize) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return Default_EstimateTxSize_CoinName +} + +// * +// Response: Estimated size of the transaction +// @prev EstimateTxSize +type TxSize struct { + TxSize *uint32 `protobuf:"varint,1,opt,name=tx_size,json=txSize" json:"tx_size,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TxSize) Reset() { *m = TxSize{} } +func (m *TxSize) String() string { return proto.CompactTextString(m) } +func (*TxSize) ProtoMessage() {} +func (*TxSize) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{44} } + +func (m *TxSize) GetTxSize() uint32 { + if m != nil && m.TxSize != nil { + return *m.TxSize + } + return 0 +} + +// * +// Request: Ask device to sign transaction +// @next PassphraseRequest +// @next PinMatrixRequest +// @next TxRequest +// @next Failure +type SignTx struct { + OutputsCount *uint32 `protobuf:"varint,1,req,name=outputs_count,json=outputsCount" json:"outputs_count,omitempty"` + InputsCount *uint32 `protobuf:"varint,2,req,name=inputs_count,json=inputsCount" json:"inputs_count,omitempty"` + CoinName *string `protobuf:"bytes,3,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` + Version *uint32 `protobuf:"varint,4,opt,name=version,def=1" json:"version,omitempty"` + LockTime *uint32 `protobuf:"varint,5,opt,name=lock_time,json=lockTime,def=0" json:"lock_time,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SignTx) Reset() { *m = SignTx{} } +func (m *SignTx) String() string { return proto.CompactTextString(m) } +func (*SignTx) ProtoMessage() {} +func (*SignTx) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{45} } + +const Default_SignTx_CoinName string = "Bitcoin" +const Default_SignTx_Version uint32 = 1 +const Default_SignTx_LockTime uint32 = 0 + +func (m *SignTx) GetOutputsCount() uint32 { + if m != nil && m.OutputsCount != nil { + return *m.OutputsCount + } + return 0 +} + +func (m *SignTx) GetInputsCount() uint32 { + if m != nil && m.InputsCount != nil { + return *m.InputsCount + } + return 0 +} + +func (m *SignTx) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return Default_SignTx_CoinName +} + +func (m *SignTx) GetVersion() uint32 { + if m != nil && m.Version != nil { + return *m.Version + } + return Default_SignTx_Version +} + +func (m *SignTx) GetLockTime() uint32 { + if m != nil && m.LockTime != nil { + return *m.LockTime + } + return Default_SignTx_LockTime +} + +// * +// Request: Simplified transaction signing +// This method doesn't support streaming, so there are hardware limits in number of inputs and outputs. +// In case of success, the result is returned using TxRequest message. +// @next PassphraseRequest +// @next PinMatrixRequest +// @next TxRequest +// @next Failure +type SimpleSignTx struct { + Inputs []*TxInputType `protobuf:"bytes,1,rep,name=inputs" json:"inputs,omitempty"` + Outputs []*TxOutputType `protobuf:"bytes,2,rep,name=outputs" json:"outputs,omitempty"` + Transactions []*TransactionType `protobuf:"bytes,3,rep,name=transactions" json:"transactions,omitempty"` + CoinName *string `protobuf:"bytes,4,opt,name=coin_name,json=coinName,def=Bitcoin" json:"coin_name,omitempty"` + Version *uint32 `protobuf:"varint,5,opt,name=version,def=1" json:"version,omitempty"` + LockTime *uint32 `protobuf:"varint,6,opt,name=lock_time,json=lockTime,def=0" json:"lock_time,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SimpleSignTx) Reset() { *m = SimpleSignTx{} } +func (m *SimpleSignTx) String() string { return proto.CompactTextString(m) } +func (*SimpleSignTx) ProtoMessage() {} +func (*SimpleSignTx) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{46} } + +const Default_SimpleSignTx_CoinName string = "Bitcoin" +const Default_SimpleSignTx_Version uint32 = 1 +const Default_SimpleSignTx_LockTime uint32 = 0 + +func (m *SimpleSignTx) GetInputs() []*TxInputType { + if m != nil { + return m.Inputs + } + return nil +} + +func (m *SimpleSignTx) GetOutputs() []*TxOutputType { + if m != nil { + return m.Outputs + } + return nil +} + +func (m *SimpleSignTx) GetTransactions() []*TransactionType { + if m != nil { + return m.Transactions + } + return nil +} + +func (m *SimpleSignTx) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return Default_SimpleSignTx_CoinName +} + +func (m *SimpleSignTx) GetVersion() uint32 { + if m != nil && m.Version != nil { + return *m.Version + } + return Default_SimpleSignTx_Version +} + +func (m *SimpleSignTx) GetLockTime() uint32 { + if m != nil && m.LockTime != nil { + return *m.LockTime + } + return Default_SimpleSignTx_LockTime +} + +// * +// Response: Device asks for information for signing transaction or returns the last result +// If request_index is set, device awaits TxAck message (with fields filled in according to request_type) +// If signature_index is set, 'signature' contains signed input of signature_index's input +// @prev SignTx +// @prev SimpleSignTx +// @prev TxAck +type TxRequest struct { + RequestType *RequestType `protobuf:"varint,1,opt,name=request_type,json=requestType,enum=RequestType" json:"request_type,omitempty"` + Details *TxRequestDetailsType `protobuf:"bytes,2,opt,name=details" json:"details,omitempty"` + Serialized *TxRequestSerializedType `protobuf:"bytes,3,opt,name=serialized" json:"serialized,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TxRequest) Reset() { *m = TxRequest{} } +func (m *TxRequest) String() string { return proto.CompactTextString(m) } +func (*TxRequest) ProtoMessage() {} +func (*TxRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{47} } + +func (m *TxRequest) GetRequestType() RequestType { + if m != nil && m.RequestType != nil { + return *m.RequestType + } + return RequestType_TXINPUT +} + +func (m *TxRequest) GetDetails() *TxRequestDetailsType { + if m != nil { + return m.Details + } + return nil +} + +func (m *TxRequest) GetSerialized() *TxRequestSerializedType { + if m != nil { + return m.Serialized + } + return nil +} + +// * +// Request: Reported transaction data +// @prev TxRequest +// @next TxRequest +type TxAck struct { + Tx *TransactionType `protobuf:"bytes,1,opt,name=tx" json:"tx,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TxAck) Reset() { *m = TxAck{} } +func (m *TxAck) String() string { return proto.CompactTextString(m) } +func (*TxAck) ProtoMessage() {} +func (*TxAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{48} } + +func (m *TxAck) GetTx() *TransactionType { + if m != nil { + return m.Tx + } + return nil +} + +// * +// Request: Ask device to sign transaction +// All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing. +// Note: the first at most 1024 bytes of data MUST be transmitted as part of this message. +// @next PassphraseRequest +// @next PinMatrixRequest +// @next EthereumTxRequest +// @next Failure +type EthereumSignTx struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + Nonce []byte `protobuf:"bytes,2,opt,name=nonce" json:"nonce,omitempty"` + GasPrice []byte `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice" json:"gas_price,omitempty"` + GasLimit []byte `protobuf:"bytes,4,opt,name=gas_limit,json=gasLimit" json:"gas_limit,omitempty"` + To []byte `protobuf:"bytes,5,opt,name=to" json:"to,omitempty"` + Value []byte `protobuf:"bytes,6,opt,name=value" json:"value,omitempty"` + DataInitialChunk []byte `protobuf:"bytes,7,opt,name=data_initial_chunk,json=dataInitialChunk" json:"data_initial_chunk,omitempty"` + DataLength *uint32 `protobuf:"varint,8,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` + ChainId *uint32 `protobuf:"varint,9,opt,name=chain_id,json=chainId" json:"chain_id,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EthereumSignTx) Reset() { *m = EthereumSignTx{} } +func (m *EthereumSignTx) String() string { return proto.CompactTextString(m) } +func (*EthereumSignTx) ProtoMessage() {} +func (*EthereumSignTx) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{49} } + +func (m *EthereumSignTx) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *EthereumSignTx) GetNonce() []byte { + if m != nil { + return m.Nonce + } + return nil +} + +func (m *EthereumSignTx) GetGasPrice() []byte { + if m != nil { + return m.GasPrice + } + return nil +} + +func (m *EthereumSignTx) GetGasLimit() []byte { + if m != nil { + return m.GasLimit + } + return nil +} + +func (m *EthereumSignTx) GetTo() []byte { + if m != nil { + return m.To + } + return nil +} + +func (m *EthereumSignTx) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func (m *EthereumSignTx) GetDataInitialChunk() []byte { + if m != nil { + return m.DataInitialChunk + } + return nil +} + +func (m *EthereumSignTx) GetDataLength() uint32 { + if m != nil && m.DataLength != nil { + return *m.DataLength + } + return 0 +} + +func (m *EthereumSignTx) GetChainId() uint32 { + if m != nil && m.ChainId != nil { + return *m.ChainId + } + return 0 +} + +// * +// Response: Device asks for more data from transaction payload, or returns the signature. +// If data_length is set, device awaits that many more bytes of payload. +// Otherwise, the signature_* fields contain the computed transaction signature. All three fields will be present. +// @prev EthereumSignTx +// @next EthereumTxAck +type EthereumTxRequest struct { + DataLength *uint32 `protobuf:"varint,1,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` + SignatureV *uint32 `protobuf:"varint,2,opt,name=signature_v,json=signatureV" json:"signature_v,omitempty"` + SignatureR []byte `protobuf:"bytes,3,opt,name=signature_r,json=signatureR" json:"signature_r,omitempty"` + SignatureS []byte `protobuf:"bytes,4,opt,name=signature_s,json=signatureS" json:"signature_s,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EthereumTxRequest) Reset() { *m = EthereumTxRequest{} } +func (m *EthereumTxRequest) String() string { return proto.CompactTextString(m) } +func (*EthereumTxRequest) ProtoMessage() {} +func (*EthereumTxRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{50} } + +func (m *EthereumTxRequest) GetDataLength() uint32 { + if m != nil && m.DataLength != nil { + return *m.DataLength + } + return 0 +} + +func (m *EthereumTxRequest) GetSignatureV() uint32 { + if m != nil && m.SignatureV != nil { + return *m.SignatureV + } + return 0 +} + +func (m *EthereumTxRequest) GetSignatureR() []byte { + if m != nil { + return m.SignatureR + } + return nil +} + +func (m *EthereumTxRequest) GetSignatureS() []byte { + if m != nil { + return m.SignatureS + } + return nil +} + +// * +// Request: Transaction payload data. +// @prev EthereumTxRequest +// @next EthereumTxRequest +type EthereumTxAck struct { + DataChunk []byte `protobuf:"bytes,1,opt,name=data_chunk,json=dataChunk" json:"data_chunk,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EthereumTxAck) Reset() { *m = EthereumTxAck{} } +func (m *EthereumTxAck) String() string { return proto.CompactTextString(m) } +func (*EthereumTxAck) ProtoMessage() {} +func (*EthereumTxAck) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{51} } + +func (m *EthereumTxAck) GetDataChunk() []byte { + if m != nil { + return m.DataChunk + } + return nil +} + +// * +// Request: Ask device to sign message +// @next EthereumMessageSignature +// @next Failure +type EthereumSignMessage struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + Message []byte `protobuf:"bytes,2,req,name=message" json:"message,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EthereumSignMessage) Reset() { *m = EthereumSignMessage{} } +func (m *EthereumSignMessage) String() string { return proto.CompactTextString(m) } +func (*EthereumSignMessage) ProtoMessage() {} +func (*EthereumSignMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{52} } + +func (m *EthereumSignMessage) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *EthereumSignMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +// * +// Request: Ask device to verify message +// @next Success +// @next Failure +type EthereumVerifyMessage struct { + Address []byte `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EthereumVerifyMessage) Reset() { *m = EthereumVerifyMessage{} } +func (m *EthereumVerifyMessage) String() string { return proto.CompactTextString(m) } +func (*EthereumVerifyMessage) ProtoMessage() {} +func (*EthereumVerifyMessage) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{53} } + +func (m *EthereumVerifyMessage) GetAddress() []byte { + if m != nil { + return m.Address + } + return nil +} + +func (m *EthereumVerifyMessage) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func (m *EthereumVerifyMessage) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +// * +// Response: Signed message +// @prev EthereumSignMessage +type EthereumMessageSignature struct { + Address []byte `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EthereumMessageSignature) Reset() { *m = EthereumMessageSignature{} } +func (m *EthereumMessageSignature) String() string { return proto.CompactTextString(m) } +func (*EthereumMessageSignature) ProtoMessage() {} +func (*EthereumMessageSignature) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{54} } + +func (m *EthereumMessageSignature) GetAddress() []byte { + if m != nil { + return m.Address + } + return nil +} + +func (m *EthereumMessageSignature) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +// * +// Request: Ask device to sign identity +// @next SignedIdentity +// @next Failure +type SignIdentity struct { + Identity *IdentityType `protobuf:"bytes,1,opt,name=identity" json:"identity,omitempty"` + ChallengeHidden []byte `protobuf:"bytes,2,opt,name=challenge_hidden,json=challengeHidden" json:"challenge_hidden,omitempty"` + ChallengeVisual *string `protobuf:"bytes,3,opt,name=challenge_visual,json=challengeVisual" json:"challenge_visual,omitempty"` + EcdsaCurveName *string `protobuf:"bytes,4,opt,name=ecdsa_curve_name,json=ecdsaCurveName" json:"ecdsa_curve_name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SignIdentity) Reset() { *m = SignIdentity{} } +func (m *SignIdentity) String() string { return proto.CompactTextString(m) } +func (*SignIdentity) ProtoMessage() {} +func (*SignIdentity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{55} } + +func (m *SignIdentity) GetIdentity() *IdentityType { + if m != nil { + return m.Identity + } + return nil +} + +func (m *SignIdentity) GetChallengeHidden() []byte { + if m != nil { + return m.ChallengeHidden + } + return nil +} + +func (m *SignIdentity) GetChallengeVisual() string { + if m != nil && m.ChallengeVisual != nil { + return *m.ChallengeVisual + } + return "" +} + +func (m *SignIdentity) GetEcdsaCurveName() string { + if m != nil && m.EcdsaCurveName != nil { + return *m.EcdsaCurveName + } + return "" +} + +// * +// Response: Device provides signed identity +// @prev SignIdentity +type SignedIdentity struct { + Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey" json:"public_key,omitempty"` + Signature []byte `protobuf:"bytes,3,opt,name=signature" json:"signature,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SignedIdentity) Reset() { *m = SignedIdentity{} } +func (m *SignedIdentity) String() string { return proto.CompactTextString(m) } +func (*SignedIdentity) ProtoMessage() {} +func (*SignedIdentity) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{56} } + +func (m *SignedIdentity) GetAddress() string { + if m != nil && m.Address != nil { + return *m.Address + } + return "" +} + +func (m *SignedIdentity) GetPublicKey() []byte { + if m != nil { + return m.PublicKey + } + return nil +} + +func (m *SignedIdentity) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +// * +// Request: Ask device to generate ECDH session key +// @next ECDHSessionKey +// @next Failure +type GetECDHSessionKey struct { + Identity *IdentityType `protobuf:"bytes,1,opt,name=identity" json:"identity,omitempty"` + PeerPublicKey []byte `protobuf:"bytes,2,opt,name=peer_public_key,json=peerPublicKey" json:"peer_public_key,omitempty"` + EcdsaCurveName *string `protobuf:"bytes,3,opt,name=ecdsa_curve_name,json=ecdsaCurveName" json:"ecdsa_curve_name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GetECDHSessionKey) Reset() { *m = GetECDHSessionKey{} } +func (m *GetECDHSessionKey) String() string { return proto.CompactTextString(m) } +func (*GetECDHSessionKey) ProtoMessage() {} +func (*GetECDHSessionKey) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{57} } + +func (m *GetECDHSessionKey) GetIdentity() *IdentityType { + if m != nil { + return m.Identity + } + return nil +} + +func (m *GetECDHSessionKey) GetPeerPublicKey() []byte { + if m != nil { + return m.PeerPublicKey + } + return nil +} + +func (m *GetECDHSessionKey) GetEcdsaCurveName() string { + if m != nil && m.EcdsaCurveName != nil { + return *m.EcdsaCurveName + } + return "" +} + +// * +// Response: Device provides ECDH session key +// @prev GetECDHSessionKey +type ECDHSessionKey struct { + SessionKey []byte `protobuf:"bytes,1,opt,name=session_key,json=sessionKey" json:"session_key,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ECDHSessionKey) Reset() { *m = ECDHSessionKey{} } +func (m *ECDHSessionKey) String() string { return proto.CompactTextString(m) } +func (*ECDHSessionKey) ProtoMessage() {} +func (*ECDHSessionKey) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{58} } + +func (m *ECDHSessionKey) GetSessionKey() []byte { + if m != nil { + return m.SessionKey + } + return nil +} + +// * +// Request: Set U2F counter +// @next Success +type SetU2FCounter struct { + U2FCounter *uint32 `protobuf:"varint,1,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SetU2FCounter) Reset() { *m = SetU2FCounter{} } +func (m *SetU2FCounter) String() string { return proto.CompactTextString(m) } +func (*SetU2FCounter) ProtoMessage() {} +func (*SetU2FCounter) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{59} } + +func (m *SetU2FCounter) GetU2FCounter() uint32 { + if m != nil && m.U2FCounter != nil { + return *m.U2FCounter + } + return 0 +} + +// * +// Request: Ask device to erase its firmware (so it can be replaced via FirmwareUpload) +// @next Success +// @next FirmwareRequest +// @next Failure +type FirmwareErase struct { + Length *uint32 `protobuf:"varint,1,opt,name=length" json:"length,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FirmwareErase) Reset() { *m = FirmwareErase{} } +func (m *FirmwareErase) String() string { return proto.CompactTextString(m) } +func (*FirmwareErase) ProtoMessage() {} +func (*FirmwareErase) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{60} } + +func (m *FirmwareErase) GetLength() uint32 { + if m != nil && m.Length != nil { + return *m.Length + } + return 0 +} + +// * +// Response: Ask for firmware chunk +// @next FirmwareUpload +type FirmwareRequest struct { + Offset *uint32 `protobuf:"varint,1,opt,name=offset" json:"offset,omitempty"` + Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FirmwareRequest) Reset() { *m = FirmwareRequest{} } +func (m *FirmwareRequest) String() string { return proto.CompactTextString(m) } +func (*FirmwareRequest) ProtoMessage() {} +func (*FirmwareRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{61} } + +func (m *FirmwareRequest) GetOffset() uint32 { + if m != nil && m.Offset != nil { + return *m.Offset + } + return 0 +} + +func (m *FirmwareRequest) GetLength() uint32 { + if m != nil && m.Length != nil { + return *m.Length + } + return 0 +} + +// * +// Request: Send firmware in binary form to the device +// @next Success +// @next Failure +type FirmwareUpload struct { + Payload []byte `protobuf:"bytes,1,req,name=payload" json:"payload,omitempty"` + Hash []byte `protobuf:"bytes,2,opt,name=hash" json:"hash,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FirmwareUpload) Reset() { *m = FirmwareUpload{} } +func (m *FirmwareUpload) String() string { return proto.CompactTextString(m) } +func (*FirmwareUpload) ProtoMessage() {} +func (*FirmwareUpload) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{62} } + +func (m *FirmwareUpload) GetPayload() []byte { + if m != nil { + return m.Payload + } + return nil +} + +func (m *FirmwareUpload) GetHash() []byte { + if m != nil { + return m.Hash + } + return nil +} + +// * +// Request: Perform a device self-test +// @next Success +// @next Failure +type SelfTest struct { + Payload []byte `protobuf:"bytes,1,opt,name=payload" json:"payload,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SelfTest) Reset() { *m = SelfTest{} } +func (m *SelfTest) String() string { return proto.CompactTextString(m) } +func (*SelfTest) ProtoMessage() {} +func (*SelfTest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{63} } + +func (m *SelfTest) GetPayload() []byte { + if m != nil { + return m.Payload + } + return nil +} + +// * +// Request: "Press" the button on the device +// @next Success +type DebugLinkDecision struct { + YesNo *bool `protobuf:"varint,1,req,name=yes_no,json=yesNo" json:"yes_no,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkDecision) Reset() { *m = DebugLinkDecision{} } +func (m *DebugLinkDecision) String() string { return proto.CompactTextString(m) } +func (*DebugLinkDecision) ProtoMessage() {} +func (*DebugLinkDecision) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{64} } + +func (m *DebugLinkDecision) GetYesNo() bool { + if m != nil && m.YesNo != nil { + return *m.YesNo + } + return false +} + +// * +// Request: Computer asks for device state +// @next DebugLinkState +type DebugLinkGetState struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkGetState) Reset() { *m = DebugLinkGetState{} } +func (m *DebugLinkGetState) String() string { return proto.CompactTextString(m) } +func (*DebugLinkGetState) ProtoMessage() {} +func (*DebugLinkGetState) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{65} } + +// * +// Response: Device current state +// @prev DebugLinkGetState +type DebugLinkState struct { + Layout []byte `protobuf:"bytes,1,opt,name=layout" json:"layout,omitempty"` + Pin *string `protobuf:"bytes,2,opt,name=pin" json:"pin,omitempty"` + Matrix *string `protobuf:"bytes,3,opt,name=matrix" json:"matrix,omitempty"` + Mnemonic *string `protobuf:"bytes,4,opt,name=mnemonic" json:"mnemonic,omitempty"` + Node *HDNodeType `protobuf:"bytes,5,opt,name=node" json:"node,omitempty"` + PassphraseProtection *bool `protobuf:"varint,6,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` + ResetWord *string `protobuf:"bytes,7,opt,name=reset_word,json=resetWord" json:"reset_word,omitempty"` + ResetEntropy []byte `protobuf:"bytes,8,opt,name=reset_entropy,json=resetEntropy" json:"reset_entropy,omitempty"` + RecoveryFakeWord *string `protobuf:"bytes,9,opt,name=recovery_fake_word,json=recoveryFakeWord" json:"recovery_fake_word,omitempty"` + RecoveryWordPos *uint32 `protobuf:"varint,10,opt,name=recovery_word_pos,json=recoveryWordPos" json:"recovery_word_pos,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkState) Reset() { *m = DebugLinkState{} } +func (m *DebugLinkState) String() string { return proto.CompactTextString(m) } +func (*DebugLinkState) ProtoMessage() {} +func (*DebugLinkState) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{66} } + +func (m *DebugLinkState) GetLayout() []byte { + if m != nil { + return m.Layout + } + return nil +} + +func (m *DebugLinkState) GetPin() string { + if m != nil && m.Pin != nil { + return *m.Pin + } + return "" +} + +func (m *DebugLinkState) GetMatrix() string { + if m != nil && m.Matrix != nil { + return *m.Matrix + } + return "" +} + +func (m *DebugLinkState) GetMnemonic() string { + if m != nil && m.Mnemonic != nil { + return *m.Mnemonic + } + return "" +} + +func (m *DebugLinkState) GetNode() *HDNodeType { + if m != nil { + return m.Node + } + return nil +} + +func (m *DebugLinkState) GetPassphraseProtection() bool { + if m != nil && m.PassphraseProtection != nil { + return *m.PassphraseProtection + } + return false +} + +func (m *DebugLinkState) GetResetWord() string { + if m != nil && m.ResetWord != nil { + return *m.ResetWord + } + return "" +} + +func (m *DebugLinkState) GetResetEntropy() []byte { + if m != nil { + return m.ResetEntropy + } + return nil +} + +func (m *DebugLinkState) GetRecoveryFakeWord() string { + if m != nil && m.RecoveryFakeWord != nil { + return *m.RecoveryFakeWord + } + return "" +} + +func (m *DebugLinkState) GetRecoveryWordPos() uint32 { + if m != nil && m.RecoveryWordPos != nil { + return *m.RecoveryWordPos + } + return 0 +} + +// * +// Request: Ask device to restart +type DebugLinkStop struct { + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkStop) Reset() { *m = DebugLinkStop{} } +func (m *DebugLinkStop) String() string { return proto.CompactTextString(m) } +func (*DebugLinkStop) ProtoMessage() {} +func (*DebugLinkStop) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{67} } + +// * +// Response: Device wants host to log event +type DebugLinkLog struct { + Level *uint32 `protobuf:"varint,1,opt,name=level" json:"level,omitempty"` + Bucket *string `protobuf:"bytes,2,opt,name=bucket" json:"bucket,omitempty"` + Text *string `protobuf:"bytes,3,opt,name=text" json:"text,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkLog) Reset() { *m = DebugLinkLog{} } +func (m *DebugLinkLog) String() string { return proto.CompactTextString(m) } +func (*DebugLinkLog) ProtoMessage() {} +func (*DebugLinkLog) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{68} } + +func (m *DebugLinkLog) GetLevel() uint32 { + if m != nil && m.Level != nil { + return *m.Level + } + return 0 +} + +func (m *DebugLinkLog) GetBucket() string { + if m != nil && m.Bucket != nil { + return *m.Bucket + } + return "" +} + +func (m *DebugLinkLog) GetText() string { + if m != nil && m.Text != nil { + return *m.Text + } + return "" +} + +// * +// Request: Read memory from device +// @next DebugLinkMemory +type DebugLinkMemoryRead struct { + Address *uint32 `protobuf:"varint,1,opt,name=address" json:"address,omitempty"` + Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkMemoryRead) Reset() { *m = DebugLinkMemoryRead{} } +func (m *DebugLinkMemoryRead) String() string { return proto.CompactTextString(m) } +func (*DebugLinkMemoryRead) ProtoMessage() {} +func (*DebugLinkMemoryRead) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{69} } + +func (m *DebugLinkMemoryRead) GetAddress() uint32 { + if m != nil && m.Address != nil { + return *m.Address + } + return 0 +} + +func (m *DebugLinkMemoryRead) GetLength() uint32 { + if m != nil && m.Length != nil { + return *m.Length + } + return 0 +} + +// * +// Response: Device sends memory back +// @prev DebugLinkMemoryRead +type DebugLinkMemory struct { + Memory []byte `protobuf:"bytes,1,opt,name=memory" json:"memory,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkMemory) Reset() { *m = DebugLinkMemory{} } +func (m *DebugLinkMemory) String() string { return proto.CompactTextString(m) } +func (*DebugLinkMemory) ProtoMessage() {} +func (*DebugLinkMemory) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{70} } + +func (m *DebugLinkMemory) GetMemory() []byte { + if m != nil { + return m.Memory + } + return nil +} + +// * +// Request: Write memory to device. +// WARNING: Writing to the wrong location can irreparably break the device. +type DebugLinkMemoryWrite struct { + Address *uint32 `protobuf:"varint,1,opt,name=address" json:"address,omitempty"` + Memory []byte `protobuf:"bytes,2,opt,name=memory" json:"memory,omitempty"` + Flash *bool `protobuf:"varint,3,opt,name=flash" json:"flash,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkMemoryWrite) Reset() { *m = DebugLinkMemoryWrite{} } +func (m *DebugLinkMemoryWrite) String() string { return proto.CompactTextString(m) } +func (*DebugLinkMemoryWrite) ProtoMessage() {} +func (*DebugLinkMemoryWrite) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{71} } + +func (m *DebugLinkMemoryWrite) GetAddress() uint32 { + if m != nil && m.Address != nil { + return *m.Address + } + return 0 +} + +func (m *DebugLinkMemoryWrite) GetMemory() []byte { + if m != nil { + return m.Memory + } + return nil +} + +func (m *DebugLinkMemoryWrite) GetFlash() bool { + if m != nil && m.Flash != nil { + return *m.Flash + } + return false +} + +// * +// Request: Erase block of flash on device +// WARNING: Writing to the wrong location can irreparably break the device. +type DebugLinkFlashErase struct { + Sector *uint32 `protobuf:"varint,1,opt,name=sector" json:"sector,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DebugLinkFlashErase) Reset() { *m = DebugLinkFlashErase{} } +func (m *DebugLinkFlashErase) String() string { return proto.CompactTextString(m) } +func (*DebugLinkFlashErase) ProtoMessage() {} +func (*DebugLinkFlashErase) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{72} } + +func (m *DebugLinkFlashErase) GetSector() uint32 { + if m != nil && m.Sector != nil { + return *m.Sector + } + return 0 +} + +func init() { + proto.RegisterType((*Initialize)(nil), "Initialize") + proto.RegisterType((*GetFeatures)(nil), "GetFeatures") + proto.RegisterType((*Features)(nil), "Features") + proto.RegisterType((*ClearSession)(nil), "ClearSession") + proto.RegisterType((*ApplySettings)(nil), "ApplySettings") + proto.RegisterType((*ApplyFlags)(nil), "ApplyFlags") + proto.RegisterType((*ChangePin)(nil), "ChangePin") + proto.RegisterType((*Ping)(nil), "Ping") + proto.RegisterType((*Success)(nil), "Success") + proto.RegisterType((*Failure)(nil), "Failure") + proto.RegisterType((*ButtonRequest)(nil), "ButtonRequest") + proto.RegisterType((*ButtonAck)(nil), "ButtonAck") + proto.RegisterType((*PinMatrixRequest)(nil), "PinMatrixRequest") + proto.RegisterType((*PinMatrixAck)(nil), "PinMatrixAck") + proto.RegisterType((*Cancel)(nil), "Cancel") + proto.RegisterType((*PassphraseRequest)(nil), "PassphraseRequest") + proto.RegisterType((*PassphraseAck)(nil), "PassphraseAck") + proto.RegisterType((*GetEntropy)(nil), "GetEntropy") + proto.RegisterType((*Entropy)(nil), "Entropy") + proto.RegisterType((*GetPublicKey)(nil), "GetPublicKey") + proto.RegisterType((*PublicKey)(nil), "PublicKey") + proto.RegisterType((*GetAddress)(nil), "GetAddress") + proto.RegisterType((*EthereumGetAddress)(nil), "EthereumGetAddress") + proto.RegisterType((*Address)(nil), "Address") + proto.RegisterType((*EthereumAddress)(nil), "EthereumAddress") + proto.RegisterType((*WipeDevice)(nil), "WipeDevice") + proto.RegisterType((*LoadDevice)(nil), "LoadDevice") + proto.RegisterType((*ResetDevice)(nil), "ResetDevice") + proto.RegisterType((*BackupDevice)(nil), "BackupDevice") + proto.RegisterType((*EntropyRequest)(nil), "EntropyRequest") + proto.RegisterType((*EntropyAck)(nil), "EntropyAck") + proto.RegisterType((*RecoveryDevice)(nil), "RecoveryDevice") + proto.RegisterType((*WordRequest)(nil), "WordRequest") + proto.RegisterType((*WordAck)(nil), "WordAck") + proto.RegisterType((*SignMessage)(nil), "SignMessage") + proto.RegisterType((*VerifyMessage)(nil), "VerifyMessage") + proto.RegisterType((*MessageSignature)(nil), "MessageSignature") + proto.RegisterType((*EncryptMessage)(nil), "EncryptMessage") + proto.RegisterType((*EncryptedMessage)(nil), "EncryptedMessage") + proto.RegisterType((*DecryptMessage)(nil), "DecryptMessage") + proto.RegisterType((*DecryptedMessage)(nil), "DecryptedMessage") + proto.RegisterType((*CipherKeyValue)(nil), "CipherKeyValue") + proto.RegisterType((*CipheredKeyValue)(nil), "CipheredKeyValue") + proto.RegisterType((*EstimateTxSize)(nil), "EstimateTxSize") + proto.RegisterType((*TxSize)(nil), "TxSize") + proto.RegisterType((*SignTx)(nil), "SignTx") + proto.RegisterType((*SimpleSignTx)(nil), "SimpleSignTx") + proto.RegisterType((*TxRequest)(nil), "TxRequest") + proto.RegisterType((*TxAck)(nil), "TxAck") + proto.RegisterType((*EthereumSignTx)(nil), "EthereumSignTx") + proto.RegisterType((*EthereumTxRequest)(nil), "EthereumTxRequest") + proto.RegisterType((*EthereumTxAck)(nil), "EthereumTxAck") + proto.RegisterType((*EthereumSignMessage)(nil), "EthereumSignMessage") + proto.RegisterType((*EthereumVerifyMessage)(nil), "EthereumVerifyMessage") + proto.RegisterType((*EthereumMessageSignature)(nil), "EthereumMessageSignature") + proto.RegisterType((*SignIdentity)(nil), "SignIdentity") + proto.RegisterType((*SignedIdentity)(nil), "SignedIdentity") + proto.RegisterType((*GetECDHSessionKey)(nil), "GetECDHSessionKey") + proto.RegisterType((*ECDHSessionKey)(nil), "ECDHSessionKey") + proto.RegisterType((*SetU2FCounter)(nil), "SetU2FCounter") + proto.RegisterType((*FirmwareErase)(nil), "FirmwareErase") + proto.RegisterType((*FirmwareRequest)(nil), "FirmwareRequest") + proto.RegisterType((*FirmwareUpload)(nil), "FirmwareUpload") + proto.RegisterType((*SelfTest)(nil), "SelfTest") + proto.RegisterType((*DebugLinkDecision)(nil), "DebugLinkDecision") + proto.RegisterType((*DebugLinkGetState)(nil), "DebugLinkGetState") + proto.RegisterType((*DebugLinkState)(nil), "DebugLinkState") + proto.RegisterType((*DebugLinkStop)(nil), "DebugLinkStop") + proto.RegisterType((*DebugLinkLog)(nil), "DebugLinkLog") + proto.RegisterType((*DebugLinkMemoryRead)(nil), "DebugLinkMemoryRead") + proto.RegisterType((*DebugLinkMemory)(nil), "DebugLinkMemory") + proto.RegisterType((*DebugLinkMemoryWrite)(nil), "DebugLinkMemoryWrite") + proto.RegisterType((*DebugLinkFlashErase)(nil), "DebugLinkFlashErase") + proto.RegisterEnum("MessageType", MessageType_name, MessageType_value) +} + +func init() { proto.RegisterFile("messages.proto", fileDescriptor1) } + +var fileDescriptor1 = []byte{ + // 3424 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5a, 0xcb, 0x6f, 0xdc, 0x46, + 0x9a, 0x5f, 0x76, 0xb7, 0xfa, 0xf1, 0x35, 0xbb, 0x55, 0xa2, 0x2d, 0xbb, 0x2d, 0x5b, 0xb6, 0x4c, + 0xc9, 0xb6, 0x64, 0x27, 0xed, 0x44, 0x79, 0x6c, 0xd6, 0xbb, 0x79, 0xc8, 0x7a, 0xd8, 0xde, 0xd8, + 0x8e, 0xc0, 0x56, 0x9c, 0xdb, 0x12, 0x14, 0x59, 0xea, 0xae, 0x55, 0x37, 0xc9, 0xf0, 0xa1, 0xa8, + 0x7d, 0xd8, 0xeb, 0xee, 0x65, 0x81, 0xec, 0x69, 0x73, 0x1a, 0xe4, 0x36, 0x19, 0x04, 0x18, 0x0c, + 0x30, 0x18, 0x60, 0x72, 0x9a, 0x3f, 0x60, 0xfe, 0x8b, 0x39, 0xce, 0x1f, 0x30, 0xe7, 0x41, 0x3d, + 0x48, 0x16, 0x29, 0xb6, 0x6c, 0x27, 0xc0, 0x5c, 0x04, 0xd6, 0x57, 0xbf, 0xfe, 0xea, 0x7b, 0xd5, + 0x57, 0x5f, 0x7d, 0x25, 0xe8, 0x4e, 0x70, 0x18, 0x5a, 0x43, 0x1c, 0xf6, 0xfd, 0xc0, 0x8b, 0xbc, + 0xa5, 0x76, 0x34, 0xf5, 0x93, 0x81, 0xae, 0x02, 0x3c, 0x71, 0x49, 0x44, 0xac, 0x31, 0x79, 0x89, + 0xf5, 0x0e, 0xb4, 0x1f, 0xe1, 0x68, 0x0f, 0x5b, 0x51, 0x1c, 0xe0, 0x50, 0xff, 0x69, 0x0e, 0x9a, + 0xc9, 0x40, 0xbb, 0x04, 0xf5, 0x13, 0xec, 0x3a, 0x5e, 0xd0, 0x53, 0x56, 0x94, 0xf5, 0x96, 0x21, + 0x46, 0xda, 0x2a, 0x74, 0x26, 0xd6, 0x7f, 0x7a, 0x81, 0x79, 0x82, 0x83, 0x90, 0x78, 0x6e, 0xaf, + 0xb2, 0xa2, 0xac, 0x77, 0x0c, 0x95, 0x11, 0x5f, 0x70, 0x1a, 0x03, 0x11, 0x57, 0x02, 0x55, 0x05, + 0x88, 0x12, 0x25, 0x90, 0x6f, 0x45, 0xf6, 0x28, 0x05, 0xd5, 0x38, 0x88, 0x11, 0x13, 0xd0, 0x1d, + 0x98, 0x3f, 0xf4, 0xbc, 0x68, 0xec, 0x59, 0x0e, 0x0e, 0xcc, 0x89, 0xe7, 0xe0, 0xde, 0xdc, 0x8a, + 0xb2, 0xde, 0x34, 0xba, 0x19, 0xf9, 0x99, 0xe7, 0x60, 0xed, 0x2a, 0xb4, 0x1c, 0x7c, 0x42, 0x6c, + 0x6c, 0x12, 0xa7, 0x57, 0x67, 0x22, 0x37, 0x39, 0xe1, 0x89, 0xa3, 0xdd, 0x82, 0xae, 0x4f, 0x5c, + 0x93, 0xda, 0x00, 0xdb, 0x11, 0x5d, 0xab, 0xc1, 0x98, 0x74, 0x7c, 0xe2, 0xee, 0xa7, 0x44, 0xed, + 0x3d, 0x58, 0xf4, 0xad, 0x30, 0xf4, 0x47, 0x81, 0x15, 0x62, 0x19, 0xdd, 0x64, 0xe8, 0x8b, 0xd9, + 0xa4, 0xf4, 0xa3, 0x25, 0x68, 0x8e, 0x2d, 0x77, 0x18, 0x5b, 0x43, 0xdc, 0x6b, 0xf1, 0x75, 0x93, + 0xb1, 0x76, 0x11, 0xe6, 0xc6, 0xd6, 0x21, 0x1e, 0xf7, 0x80, 0x4d, 0xf0, 0x81, 0x76, 0x03, 0xe6, + 0x6c, 0x8f, 0xb8, 0x61, 0xaf, 0xbd, 0x52, 0x5d, 0x6f, 0x6f, 0xb6, 0xfa, 0xdb, 0x1e, 0x71, 0x0f, + 0xa6, 0x3e, 0x36, 0x38, 0x5d, 0x5b, 0x81, 0x36, 0x49, 0xbd, 0xe4, 0xf4, 0x54, 0xb6, 0xba, 0x4c, + 0xa2, 0x8b, 0x06, 0xf8, 0x84, 0x30, 0xb3, 0x75, 0x56, 0x94, 0x75, 0xd5, 0x48, 0xc7, 0x05, 0x93, + 0x8d, 0xac, 0x70, 0xd4, 0xeb, 0x32, 0x88, 0x64, 0xb2, 0xc7, 0x56, 0x38, 0xa2, 0x4c, 0xc8, 0xc4, + 0xf7, 0x82, 0x08, 0x3b, 0xbd, 0x79, 0xb6, 0x46, 0x3a, 0xd6, 0x96, 0x01, 0xa8, 0xc5, 0x6c, 0xcb, + 0x1e, 0x61, 0xa7, 0x87, 0xd8, 0x6c, 0xcb, 0x27, 0xee, 0x36, 0x23, 0x68, 0xf7, 0x60, 0x41, 0xb2, + 0x94, 0x40, 0x2d, 0x30, 0x14, 0xca, 0x26, 0x04, 0x78, 0x03, 0xd0, 0x11, 0x09, 0x26, 0xdf, 0x58, + 0x01, 0x35, 0x2a, 0x0e, 0xb1, 0x1b, 0xf5, 0x34, 0x86, 0x9d, 0x4f, 0xe8, 0xfb, 0x9c, 0xac, 0xdd, + 0x04, 0xd5, 0xc5, 0xd8, 0x09, 0xcd, 0x43, 0xcb, 0x3e, 0x8e, 0xfd, 0xde, 0x05, 0xae, 0x3a, 0xa3, + 0x3d, 0x64, 0x24, 0x6a, 0xd3, 0xa3, 0xb1, 0x35, 0x0c, 0x7b, 0x17, 0x59, 0xb8, 0xf0, 0x81, 0xde, + 0x05, 0x75, 0x7b, 0x8c, 0xad, 0x60, 0x80, 0x43, 0x6a, 0x04, 0xfd, 0x7f, 0x14, 0xe8, 0x6c, 0xf9, + 0xfe, 0x78, 0x3a, 0xc0, 0x51, 0x44, 0xdc, 0x61, 0x98, 0xf3, 0x93, 0x32, 0xcb, 0x4f, 0x15, 0xd9, + 0x4f, 0xb7, 0xa0, 0x1b, 0xd3, 0x38, 0x48, 0xf5, 0x61, 0x61, 0xdc, 0x34, 0x3a, 0x71, 0x88, 0xf7, + 0x53, 0xa2, 0x76, 0x1d, 0x60, 0xe4, 0x4d, 0x70, 0x68, 0x07, 0x18, 0xf3, 0x20, 0x56, 0x0d, 0x89, + 0xa2, 0xeb, 0x00, 0x4c, 0x92, 0x3d, 0x2a, 0x68, 0x26, 0xbe, 0x22, 0x8b, 0xbf, 0x0a, 0xad, 0xed, + 0x91, 0xe5, 0x0e, 0xf1, 0x3e, 0x71, 0xe9, 0xd6, 0x0b, 0xf0, 0xc4, 0x3b, 0xe1, 0x72, 0x36, 0x0d, + 0x31, 0xd2, 0x7f, 0xa3, 0x40, 0x6d, 0x9f, 0xb8, 0x43, 0xad, 0x07, 0x0d, 0xb1, 0xc9, 0x85, 0x26, + 0xc9, 0x90, 0xfa, 0xe5, 0x30, 0x8e, 0x22, 0x2f, 0x17, 0xeb, 0x15, 0xee, 0x17, 0x3e, 0x21, 0x45, + 0xee, 0xd9, 0x5d, 0x51, 0x7d, 0xa3, 0x5d, 0x51, 0x9b, 0xbd, 0x2b, 0xf4, 0x55, 0x68, 0x0c, 0x62, + 0xdb, 0xc6, 0x61, 0x38, 0x5b, 0x5a, 0x7d, 0x17, 0x1a, 0x7b, 0x16, 0x19, 0xc7, 0x01, 0xd6, 0x56, + 0xa0, 0x66, 0xd3, 0xcd, 0x4d, 0x11, 0xdd, 0x4d, 0xb5, 0x2f, 0xe8, 0x6c, 0x57, 0xb0, 0x19, 0x99, + 0x4d, 0x25, 0xcf, 0xe6, 0x73, 0xe8, 0x3c, 0x64, 0xba, 0x19, 0xf8, 0xeb, 0x18, 0x87, 0x91, 0x76, + 0x3b, 0xc7, 0x4c, 0xeb, 0xe7, 0x66, 0x25, 0x96, 0x1a, 0xd4, 0x1c, 0x2b, 0xb2, 0x04, 0x3f, 0xf6, + 0xad, 0xb7, 0xa1, 0xc5, 0xe1, 0x5b, 0xf6, 0xb1, 0xfe, 0x31, 0xa0, 0x7d, 0xe2, 0x3e, 0xb3, 0xa2, + 0x80, 0x9c, 0x26, 0xcc, 0x37, 0xa0, 0x46, 0x33, 0xaa, 0x60, 0xbe, 0xd8, 0x2f, 0x02, 0x38, 0x7f, + 0x0a, 0xd1, 0x57, 0x40, 0x4d, 0x67, 0xb7, 0xec, 0x63, 0x0d, 0x41, 0xd5, 0x27, 0x6e, 0x4f, 0x59, + 0xa9, 0xac, 0xb7, 0x0c, 0xfa, 0xa9, 0x37, 0xa1, 0xbe, 0x6d, 0xb9, 0x36, 0x1e, 0xeb, 0x17, 0x60, + 0x21, 0x8b, 0x29, 0xc1, 0x4a, 0xbf, 0x0f, 0x9d, 0x8c, 0x48, 0x39, 0x5c, 0x07, 0x90, 0xc2, 0x91, + 0x33, 0x92, 0x28, 0xfa, 0x0a, 0xc0, 0x23, 0x1c, 0xed, 0xba, 0x51, 0xe0, 0xf9, 0x53, 0xaa, 0x5f, + 0x48, 0x5e, 0x72, 0x5c, 0xc7, 0x60, 0xdf, 0xd4, 0x31, 0xc9, 0x74, 0x0f, 0x1a, 0x98, 0x7f, 0x32, + 0x84, 0x6a, 0x24, 0x43, 0xfd, 0x57, 0x0a, 0xa8, 0x8f, 0x70, 0xb4, 0x1f, 0x1f, 0x8e, 0x89, 0xfd, + 0x39, 0x9e, 0xd2, 0xec, 0x6a, 0x39, 0x4e, 0x80, 0xc3, 0xd0, 0xa4, 0xf2, 0x57, 0xd7, 0x3b, 0x46, + 0x53, 0x10, 0x9e, 0x6b, 0xeb, 0x80, 0xb0, 0xed, 0x84, 0x96, 0x69, 0xc7, 0xc1, 0x09, 0x36, 0x5d, + 0x6b, 0x92, 0xb8, 0xa8, 0xcb, 0xe8, 0xdb, 0x94, 0xfc, 0xdc, 0x9a, 0x60, 0xba, 0xbd, 0xc3, 0x91, + 0xf7, 0x8d, 0xe9, 0x90, 0xd0, 0x1f, 0x5b, 0x53, 0x11, 0x6f, 0x6d, 0x4a, 0xdb, 0xe1, 0x24, 0x6d, + 0x0d, 0x5a, 0x34, 0x09, 0x72, 0x2e, 0x34, 0xc2, 0x5a, 0x0f, 0x1a, 0x0f, 0x49, 0x44, 0x69, 0x46, + 0x93, 0xfe, 0xa5, 0x8c, 0xf4, 0xcf, 0xa0, 0x95, 0x09, 0x77, 0x03, 0x6a, 0x2e, 0x77, 0x77, 0x65, + 0xbd, 0xbd, 0xd9, 0xee, 0x3f, 0xde, 0x79, 0xee, 0x39, 0x22, 0x74, 0x5c, 0xe1, 0xe7, 0x53, 0x3f, + 0x3e, 0x4c, 0xfc, 0x4c, 0xbf, 0xf5, 0xbf, 0x2a, 0xcc, 0x54, 0x5b, 0x5c, 0x89, 0xf3, 0x15, 0xcc, + 0xc9, 0x54, 0x99, 0x21, 0xd3, 0xeb, 0x28, 0xf7, 0x01, 0x34, 0x27, 0xf1, 0x38, 0x22, 0x21, 0x19, + 0x32, 0xdd, 0xda, 0x9b, 0x57, 0xfa, 0xcf, 0x04, 0xc1, 0xc0, 0x0e, 0xc6, 0x93, 0x81, 0x1d, 0x10, + 0x9f, 0xc7, 0x50, 0x0a, 0xd5, 0x3e, 0x85, 0x76, 0xc8, 0xe8, 0x26, 0x8b, 0xbc, 0x39, 0x16, 0x79, + 0xa8, 0xff, 0xc4, 0xf5, 0xe3, 0x28, 0xfb, 0xc1, 0x03, 0x75, 0xb0, 0xbf, 0xfb, 0x7c, 0x67, 0x6b, + 0x67, 0xc7, 0xd8, 0x1d, 0x0c, 0x0c, 0x08, 0xd3, 0x19, 0xfd, 0x00, 0xb4, 0xdd, 0x68, 0x84, 0x03, + 0x1c, 0x4f, 0x5e, 0x57, 0xe7, 0xa2, 0x36, 0x95, 0x33, 0xda, 0xd0, 0x50, 0x4a, 0x58, 0xf5, 0xa0, + 0x21, 0x7e, 0x29, 0x82, 0x32, 0x19, 0xea, 0xf7, 0x60, 0x3e, 0x59, 0x7a, 0x06, 0x58, 0xcd, 0xc0, + 0x2a, 0xc0, 0x57, 0xc4, 0xc7, 0x3b, 0xec, 0xdc, 0xd6, 0xff, 0xaf, 0x02, 0xf0, 0xd4, 0xb3, 0x1c, + 0x3e, 0xa4, 0x09, 0x7c, 0xe2, 0xe2, 0x89, 0xe7, 0x12, 0x3b, 0x49, 0xe0, 0xc9, 0x38, 0x0d, 0x81, + 0x0a, 0x33, 0x6a, 0x49, 0x08, 0x88, 0xad, 0x57, 0x65, 0xbf, 0xa3, 0x9f, 0x3f, 0x2b, 0xad, 0x69, + 0xab, 0xd2, 0x21, 0x32, 0xc7, 0x03, 0x01, 0xbb, 0xc3, 0x31, 0x09, 0x47, 0x65, 0xa7, 0x49, 0x5d, + 0x3e, 0x4d, 0x56, 0xa1, 0x13, 0x1e, 0x13, 0xdf, 0xb4, 0x47, 0xd8, 0x3e, 0x0e, 0xe3, 0x89, 0x28, + 0x41, 0x54, 0x4a, 0xdc, 0x16, 0x34, 0xed, 0x06, 0xb4, 0xe3, 0xcd, 0x23, 0xd3, 0xf6, 0x62, 0x37, + 0xc2, 0x01, 0xab, 0x3b, 0x3a, 0x06, 0xc4, 0x9b, 0x47, 0xdb, 0x9c, 0xa2, 0xff, 0xb6, 0x02, 0x6d, + 0x03, 0x87, 0x38, 0x12, 0x46, 0xb9, 0x05, 0x5d, 0xe1, 0x21, 0x33, 0xb0, 0x5c, 0xc7, 0x9b, 0x88, + 0x33, 0xa3, 0x23, 0xa8, 0x06, 0x23, 0x6a, 0x37, 0xa0, 0x19, 0x46, 0x01, 0x76, 0x87, 0xd1, 0x88, + 0x17, 0x6c, 0x0f, 0xaa, 0x9b, 0x1f, 0x7c, 0x68, 0xa4, 0xc4, 0xd9, 0xd6, 0xa8, 0x9e, 0x63, 0x8d, + 0xb3, 0x07, 0x48, 0xad, 0xec, 0x00, 0xf9, 0x05, 0x46, 0x2b, 0xd8, 0xa3, 0x51, 0xb4, 0x07, 0x05, + 0x30, 0xab, 0x8a, 0x7a, 0x81, 0x17, 0x6a, 0x40, 0x49, 0xbc, 0x5c, 0xa0, 0x85, 0x01, 0xff, 0x12, + 0x41, 0x85, 0xa0, 0x2b, 0xf2, 0x5f, 0x92, 0x64, 0x6f, 0x03, 0x08, 0x0a, 0xcd, 0xb0, 0xb9, 0xa4, + 0xa8, 0xc8, 0x49, 0xf1, 0x4f, 0x15, 0xe8, 0x1a, 0xd8, 0xf6, 0x4e, 0x70, 0x30, 0x15, 0xd6, 0x5f, + 0x06, 0xf8, 0xc6, 0x0b, 0x1c, 0x2e, 0x9f, 0x38, 0xd1, 0x5b, 0x94, 0xc2, 0xc4, 0x9b, 0x6d, 0xd4, + 0xca, 0x1b, 0x19, 0xb5, 0xfa, 0x2a, 0xa3, 0xd6, 0x5e, 0x69, 0xd4, 0x39, 0xd9, 0xa8, 0x1b, 0x80, + 0xb0, 0x7b, 0xe4, 0x05, 0x36, 0x36, 0xa9, 0xac, 0x63, 0x12, 0x46, 0xcc, 0xea, 0x4d, 0x63, 0x5e, + 0xd0, 0xbf, 0x12, 0x64, 0x9a, 0x39, 0x59, 0xca, 0xe1, 0x81, 0xc8, 0xbe, 0x8b, 0x3e, 0x69, 0x9d, + 0xf1, 0xc9, 0x65, 0x68, 0x38, 0xc1, 0xd4, 0x0c, 0x62, 0x97, 0xd5, 0xbd, 0x4d, 0xa3, 0xee, 0x04, + 0x53, 0x23, 0x76, 0xf5, 0xf7, 0xa0, 0x4d, 0x39, 0x27, 0x27, 0xe9, 0x5a, 0xee, 0x24, 0x45, 0x7d, + 0x69, 0x4e, 0x3a, 0x44, 0x97, 0xa1, 0x41, 0x27, 0xa8, 0x6f, 0x34, 0xa8, 0x51, 0x81, 0x45, 0x8a, + 0x61, 0xdf, 0xfa, 0x8f, 0x0a, 0xb4, 0x07, 0x64, 0xe8, 0x3e, 0x13, 0x15, 0xd0, 0xb9, 0x49, 0x2d, + 0x57, 0x43, 0xb0, 0xcc, 0x93, 0x14, 0x4e, 0xb9, 0x14, 0x5f, 0x9d, 0x95, 0xe2, 0x0b, 0x89, 0xb8, + 0xf6, 0xc6, 0x89, 0xf8, 0xbf, 0x15, 0xe8, 0xbc, 0xc0, 0x01, 0x39, 0x9a, 0x26, 0xf2, 0xe6, 0x92, + 0xa1, 0x22, 0x65, 0x4e, 0xed, 0x1a, 0xb4, 0x42, 0x32, 0x74, 0xd9, 0x7d, 0x8c, 0x45, 0x8c, 0x6a, + 0x64, 0x04, 0x59, 0x95, 0x2a, 0x8f, 0xd3, 0x52, 0x55, 0x66, 0x9e, 0xa0, 0xff, 0x0e, 0x48, 0x88, + 0x30, 0x90, 0x79, 0xfe, 0x1c, 0x59, 0xf4, 0x1f, 0x14, 0xba, 0xa9, 0xec, 0x60, 0xea, 0x47, 0x89, + 0x5a, 0x97, 0xa0, 0xee, 0xc7, 0x87, 0xc7, 0x38, 0xd9, 0x45, 0x62, 0x54, 0xac, 0xe2, 0x24, 0xb1, + 0x6f, 0x82, 0x9a, 0x64, 0x32, 0xcf, 0x1d, 0xa7, 0xc7, 0xa7, 0xa0, 0x7d, 0xe1, 0x8e, 0x0b, 0x55, + 0x48, 0xed, 0xbc, 0x43, 0x7a, 0x6e, 0x96, 0xda, 0x2f, 0x00, 0x09, 0x49, 0xb1, 0x93, 0xc8, 0x7a, + 0x11, 0xe6, 0x5c, 0xcf, 0xb5, 0xb1, 0x10, 0x95, 0x0f, 0xce, 0x91, 0x54, 0x83, 0xda, 0x68, 0x62, + 0xd9, 0xc2, 0xee, 0xec, 0x5b, 0xff, 0x1a, 0xba, 0x3b, 0x38, 0x67, 0x81, 0x73, 0x03, 0x31, 0x5d, + 0xb2, 0x32, 0x63, 0xc9, 0x6a, 0xf9, 0x92, 0x35, 0x69, 0xc9, 0x3d, 0x40, 0x62, 0xc9, 0x4c, 0x95, + 0x42, 0xad, 0x2d, 0x71, 0x90, 0x7c, 0x5b, 0xc9, 0xf9, 0x56, 0xff, 0xb3, 0x02, 0xdd, 0x6d, 0xe2, + 0x8f, 0x70, 0xf0, 0x39, 0x9e, 0xbe, 0xb0, 0xc6, 0xf1, 0x2b, 0x64, 0x47, 0x50, 0xa5, 0x7e, 0xe5, + 0x5c, 0xe8, 0x27, 0xd5, 0xe6, 0x84, 0xfe, 0x4e, 0x48, 0xcd, 0x07, 0x3c, 0x93, 0x32, 0xf9, 0xc4, + 0xb1, 0x90, 0x0c, 0xb5, 0x35, 0xe8, 0x5a, 0xe1, 0xb1, 0xe9, 0xb9, 0x66, 0x02, 0xe0, 0x77, 0x7a, + 0xd5, 0x0a, 0x8f, 0xbf, 0x70, 0x77, 0xcf, 0xa0, 0x1c, 0xae, 0xa6, 0x48, 0x52, 0x1c, 0x25, 0x54, + 0xd7, 0xba, 0x50, 0x21, 0x27, 0xec, 0x60, 0x50, 0x8d, 0x0a, 0x39, 0xd1, 0xd7, 0x01, 0x71, 0x65, + 0xb0, 0x93, 0xaa, 0x93, 0xca, 0xa7, 0x48, 0xf2, 0xe9, 0xff, 0x05, 0xdd, 0xdd, 0x30, 0x22, 0x13, + 0x2b, 0xc2, 0x07, 0xa7, 0x03, 0xf2, 0x12, 0xd3, 0x23, 0xda, 0x8b, 0x23, 0x3f, 0x8e, 0xc2, 0x34, + 0xa3, 0xd3, 0xc2, 0x59, 0x15, 0x44, 0x9e, 0xd4, 0x6f, 0x82, 0x4a, 0x5c, 0x09, 0x53, 0x61, 0x98, + 0x36, 0xa7, 0x71, 0xc8, 0x6b, 0x25, 0x13, 0xfd, 0x26, 0xd4, 0xc5, 0xba, 0x97, 0xa1, 0x11, 0x9d, + 0x9a, 0xa2, 0x54, 0xa7, 0xd9, 0xb4, 0x1e, 0xb1, 0x09, 0xfd, 0xf7, 0x0a, 0xd4, 0xe9, 0xf6, 0x3c, + 0x38, 0xfd, 0xc7, 0xca, 0xa6, 0x5d, 0x85, 0x46, 0xae, 0x2b, 0xf3, 0x40, 0x79, 0xd7, 0x48, 0x28, + 0xda, 0x75, 0x68, 0x8d, 0x3d, 0xfb, 0xd8, 0x8c, 0x88, 0xd8, 0x69, 0x9d, 0x07, 0xca, 0x3b, 0x46, + 0x93, 0xd2, 0x0e, 0xc8, 0x04, 0xeb, 0x7f, 0x53, 0x40, 0x1d, 0x90, 0x89, 0x3f, 0xc6, 0x42, 0xf6, + 0x35, 0xa8, 0x73, 0x11, 0x58, 0x2c, 0xb5, 0x37, 0xd5, 0xfe, 0xc1, 0x29, 0xcb, 0x99, 0x2c, 0xcd, + 0x8b, 0x39, 0xed, 0x0e, 0x34, 0x84, 0x32, 0xbd, 0x0a, 0x83, 0x75, 0xfa, 0x07, 0xa7, 0x5f, 0x30, + 0x0a, 0xc3, 0x25, 0xb3, 0xda, 0xfb, 0xa0, 0x46, 0x81, 0xe5, 0x86, 0x16, 0x3b, 0x09, 0xc3, 0x5e, + 0x95, 0xa1, 0x51, 0xff, 0x20, 0x23, 0xb2, 0x1f, 0xe4, 0x50, 0xaf, 0x97, 0x16, 0x65, 0xc5, 0xe7, + 0xce, 0x57, 0xbc, 0x7e, 0x56, 0xf1, 0x5f, 0x2b, 0xd0, 0x3a, 0x48, 0x2f, 0x8a, 0xf7, 0x41, 0x0d, + 0xf8, 0xa7, 0x29, 0x1d, 0x73, 0x6a, 0x5f, 0x3e, 0xe2, 0xda, 0x41, 0x36, 0xd0, 0xee, 0x43, 0xc3, + 0xc1, 0x91, 0x45, 0xc6, 0xa1, 0xa8, 0x63, 0x17, 0xfb, 0x29, 0xb7, 0x1d, 0x3e, 0xc1, 0x0d, 0x21, + 0x50, 0xda, 0x47, 0x00, 0x21, 0x0e, 0x92, 0x36, 0x51, 0x95, 0xfd, 0xa6, 0x97, 0xfd, 0x66, 0x90, + 0xce, 0xb1, 0x9f, 0x49, 0x58, 0x7d, 0x03, 0xe6, 0x0e, 0xd8, 0x95, 0x74, 0x05, 0x2a, 0xd1, 0x29, + 0x13, 0xad, 0xcc, 0x82, 0x95, 0xe8, 0x54, 0xff, 0xdf, 0x0a, 0x74, 0x93, 0x0a, 0x5e, 0xf8, 0xf3, + 0x67, 0xa4, 0xb6, 0xab, 0xd0, 0x1a, 0x5a, 0xa1, 0xe9, 0x07, 0xc4, 0x4e, 0xd2, 0x44, 0x73, 0x68, + 0x85, 0xfb, 0x74, 0x9c, 0x4c, 0x8e, 0xc9, 0x84, 0x44, 0x22, 0xc5, 0xd1, 0xc9, 0xa7, 0x74, 0x4c, + 0x37, 0x78, 0xe4, 0x31, 0x67, 0xa8, 0x46, 0x25, 0xf2, 0xb2, 0xcd, 0x5c, 0x97, 0x93, 0xcd, 0x5b, + 0xa0, 0xd1, 0xeb, 0xbb, 0x29, 0x9a, 0x64, 0xa6, 0x3d, 0x8a, 0xdd, 0x63, 0x91, 0x16, 0x10, 0x9d, + 0x11, 0x6d, 0xcf, 0x6d, 0x4a, 0xa7, 0x25, 0x0c, 0x43, 0x8f, 0x79, 0x45, 0x2c, 0xca, 0x6c, 0x4a, + 0x7a, 0xca, 0xcb, 0xe1, 0x2b, 0xd0, 0xb4, 0x47, 0x16, 0x71, 0x4d, 0xe2, 0x88, 0x02, 0xa7, 0xc1, + 0xc6, 0x4f, 0x1c, 0xfd, 0xff, 0x15, 0x58, 0x48, 0xec, 0x91, 0x39, 0xbb, 0xc0, 0x51, 0x39, 0xc3, + 0x91, 0x16, 0xaa, 0xc9, 0x81, 0x69, 0x9e, 0x88, 0xae, 0x29, 0xa4, 0xa4, 0x17, 0x79, 0x40, 0x20, + 0x6c, 0x94, 0x01, 0x8c, 0x3c, 0x20, 0x4c, 0x1a, 0x4d, 0x29, 0x69, 0xa0, 0xf7, 0xa1, 0x93, 0x09, + 0x46, 0x9d, 0xbb, 0x0c, 0x4c, 0x02, 0x61, 0x0c, 0x9e, 0xfc, 0x5a, 0x94, 0xc2, 0xac, 0xa0, 0x3f, + 0x85, 0x0b, 0xb2, 0x63, 0x7f, 0x59, 0x05, 0xa5, 0x13, 0x58, 0x4c, 0xb8, 0x9d, 0x5b, 0xe1, 0xa8, + 0xbf, 0xb8, 0xc2, 0xd1, 0x0d, 0xe8, 0x25, 0x4b, 0xbd, 0xaa, 0x86, 0x79, 0xdd, 0xd5, 0xf4, 0x9f, + 0x58, 0xd2, 0x1a, 0xba, 0x4f, 0x1c, 0xec, 0x46, 0x24, 0x9a, 0x6a, 0x1b, 0xd0, 0x24, 0xe2, 0x5b, + 0xec, 0x8f, 0x4e, 0x3f, 0x99, 0xe4, 0xf7, 0x73, 0x92, 0x41, 0x91, 0x3d, 0xb2, 0xc6, 0xd4, 0xf7, + 0xd8, 0x1c, 0x11, 0xc7, 0xc1, 0xae, 0x58, 0x60, 0x3e, 0xa5, 0x3f, 0x66, 0xe4, 0x3c, 0xf4, 0x84, + 0x84, 0xb1, 0x35, 0x16, 0x97, 0xd2, 0x0c, 0xfa, 0x82, 0x91, 0x4b, 0xdb, 0x2a, 0xb5, 0xb2, 0xb6, + 0x8a, 0x3e, 0x84, 0x2e, 0x15, 0x1d, 0x3b, 0xa9, 0xf0, 0xb3, 0x2b, 0xb9, 0x65, 0x00, 0x9f, 0x75, + 0x4e, 0xcc, 0xe4, 0x10, 0x57, 0x8d, 0x96, 0x9f, 0xf6, 0x52, 0x72, 0x46, 0xaa, 0x16, 0x8d, 0xf4, + 0xad, 0x02, 0x0b, 0x8f, 0x70, 0xb4, 0xbb, 0xbd, 0xf3, 0x58, 0x34, 0x5a, 0xe9, 0x6f, 0xde, 0xc0, + 0x52, 0xb7, 0x61, 0xde, 0xc7, 0x38, 0x30, 0xcf, 0x88, 0xd0, 0xa1, 0xe4, 0xac, 0xa5, 0x53, 0xa6, + 0x7b, 0xb5, 0x54, 0xf7, 0x77, 0xa1, 0x5b, 0x10, 0x87, 0xee, 0x13, 0x3e, 0x32, 0xb3, 0xfa, 0x13, + 0xc2, 0x14, 0xa0, 0xbf, 0x03, 0x9d, 0x01, 0x8e, 0xbe, 0xdc, 0xdc, 0x93, 0x2e, 0x91, 0xf2, 0x8d, + 0x46, 0x39, 0x73, 0xeb, 0xbe, 0x03, 0x9d, 0x3d, 0xd1, 0xa9, 0xde, 0x65, 0x3d, 0xdf, 0x4b, 0x50, + 0xcf, 0xed, 0x74, 0x31, 0xd2, 0xb7, 0x60, 0x3e, 0x01, 0x26, 0x99, 0xe1, 0x12, 0xd4, 0xbd, 0xa3, + 0xa3, 0x10, 0x27, 0xf7, 0x43, 0x31, 0x92, 0x58, 0x54, 0x72, 0x2c, 0x3e, 0x81, 0x6e, 0xc2, 0xe2, + 0x4b, 0x7f, 0xec, 0x59, 0x0e, 0x75, 0xa6, 0x6f, 0x4d, 0xe9, 0x67, 0xd2, 0x2f, 0x11, 0x43, 0x56, + 0x16, 0x5a, 0xe1, 0x48, 0xd8, 0x90, 0x7d, 0xeb, 0x6b, 0xd0, 0x1c, 0xe0, 0xf1, 0xd1, 0x01, 0x5d, + 0x3b, 0xf7, 0x4b, 0x45, 0xfa, 0xa5, 0x7e, 0x17, 0x16, 0x76, 0xf0, 0x61, 0x3c, 0x7c, 0x4a, 0xdc, + 0xe3, 0x1d, 0x6c, 0xf3, 0x97, 0x83, 0x45, 0xa8, 0x4f, 0x71, 0x68, 0xba, 0x1e, 0x5b, 0xa7, 0x69, + 0xcc, 0x4d, 0x71, 0xf8, 0xdc, 0xd3, 0x2f, 0x48, 0xd8, 0x47, 0x38, 0x1a, 0x44, 0x56, 0x84, 0xf5, + 0xbf, 0x54, 0x68, 0xc5, 0x2b, 0xa8, 0x8c, 0xc4, 0x34, 0xb2, 0xa6, 0x5e, 0x1c, 0x25, 0x35, 0x3f, + 0x1f, 0x25, 0xbd, 0x97, 0x4a, 0xd6, 0x7b, 0xb9, 0x04, 0xf5, 0x09, 0xeb, 0x8a, 0x0a, 0xa7, 0x8a, + 0x51, 0xae, 0xc5, 0x53, 0x9b, 0xd1, 0xe2, 0x99, 0x9b, 0xd5, 0xe2, 0x99, 0x79, 0xdb, 0xae, 0x9f, + 0x73, 0xdb, 0x5e, 0x06, 0x08, 0x70, 0x88, 0x23, 0x76, 0x13, 0x66, 0xe7, 0x45, 0xcb, 0x68, 0x31, + 0x0a, 0xbd, 0x74, 0xd2, 0xaa, 0x8b, 0x4f, 0x27, 0x3d, 0x81, 0x26, 0xd3, 0x4c, 0x65, 0xc4, 0xa4, + 0x8f, 0xfa, 0x16, 0x68, 0x81, 0xe8, 0x0b, 0x98, 0x47, 0xd6, 0x31, 0xbf, 0x55, 0x8b, 0xb7, 0x20, + 0x94, 0xcc, 0xec, 0x59, 0xc7, 0xec, 0x5a, 0xad, 0xdd, 0x85, 0x85, 0x14, 0xcd, 0x9a, 0x07, 0xbe, + 0x17, 0xb2, 0x7b, 0x72, 0xc7, 0x98, 0x4f, 0x26, 0x28, 0x70, 0xdf, 0x0b, 0xf5, 0x79, 0xe8, 0x48, + 0x36, 0xf6, 0x7c, 0x7d, 0x1f, 0xd4, 0x94, 0xf0, 0xd4, 0x1b, 0xb2, 0x0b, 0x3e, 0x3e, 0xc1, 0xe3, + 0xe4, 0x35, 0x81, 0x0d, 0xa8, 0x79, 0x0f, 0x63, 0xfb, 0x18, 0x47, 0xc2, 0xe6, 0x62, 0xc4, 0x6e, + 0xf3, 0xf8, 0x34, 0x12, 0x46, 0x67, 0xdf, 0xfa, 0x23, 0xb8, 0x90, 0x72, 0x7c, 0x86, 0x27, 0x5e, + 0x30, 0x35, 0x30, 0x8f, 0x39, 0x39, 0x81, 0x74, 0xb2, 0x04, 0x32, 0x2b, 0x6e, 0x37, 0x60, 0xbe, + 0xc0, 0x88, 0xb9, 0x99, 0x7d, 0x25, 0x01, 0xc1, 0x47, 0xfa, 0x7f, 0xc0, 0xc5, 0x02, 0xf4, 0xab, + 0x80, 0x44, 0xf8, 0xfc, 0x45, 0x05, 0xa7, 0x8a, 0xcc, 0x49, 0xbc, 0xa6, 0x84, 0x23, 0x71, 0x5b, + 0xe4, 0x03, 0xfd, 0x6d, 0x49, 0xa7, 0x3d, 0x4a, 0x49, 0x37, 0x6d, 0x88, 0xed, 0xc8, 0x4b, 0x76, + 0xb8, 0x18, 0xdd, 0xfd, 0x71, 0x11, 0xda, 0xe2, 0x1c, 0x61, 0x75, 0xd8, 0x0a, 0x5c, 0x92, 0x86, + 0x66, 0xf6, 0x60, 0x8a, 0xfe, 0x69, 0xa9, 0xf6, 0xed, 0x1f, 0x7a, 0x8a, 0xb6, 0x94, 0x5e, 0x9e, + 0x19, 0x62, 0x9f, 0xb8, 0x43, 0xa4, 0x88, 0xb9, 0x65, 0xb8, 0x20, 0xcf, 0x89, 0x57, 0x10, 0x54, + 0x59, 0xaa, 0x7d, 0x57, 0x32, 0x2d, 0xde, 0x39, 0x50, 0x55, 0x4c, 0xdf, 0x80, 0x45, 0x79, 0x3a, + 0x7d, 0x14, 0x42, 0x35, 0xc1, 0xbe, 0x20, 0x5c, 0xd6, 0x2e, 0x45, 0x73, 0x02, 0x71, 0x07, 0xae, + 0xe4, 0x56, 0x90, 0x13, 0x17, 0xaa, 0x2f, 0x35, 0x29, 0xe8, 0x8f, 0x14, 0xb8, 0x0e, 0x4b, 0x65, + 0x40, 0x9e, 0x75, 0x50, 0x43, 0x42, 0x6e, 0xc0, 0xd5, 0x32, 0xa4, 0x48, 0x71, 0xa8, 0xb9, 0xd4, + 0xfc, 0x2e, 0x81, 0x16, 0xe4, 0xcb, 0x5e, 0x23, 0x50, 0xab, 0xdc, 0x40, 0xc9, 0x34, 0x08, 0x0b, + 0xe8, 0xd0, 0x2b, 0x30, 0x48, 0x8f, 0x05, 0xd4, 0x16, 0x2c, 0x0a, 0x56, 0xca, 0x00, 0xaa, 0x60, + 0x52, 0x90, 0x22, 0xeb, 0x22, 0xa3, 0x8e, 0x60, 0x71, 0x13, 0x2e, 0xcb, 0x08, 0xa9, 0xa7, 0x8a, + 0xba, 0x02, 0x72, 0x0d, 0xb4, 0x9c, 0x27, 0x59, 0xf1, 0x8b, 0xe6, 0xc5, 0xec, 0x5a, 0x5e, 0x4e, + 0xf9, 0xc2, 0x83, 0xd0, 0x52, 0x9d, 0x62, 0x9a, 0x8a, 0x76, 0x1d, 0x2e, 0xe6, 0x2c, 0x27, 0x9e, + 0xd7, 0xd1, 0x82, 0x10, 0xf4, 0x36, 0x5c, 0x2b, 0x44, 0x52, 0xee, 0x31, 0x09, 0x69, 0x29, 0xae, + 0x57, 0x8a, 0xdb, 0xb2, 0x8f, 0xd1, 0x05, 0xee, 0xa9, 0xdf, 0x95, 0xc8, 0xcc, 0x1f, 0x97, 0xd0, + 0xc5, 0x72, 0xbb, 0xa5, 0xe5, 0x2b, 0x5a, 0x14, 0xcb, 0x5c, 0x85, 0x85, 0x3c, 0x80, 0xf2, 0xbf, + 0x94, 0x6a, 0x9c, 0x8b, 0x97, 0x7c, 0xcf, 0x00, 0x5d, 0x16, 0xa8, 0x82, 0xff, 0xe4, 0x57, 0x59, + 0xd4, 0x13, 0x98, 0xd5, 0x7c, 0x88, 0xe6, 0x1e, 0x6a, 0xd1, 0x95, 0x72, 0x50, 0xee, 0x11, 0x0f, + 0x2d, 0x09, 0x81, 0x57, 0xf3, 0x1a, 0xa5, 0x4f, 0x77, 0xe8, 0xaa, 0x64, 0x94, 0x42, 0x34, 0x64, + 0xaf, 0xb1, 0xe8, 0x5a, 0xf9, 0xae, 0xca, 0x1e, 0x49, 0xd0, 0x72, 0x79, 0xd4, 0x26, 0xd3, 0xd7, + 0xd3, 0xa8, 0xcd, 0xf9, 0x39, 0x39, 0x81, 0xd1, 0x8a, 0xb4, 0x8b, 0x0a, 0x96, 0x91, 0xdb, 0xd2, + 0x48, 0x2f, 0xb7, 0x71, 0xbe, 0x55, 0x8d, 0x56, 0xcb, 0xc3, 0x3b, 0x6b, 0x5f, 0xa3, 0xb5, 0xf2, + 0xf0, 0x96, 0xea, 0x7b, 0x74, 0xbb, 0xdc, 0xbe, 0xb9, 0xa2, 0x1d, 0xdd, 0x11, 0xa0, 0x42, 0x7c, + 0x16, 0xcb, 0x6d, 0xb4, 0x2e, 0x24, 0xba, 0x03, 0xcb, 0xb9, 0xf8, 0x2c, 0x3e, 0x65, 0xa2, 0x8d, + 0x14, 0x78, 0xa5, 0x1c, 0x48, 0xa5, 0xbf, 0x2b, 0x39, 0xed, 0x76, 0xc1, 0x12, 0xb9, 0x56, 0x0d, + 0xba, 0x27, 0xed, 0x30, 0x2d, 0x1f, 0xb2, 0x6c, 0xfe, 0xad, 0xa5, 0xfa, 0x77, 0x7c, 0xbe, 0x60, + 0xd1, 0x7c, 0x07, 0x1f, 0xbd, 0x5d, 0x6e, 0x2f, 0xa9, 0x15, 0x8d, 0xfa, 0xe5, 0x99, 0x5b, 0x34, + 0xa5, 0xd1, 0xfd, 0x72, 0x4b, 0x15, 0x9b, 0x50, 0xe8, 0x9d, 0x74, 0x27, 0x17, 0x3c, 0x2c, 0x77, + 0x0d, 0xd1, 0xbb, 0xa9, 0x5e, 0xeb, 0x79, 0x7e, 0xc5, 0xae, 0x25, 0xda, 0x4c, 0x35, 0x2c, 0x70, + 0xcc, 0xf7, 0x21, 0xd1, 0x7b, 0xb3, 0x38, 0x16, 0x9b, 0x87, 0xe8, 0xfd, 0x94, 0xa3, 0x5e, 0xcc, + 0x6d, 0xd9, 0xbd, 0x08, 0x7d, 0x50, 0x1e, 0xa9, 0xf9, 0x0b, 0x08, 0xfa, 0x50, 0x68, 0x5b, 0xb0, + 0xab, 0xf4, 0xef, 0x46, 0xe8, 0x9f, 0x05, 0xa3, 0x75, 0xb8, 0x9e, 0x53, 0xf4, 0xcc, 0x43, 0x25, + 0xfa, 0x48, 0x20, 0x6f, 0xe5, 0x8f, 0xa1, 0xc2, 0xbb, 0x22, 0xfa, 0x17, 0xb1, 0x66, 0x71, 0x0f, + 0xe5, 0x9a, 0x17, 0xe8, 0x41, 0x7a, 0x4c, 0x2e, 0x97, 0xa1, 0xb2, 0x9c, 0xf8, 0xaf, 0x69, 0x8a, + 0xb9, 0x52, 0x0e, 0xa4, 0xde, 0xff, 0xb7, 0x72, 0x6e, 0x67, 0x2e, 0x49, 0xe8, 0xe3, 0x19, 0x1b, + 0x3c, 0x8f, 0xfa, 0xa4, 0x7c, 0xcd, 0xdc, 0x75, 0x05, 0x7d, 0x2a, 0x58, 0x6d, 0xc0, 0x8d, 0x59, + 0x7a, 0x26, 0x2e, 0xfd, 0x4c, 0x40, 0xef, 0xc1, 0xcd, 0x32, 0x68, 0x7e, 0xcf, 0x6f, 0x09, 0x70, + 0x1f, 0xd6, 0xca, 0xc0, 0x67, 0xf6, 0xfe, 0x43, 0x21, 0xec, 0xbd, 0xbc, 0xee, 0x67, 0xee, 0x15, + 0xc8, 0x59, 0x6a, 0x7e, 0x9f, 0x6c, 0xeb, 0x3b, 0x33, 0xc0, 0xc9, 0xc5, 0x02, 0xe1, 0xa5, 0xda, + 0xf7, 0x25, 0x86, 0xca, 0xdf, 0x35, 0xd0, 0xd1, 0x52, 0xed, 0x87, 0x12, 0x43, 0xe5, 0xaa, 0x65, + 0x34, 0x14, 0xac, 0x0a, 0xe1, 0x2c, 0x57, 0xd0, 0x68, 0x24, 0x18, 0x15, 0x8c, 0x59, 0x52, 0x13, + 0x23, 0x57, 0xb0, 0x2b, 0x84, 0x61, 0x01, 0x8a, 0x3c, 0xc1, 0xf1, 0x2e, 0xac, 0x9c, 0x03, 0x63, + 0x15, 0x2f, 0xf2, 0x05, 0xcb, 0x59, 0xab, 0x67, 0xd5, 0x2b, 0xfa, 0x9a, 0x43, 0x1f, 0xbe, 0x0f, + 0xab, 0xb6, 0x37, 0xe9, 0x87, 0x56, 0xe4, 0x85, 0x23, 0x32, 0xb6, 0x0e, 0xc3, 0x7e, 0x14, 0xe0, + 0x97, 0x5e, 0xd0, 0x1f, 0x93, 0x43, 0xfe, 0x6f, 0x7e, 0x87, 0xf1, 0xd1, 0xc3, 0xce, 0x01, 0x23, + 0x0a, 0xae, 0x7f, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x2a, 0xe4, 0xc0, 0x85, 0x16, 0x28, 0x00, 0x00, +} diff --git a/accounts/usbwallet/internal/trezor/messages.proto b/accounts/usbwallet/internal/trezor/messages.proto new file mode 100644 index 000000000..178956457 --- /dev/null +++ b/accounts/usbwallet/internal/trezor/messages.proto @@ -0,0 +1,903 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages.proto +// dated 28.07.2017, commit dd8ec3231fb5f7992360aff9bdfe30bb58130f4b. + +/** + * Messages for TREZOR communication + */ + +// Sugar for easier handling in Java +option java_package = "com.satoshilabs.trezor.lib.protobuf"; +option java_outer_classname = "TrezorMessage"; + +import "types.proto"; + +/** + * Mapping between Trezor wire identifier (uint) and a protobuf message + */ +enum MessageType { + MessageType_Initialize = 0 [(wire_in) = true]; + MessageType_Ping = 1 [(wire_in) = true]; + MessageType_Success = 2 [(wire_out) = true]; + MessageType_Failure = 3 [(wire_out) = true]; + MessageType_ChangePin = 4 [(wire_in) = true]; + MessageType_WipeDevice = 5 [(wire_in) = true]; + MessageType_FirmwareErase = 6 [(wire_in) = true, (wire_bootloader) = true]; + MessageType_FirmwareUpload = 7 [(wire_in) = true, (wire_bootloader) = true]; + MessageType_FirmwareRequest = 8 [(wire_out) = true, (wire_bootloader) = true]; + MessageType_GetEntropy = 9 [(wire_in) = true]; + MessageType_Entropy = 10 [(wire_out) = true]; + MessageType_GetPublicKey = 11 [(wire_in) = true]; + MessageType_PublicKey = 12 [(wire_out) = true]; + MessageType_LoadDevice = 13 [(wire_in) = true]; + MessageType_ResetDevice = 14 [(wire_in) = true]; + MessageType_SignTx = 15 [(wire_in) = true]; + MessageType_SimpleSignTx = 16 [(wire_in) = true, deprecated = true]; + MessageType_Features = 17 [(wire_out) = true]; + MessageType_PinMatrixRequest = 18 [(wire_out) = true]; + MessageType_PinMatrixAck = 19 [(wire_in) = true, (wire_tiny) = true]; + MessageType_Cancel = 20 [(wire_in) = true]; + MessageType_TxRequest = 21 [(wire_out) = true]; + MessageType_TxAck = 22 [(wire_in) = true]; + MessageType_CipherKeyValue = 23 [(wire_in) = true]; + MessageType_ClearSession = 24 [(wire_in) = true]; + MessageType_ApplySettings = 25 [(wire_in) = true]; + MessageType_ButtonRequest = 26 [(wire_out) = true]; + MessageType_ButtonAck = 27 [(wire_in) = true, (wire_tiny) = true]; + MessageType_ApplyFlags = 28 [(wire_in) = true]; + MessageType_GetAddress = 29 [(wire_in) = true]; + MessageType_Address = 30 [(wire_out) = true]; + MessageType_SelfTest = 32 [(wire_in) = true, (wire_bootloader) = true]; + MessageType_BackupDevice = 34 [(wire_in) = true]; + MessageType_EntropyRequest = 35 [(wire_out) = true]; + MessageType_EntropyAck = 36 [(wire_in) = true]; + MessageType_SignMessage = 38 [(wire_in) = true]; + MessageType_VerifyMessage = 39 [(wire_in) = true]; + MessageType_MessageSignature = 40 [(wire_out) = true]; + MessageType_PassphraseRequest = 41 [(wire_out) = true]; + MessageType_PassphraseAck = 42 [(wire_in) = true, (wire_tiny) = true]; + MessageType_EstimateTxSize = 43 [(wire_in) = true, deprecated = true]; + MessageType_TxSize = 44 [(wire_out) = true, deprecated = true]; + MessageType_RecoveryDevice = 45 [(wire_in) = true]; + MessageType_WordRequest = 46 [(wire_out) = true]; + MessageType_WordAck = 47 [(wire_in) = true]; + MessageType_CipheredKeyValue = 48 [(wire_out) = true]; + MessageType_EncryptMessage = 49 [(wire_in) = true, deprecated = true]; + MessageType_EncryptedMessage = 50 [(wire_out) = true, deprecated = true]; + MessageType_DecryptMessage = 51 [(wire_in) = true, deprecated = true]; + MessageType_DecryptedMessage = 52 [(wire_out) = true, deprecated = true]; + MessageType_SignIdentity = 53 [(wire_in) = true]; + MessageType_SignedIdentity = 54 [(wire_out) = true]; + MessageType_GetFeatures = 55 [(wire_in) = true]; + MessageType_EthereumGetAddress = 56 [(wire_in) = true]; + MessageType_EthereumAddress = 57 [(wire_out) = true]; + MessageType_EthereumSignTx = 58 [(wire_in) = true]; + MessageType_EthereumTxRequest = 59 [(wire_out) = true]; + MessageType_EthereumTxAck = 60 [(wire_in) = true]; + MessageType_GetECDHSessionKey = 61 [(wire_in) = true]; + MessageType_ECDHSessionKey = 62 [(wire_out) = true]; + MessageType_SetU2FCounter = 63 [(wire_in) = true]; + MessageType_EthereumSignMessage = 64 [(wire_in) = true]; + MessageType_EthereumVerifyMessage = 65 [(wire_in) = true]; + MessageType_EthereumMessageSignature = 66 [(wire_out) = true]; + MessageType_DebugLinkDecision = 100 [(wire_debug_in) = true, (wire_tiny) = true]; + MessageType_DebugLinkGetState = 101 [(wire_debug_in) = true]; + MessageType_DebugLinkState = 102 [(wire_debug_out) = true]; + MessageType_DebugLinkStop = 103 [(wire_debug_in) = true]; + MessageType_DebugLinkLog = 104 [(wire_debug_out) = true]; + MessageType_DebugLinkMemoryRead = 110 [(wire_debug_in) = true]; + MessageType_DebugLinkMemory = 111 [(wire_debug_out) = true]; + MessageType_DebugLinkMemoryWrite = 112 [(wire_debug_in) = true]; + MessageType_DebugLinkFlashErase = 113 [(wire_debug_in) = true]; +} + +//////////////////// +// Basic messages // +//////////////////// + +/** + * Request: Reset device to default state and ask for device details + * @next Features + */ +message Initialize { +} + +/** + * Request: Ask for device details (no device reset) + * @next Features + */ +message GetFeatures { +} + +/** + * Response: Reports various information about the device + * @prev Initialize + * @prev GetFeatures + */ +message Features { + optional string vendor = 1; // name of the manufacturer, e.g. "bitcointrezor.com" + optional uint32 major_version = 2; // major version of the device, e.g. 1 + optional uint32 minor_version = 3; // minor version of the device, e.g. 0 + optional uint32 patch_version = 4; // patch version of the device, e.g. 0 + optional bool bootloader_mode = 5; // is device in bootloader mode? + optional string device_id = 6; // device's unique identifier + optional bool pin_protection = 7; // is device protected by PIN? + optional bool passphrase_protection = 8; // is node/mnemonic encrypted using passphrase? + optional string language = 9; // device language + optional string label = 10; // device description label + repeated CoinType coins = 11; // supported coins + optional bool initialized = 12; // does device contain seed? + optional bytes revision = 13; // SCM revision of firmware + optional bytes bootloader_hash = 14; // hash of the bootloader + optional bool imported = 15; // was storage imported from an external source? + optional bool pin_cached = 16; // is PIN already cached in session? + optional bool passphrase_cached = 17; // is passphrase already cached in session? + optional bool firmware_present = 18; // is valid firmware loaded? + optional bool needs_backup = 19; // does storage need backup? (equals to Storage.needs_backup) + optional uint32 flags = 20; // device flags (equals to Storage.flags) +} + +/** + * Request: clear session (removes cached PIN, passphrase, etc). + * @next Success + */ +message ClearSession { +} + +/** + * Request: change language and/or label of the device + * @next Success + * @next Failure + * @next ButtonRequest + * @next PinMatrixRequest + */ +message ApplySettings { + optional string language = 1; + optional string label = 2; + optional bool use_passphrase = 3; + optional bytes homescreen = 4; +} + +/** + * Request: set flags of the device + * @next Success + * @next Failure + */ +message ApplyFlags { + optional uint32 flags = 1; // bitmask, can only set bits, not unset +} + +/** + * Request: Starts workflow for setting/changing/removing the PIN + * @next ButtonRequest + * @next PinMatrixRequest + */ +message ChangePin { + optional bool remove = 1; // is PIN removal requested? +} + +/** + * Request: Test if the device is alive, device sends back the message in Success response + * @next Success + */ +message Ping { + optional string message = 1; // message to send back in Success message + optional bool button_protection = 2; // ask for button press + optional bool pin_protection = 3; // ask for PIN if set in device + optional bool passphrase_protection = 4; // ask for passphrase if set in device +} + +/** + * Response: Success of the previous request + */ +message Success { + optional string message = 1; // human readable description of action or request-specific payload +} + +/** + * Response: Failure of the previous request + */ +message Failure { + optional FailureType code = 1; // computer-readable definition of the error state + optional string message = 2; // human-readable message of the error state +} + +/** + * Response: Device is waiting for HW button press. + * @next ButtonAck + * @next Cancel + */ +message ButtonRequest { + optional ButtonRequestType code = 1; + optional string data = 2; +} + +/** + * Request: Computer agrees to wait for HW button press + * @prev ButtonRequest + */ +message ButtonAck { +} + +/** + * Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme + * @next PinMatrixAck + * @next Cancel + */ +message PinMatrixRequest { + optional PinMatrixRequestType type = 1; +} + +/** + * Request: Computer responds with encoded PIN + * @prev PinMatrixRequest + */ +message PinMatrixAck { + required string pin = 1; // matrix encoded PIN entered by user +} + +/** + * Request: Abort last operation that required user interaction + * @prev ButtonRequest + * @prev PinMatrixRequest + * @prev PassphraseRequest + */ +message Cancel { +} + +/** + * Response: Device awaits encryption passphrase + * @next PassphraseAck + * @next Cancel + */ +message PassphraseRequest { +} + +/** + * Request: Send passphrase back + * @prev PassphraseRequest + */ +message PassphraseAck { + required string passphrase = 1; +} + +/** + * Request: Request a sample of random data generated by hardware RNG. May be used for testing. + * @next ButtonRequest + * @next Entropy + * @next Failure + */ +message GetEntropy { + required uint32 size = 1; // size of requested entropy +} + +/** + * Response: Reply with random data generated by internal RNG + * @prev GetEntropy + */ +message Entropy { + required bytes entropy = 1; // stream of random generated bytes +} + +/** + * Request: Ask device for public key corresponding to address_n path + * @next PassphraseRequest + * @next PublicKey + * @next Failure + */ +message GetPublicKey { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional string ecdsa_curve_name = 2; // ECDSA curve name to use + optional bool show_display = 3; // optionally show on display before sending the result + optional string coin_name = 4 [default='Bitcoin']; +} + +/** + * Response: Contains public key derived from device private seed + * @prev GetPublicKey + */ +message PublicKey { + required HDNodeType node = 1; // BIP32 public node + optional string xpub = 2; // serialized form of public node +} + +/** + * Request: Ask device for address corresponding to address_n path + * @next PassphraseRequest + * @next Address + * @next Failure + */ +message GetAddress { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional string coin_name = 2 [default='Bitcoin']; + optional bool show_display = 3 ; // optionally show on display before sending the result + optional MultisigRedeemScriptType multisig = 4; // filled if we are showing a multisig address + optional InputScriptType script_type = 5 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.) +} + +/** + * Request: Ask device for Ethereum address corresponding to address_n path + * @next PassphraseRequest + * @next EthereumAddress + * @next Failure + */ +message EthereumGetAddress { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bool show_display = 2; // optionally show on display before sending the result +} + +/** + * Response: Contains address derived from device private seed + * @prev GetAddress + */ +message Address { + required string address = 1; // Coin address in Base58 encoding +} + +/** + * Response: Contains an Ethereum address derived from device private seed + * @prev EthereumGetAddress + */ +message EthereumAddress { + required bytes address = 1; // Coin address as an Ethereum 160 bit hash +} + +/** + * Request: Request device to wipe all sensitive data and settings + * @next ButtonRequest + */ +message WipeDevice { +} + +/** + * Request: Load seed and related internal settings from the computer + * @next ButtonRequest + * @next Success + * @next Failure + */ +message LoadDevice { + optional string mnemonic = 1; // seed encoded as BIP-39 mnemonic (12, 18 or 24 words) + optional HDNodeType node = 2; // BIP-32 node + optional string pin = 3; // set PIN protection + optional bool passphrase_protection = 4; // enable master node encryption using passphrase + optional string language = 5 [default='english']; // device language + optional string label = 6; // device label + optional bool skip_checksum = 7; // do not test mnemonic for valid BIP-39 checksum + optional uint32 u2f_counter = 8; // U2F counter +} + +/** + * Request: Ask device to do initialization involving user interaction + * @next EntropyRequest + * @next Failure + */ +message ResetDevice { + optional bool display_random = 1; // display entropy generated by the device before asking for additional entropy + optional uint32 strength = 2 [default=256]; // strength of seed in bits + optional bool passphrase_protection = 3; // enable master node encryption using passphrase + optional bool pin_protection = 4; // enable PIN protection + optional string language = 5 [default='english']; // device language + optional string label = 6; // device label + optional uint32 u2f_counter = 7; // U2F counter + optional bool skip_backup = 8; // postpone seed backup to BackupDevice workflow +} + +/** + * Request: Perform backup of the device seed if not backed up using ResetDevice + * @next ButtonRequest + */ +message BackupDevice { +} + +/** + * Response: Ask for additional entropy from host computer + * @prev ResetDevice + * @next EntropyAck + */ +message EntropyRequest { +} + +/** + * Request: Provide additional entropy for seed generation function + * @prev EntropyRequest + * @next ButtonRequest + */ +message EntropyAck { + optional bytes entropy = 1; // 256 bits (32 bytes) of random data +} + +/** + * Request: Start recovery workflow asking user for specific words of mnemonic + * Used to recovery device safely even on untrusted computer. + * @next WordRequest + */ +message RecoveryDevice { + optional uint32 word_count = 1; // number of words in BIP-39 mnemonic + optional bool passphrase_protection = 2; // enable master node encryption using passphrase + optional bool pin_protection = 3; // enable PIN protection + optional string language = 4 [default='english']; // device language + optional string label = 5; // device label + optional bool enforce_wordlist = 6; // enforce BIP-39 wordlist during the process + // 7 reserved for unused recovery method + optional uint32 type = 8; // supported recovery type (see RecoveryType) + optional uint32 u2f_counter = 9; // U2F counter + optional bool dry_run = 10; // perform dry-run recovery workflow (for safe mnemonic validation) +} + +/** + * Response: Device is waiting for user to enter word of the mnemonic + * Its position is shown only on device's internal display. + * @prev RecoveryDevice + * @prev WordAck + */ +message WordRequest { + optional WordRequestType type = 1; +} + +/** + * Request: Computer replies with word from the mnemonic + * @prev WordRequest + * @next WordRequest + * @next Success + * @next Failure + */ +message WordAck { + required string word = 1; // one word of mnemonic on asked position +} + +////////////////////////////// +// Message signing messages // +////////////////////////////// + +/** + * Request: Ask device to sign message + * @next MessageSignature + * @next Failure + */ +message SignMessage { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + required bytes message = 2; // message to be signed + optional string coin_name = 3 [default='Bitcoin']; // coin to use for signing + optional InputScriptType script_type = 4 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.) +} + +/** + * Request: Ask device to verify message + * @next Success + * @next Failure + */ +message VerifyMessage { + optional string address = 1; // address to verify + optional bytes signature = 2; // signature to verify + optional bytes message = 3; // message to verify + optional string coin_name = 4 [default='Bitcoin']; // coin to use for verifying +} + +/** + * Response: Signed message + * @prev SignMessage + */ +message MessageSignature { + optional string address = 1; // address used to sign the message + optional bytes signature = 2; // signature of the message +} + +/////////////////////////// +// Encryption/decryption // +/////////////////////////// + +/** + * Request: Ask device to encrypt message + * @next EncryptedMessage + * @next Failure + */ +message EncryptMessage { + optional bytes pubkey = 1; // public key + optional bytes message = 2; // message to encrypt + optional bool display_only = 3; // show just on display? (don't send back via wire) + repeated uint32 address_n = 4; // BIP-32 path to derive the signing key from master node + optional string coin_name = 5 [default='Bitcoin']; // coin to use for signing +} + +/** + * Response: Encrypted message + * @prev EncryptMessage + */ +message EncryptedMessage { + optional bytes nonce = 1; // nonce used during encryption + optional bytes message = 2; // encrypted message + optional bytes hmac = 3; // message hmac +} + +/** + * Request: Ask device to decrypt message + * @next Success + * @next Failure + */ +message DecryptMessage { + repeated uint32 address_n = 1; // BIP-32 path to derive the decryption key from master node + optional bytes nonce = 2; // nonce used during encryption + optional bytes message = 3; // message to decrypt + optional bytes hmac = 4; // message hmac +} + +/** + * Response: Decrypted message + * @prev DecryptedMessage + */ +message DecryptedMessage { + optional bytes message = 1; // decrypted message + optional string address = 2; // address used to sign the message (if used) +} + +/** + * Request: Ask device to encrypt or decrypt value of given key + * @next CipheredKeyValue + * @next Failure + */ +message CipherKeyValue { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional string key = 2; // key component of key:value + optional bytes value = 3; // value component of key:value + optional bool encrypt = 4; // are we encrypting (True) or decrypting (False)? + optional bool ask_on_encrypt = 5; // should we ask on encrypt operation? + optional bool ask_on_decrypt = 6; // should we ask on decrypt operation? + optional bytes iv = 7; // initialization vector (will be computed if not set) +} + +/** + * Response: Return ciphered/deciphered value + * @prev CipherKeyValue + */ +message CipheredKeyValue { + optional bytes value = 1; // ciphered/deciphered value +} + +////////////////////////////////// +// Transaction signing messages // +////////////////////////////////// + +/** + * Request: Estimated size of the transaction + * This behaves exactly like SignTx, which means that it can ask using TxRequest + * This call is non-blocking (except possible PassphraseRequest to unlock the seed) + * @next TxSize + * @next Failure + */ +message EstimateTxSize { + required uint32 outputs_count = 1; // number of transaction outputs + required uint32 inputs_count = 2; // number of transaction inputs + optional string coin_name = 3 [default='Bitcoin']; // coin to use +} + +/** + * Response: Estimated size of the transaction + * @prev EstimateTxSize + */ +message TxSize { + optional uint32 tx_size = 1; // estimated size of transaction in bytes +} + +/** + * Request: Ask device to sign transaction + * @next PassphraseRequest + * @next PinMatrixRequest + * @next TxRequest + * @next Failure + */ +message SignTx { + required uint32 outputs_count = 1; // number of transaction outputs + required uint32 inputs_count = 2; // number of transaction inputs + optional string coin_name = 3 [default='Bitcoin']; // coin to use + optional uint32 version = 4 [default=1]; // transaction version + optional uint32 lock_time = 5 [default=0]; // transaction lock_time +} + +/** + * Request: Simplified transaction signing + * This method doesn't support streaming, so there are hardware limits in number of inputs and outputs. + * In case of success, the result is returned using TxRequest message. + * @next PassphraseRequest + * @next PinMatrixRequest + * @next TxRequest + * @next Failure + */ +message SimpleSignTx { + repeated TxInputType inputs = 1; // transaction inputs + repeated TxOutputType outputs = 2; // transaction outputs + repeated TransactionType transactions = 3; // transactions whose outputs are used to build current inputs + optional string coin_name = 4 [default='Bitcoin']; // coin to use + optional uint32 version = 5 [default=1]; // transaction version + optional uint32 lock_time = 6 [default=0]; // transaction lock_time +} + +/** + * Response: Device asks for information for signing transaction or returns the last result + * If request_index is set, device awaits TxAck message (with fields filled in according to request_type) + * If signature_index is set, 'signature' contains signed input of signature_index's input + * @prev SignTx + * @prev SimpleSignTx + * @prev TxAck + */ +message TxRequest { + optional RequestType request_type = 1; // what should be filled in TxAck message? + optional TxRequestDetailsType details = 2; // request for tx details + optional TxRequestSerializedType serialized = 3; // serialized data and request for next +} + +/** + * Request: Reported transaction data + * @prev TxRequest + * @next TxRequest + */ +message TxAck { + optional TransactionType tx = 1; +} + +/** + * Request: Ask device to sign transaction + * All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing. + * Note: the first at most 1024 bytes of data MUST be transmitted as part of this message. + * @next PassphraseRequest + * @next PinMatrixRequest + * @next EthereumTxRequest + * @next Failure + */ +message EthereumSignTx { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bytes nonce = 2; // <=256 bit unsigned big endian + optional bytes gas_price = 3; // <=256 bit unsigned big endian (in wei) + optional bytes gas_limit = 4; // <=256 bit unsigned big endian + optional bytes to = 5; // 160 bit address hash + optional bytes value = 6; // <=256 bit unsigned big endian (in wei) + optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes) + optional uint32 data_length = 8; // Length of transaction payload + optional uint32 chain_id = 9; // Chain Id for EIP 155 +} + +/** + * Response: Device asks for more data from transaction payload, or returns the signature. + * If data_length is set, device awaits that many more bytes of payload. + * Otherwise, the signature_* fields contain the computed transaction signature. All three fields will be present. + * @prev EthereumSignTx + * @next EthereumTxAck + */ +message EthereumTxRequest { + optional uint32 data_length = 1; // Number of bytes being requested (<= 1024) + optional uint32 signature_v = 2; // Computed signature (recovery parameter, limited to 27 or 28) + optional bytes signature_r = 3; // Computed signature R component (256 bit) + optional bytes signature_s = 4; // Computed signature S component (256 bit) +} + +/** + * Request: Transaction payload data. + * @prev EthereumTxRequest + * @next EthereumTxRequest + */ +message EthereumTxAck { + optional bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes) +} + +//////////////////////////////////////// +// Ethereum: Message signing messages // +//////////////////////////////////////// + +/** + * Request: Ask device to sign message + * @next EthereumMessageSignature + * @next Failure + */ +message EthereumSignMessage { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + required bytes message = 2; // message to be signed +} + +/** + * Request: Ask device to verify message + * @next Success + * @next Failure + */ +message EthereumVerifyMessage { + optional bytes address = 1; // address to verify + optional bytes signature = 2; // signature to verify + optional bytes message = 3; // message to verify +} + +/** + * Response: Signed message + * @prev EthereumSignMessage + */ +message EthereumMessageSignature { + optional bytes address = 1; // address used to sign the message + optional bytes signature = 2; // signature of the message +} + +/////////////////////// +// Identity messages // +/////////////////////// + +/** + * Request: Ask device to sign identity + * @next SignedIdentity + * @next Failure + */ +message SignIdentity { + optional IdentityType identity = 1; // identity + optional bytes challenge_hidden = 2; // non-visible challenge + optional string challenge_visual = 3; // challenge shown on display (e.g. date+time) + optional string ecdsa_curve_name = 4; // ECDSA curve name to use +} + +/** + * Response: Device provides signed identity + * @prev SignIdentity + */ +message SignedIdentity { + optional string address = 1; // identity address + optional bytes public_key = 2; // identity public key + optional bytes signature = 3; // signature of the identity data +} + +/////////////////// +// ECDH messages // +/////////////////// + +/** + * Request: Ask device to generate ECDH session key + * @next ECDHSessionKey + * @next Failure + */ +message GetECDHSessionKey { + optional IdentityType identity = 1; // identity + optional bytes peer_public_key = 2; // peer's public key + optional string ecdsa_curve_name = 3; // ECDSA curve name to use +} + +/** + * Response: Device provides ECDH session key + * @prev GetECDHSessionKey + */ +message ECDHSessionKey { + optional bytes session_key = 1; // ECDH session key +} + +/////////////////// +// U2F messages // +/////////////////// + +/** + * Request: Set U2F counter + * @next Success + */ +message SetU2FCounter { + optional uint32 u2f_counter = 1; // counter +} + +///////////////////////// +// Bootloader messages // +///////////////////////// + +/** + * Request: Ask device to erase its firmware (so it can be replaced via FirmwareUpload) + * @next Success + * @next FirmwareRequest + * @next Failure + */ +message FirmwareErase { + optional uint32 length = 1; // length of new firmware +} + +/** + * Response: Ask for firmware chunk + * @next FirmwareUpload + */ +message FirmwareRequest { + optional uint32 offset = 1; // offset of requested firmware chunk + optional uint32 length = 2; // length of requested firmware chunk +} + +/** + * Request: Send firmware in binary form to the device + * @next Success + * @next Failure + */ +message FirmwareUpload { + required bytes payload = 1; // firmware to be loaded into device + optional bytes hash = 2; // hash of the payload +} + + +/** + * Request: Perform a device self-test + * @next Success + * @next Failure + */ +message SelfTest { + optional bytes payload = 1; // payload to be used in self-test +} + +///////////////////////////////////////////////////////////// +// Debug messages (only available if DebugLink is enabled) // +///////////////////////////////////////////////////////////// + +/** + * Request: "Press" the button on the device + * @next Success + */ +message DebugLinkDecision { + required bool yes_no = 1; // true for "Confirm", false for "Cancel" +} + +/** + * Request: Computer asks for device state + * @next DebugLinkState + */ +message DebugLinkGetState { +} + +/** + * Response: Device current state + * @prev DebugLinkGetState + */ +message DebugLinkState { + optional bytes layout = 1; // raw buffer of display + optional string pin = 2; // current PIN, blank if PIN is not set/enabled + optional string matrix = 3; // current PIN matrix + optional string mnemonic = 4; // current BIP-39 mnemonic + optional HDNodeType node = 5; // current BIP-32 node + optional bool passphrase_protection = 6; // is node/mnemonic encrypted using passphrase? + optional string reset_word = 7; // word on device display during ResetDevice workflow + optional bytes reset_entropy = 8; // current entropy during ResetDevice workflow + optional string recovery_fake_word = 9; // (fake) word on display during RecoveryDevice workflow + optional uint32 recovery_word_pos = 10; // index of mnemonic word the device is expecting during RecoveryDevice workflow +} + +/** + * Request: Ask device to restart + */ +message DebugLinkStop { +} + +/** + * Response: Device wants host to log event + */ +message DebugLinkLog { + optional uint32 level = 1; + optional string bucket = 2; + optional string text = 3; +} + +/** + * Request: Read memory from device + * @next DebugLinkMemory + */ +message DebugLinkMemoryRead { + optional uint32 address = 1; + optional uint32 length = 2; +} + +/** + * Response: Device sends memory back + * @prev DebugLinkMemoryRead + */ +message DebugLinkMemory { + optional bytes memory = 1; +} + +/** + * Request: Write memory to device. + * WARNING: Writing to the wrong location can irreparably break the device. + */ +message DebugLinkMemoryWrite { + optional uint32 address = 1; + optional bytes memory = 2; + optional bool flash = 3; +} + +/** + * Request: Erase block of flash on device + * WARNING: Writing to the wrong location can irreparably break the device. + */ +message DebugLinkFlashErase { + optional uint32 sector = 1; +} diff --git a/accounts/usbwallet/internal/trezor/trezor.go b/accounts/usbwallet/internal/trezor/trezor.go new file mode 100644 index 000000000..487aeb5f8 --- /dev/null +++ b/accounts/usbwallet/internal/trezor/trezor.go @@ -0,0 +1,46 @@ +// Copyright 2017 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/>. + +// This file contains the implementation for interacting with the Trezor hardware +// wallets. The wire protocol spec can be found on the SatoshiLabs website: +// https://doc.satoshilabs.com/trezor-tech/api-protobuf.html + +//go:generate protoc --go_out=Mgoogle/protobuf/descriptor.proto=github.com/golang/protobuf/protoc-gen-go/descriptor,import_path=trezor:. types.proto messages.proto + +// Package trezor contains the wire protocol wrapper in Go. +package trezor + +import ( + "reflect" + + "github.com/golang/protobuf/proto" +) + +// Type returns the protocol buffer type number of a specific message. If the +// message is nil, this method panics! +func Type(msg proto.Message) uint16 { + return uint16(MessageType_value["MessageType_"+reflect.TypeOf(msg).Elem().Name()]) +} + +// Name returns the friendly message type name of a specific protocol buffer +// type numbers. +func Name(kind uint16) string { + name := MessageType_name[int32(kind)] + if len(name) < 12 { + return name + } + return name[12:] +} diff --git a/accounts/usbwallet/internal/trezor/types.pb.go b/accounts/usbwallet/internal/trezor/types.pb.go new file mode 100644 index 000000000..25b7672d2 --- /dev/null +++ b/accounts/usbwallet/internal/trezor/types.pb.go @@ -0,0 +1,1333 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: types.proto + +/* +Package trezor is a generated protocol buffer package. + +It is generated from these files: + types.proto + messages.proto + +It has these top-level messages: + HDNodeType + HDNodePathType + CoinType + MultisigRedeemScriptType + TxInputType + TxOutputType + TxOutputBinType + TransactionType + TxRequestDetailsType + TxRequestSerializedType + IdentityType + Initialize + GetFeatures + Features + ClearSession + ApplySettings + ApplyFlags + ChangePin + Ping + Success + Failure + ButtonRequest + ButtonAck + PinMatrixRequest + PinMatrixAck + Cancel + PassphraseRequest + PassphraseAck + GetEntropy + Entropy + GetPublicKey + PublicKey + GetAddress + EthereumGetAddress + Address + EthereumAddress + WipeDevice + LoadDevice + ResetDevice + BackupDevice + EntropyRequest + EntropyAck + RecoveryDevice + WordRequest + WordAck + SignMessage + VerifyMessage + MessageSignature + EncryptMessage + EncryptedMessage + DecryptMessage + DecryptedMessage + CipherKeyValue + CipheredKeyValue + EstimateTxSize + TxSize + SignTx + SimpleSignTx + TxRequest + TxAck + EthereumSignTx + EthereumTxRequest + EthereumTxAck + EthereumSignMessage + EthereumVerifyMessage + EthereumMessageSignature + SignIdentity + SignedIdentity + GetECDHSessionKey + ECDHSessionKey + SetU2FCounter + FirmwareErase + FirmwareRequest + FirmwareUpload + SelfTest + DebugLinkDecision + DebugLinkGetState + DebugLinkState + DebugLinkStop + DebugLinkLog + DebugLinkMemoryRead + DebugLinkMemory + DebugLinkMemoryWrite + DebugLinkFlashErase +*/ +package trezor + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import google_protobuf "github.com/golang/protobuf/protoc-gen-go/descriptor" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// * +// Type of failures returned by Failure message +// @used_in Failure +type FailureType int32 + +const ( + FailureType_Failure_UnexpectedMessage FailureType = 1 + FailureType_Failure_ButtonExpected FailureType = 2 + FailureType_Failure_DataError FailureType = 3 + FailureType_Failure_ActionCancelled FailureType = 4 + FailureType_Failure_PinExpected FailureType = 5 + FailureType_Failure_PinCancelled FailureType = 6 + FailureType_Failure_PinInvalid FailureType = 7 + FailureType_Failure_InvalidSignature FailureType = 8 + FailureType_Failure_ProcessError FailureType = 9 + FailureType_Failure_NotEnoughFunds FailureType = 10 + FailureType_Failure_NotInitialized FailureType = 11 + FailureType_Failure_FirmwareError FailureType = 99 +) + +var FailureType_name = map[int32]string{ + 1: "Failure_UnexpectedMessage", + 2: "Failure_ButtonExpected", + 3: "Failure_DataError", + 4: "Failure_ActionCancelled", + 5: "Failure_PinExpected", + 6: "Failure_PinCancelled", + 7: "Failure_PinInvalid", + 8: "Failure_InvalidSignature", + 9: "Failure_ProcessError", + 10: "Failure_NotEnoughFunds", + 11: "Failure_NotInitialized", + 99: "Failure_FirmwareError", +} +var FailureType_value = map[string]int32{ + "Failure_UnexpectedMessage": 1, + "Failure_ButtonExpected": 2, + "Failure_DataError": 3, + "Failure_ActionCancelled": 4, + "Failure_PinExpected": 5, + "Failure_PinCancelled": 6, + "Failure_PinInvalid": 7, + "Failure_InvalidSignature": 8, + "Failure_ProcessError": 9, + "Failure_NotEnoughFunds": 10, + "Failure_NotInitialized": 11, + "Failure_FirmwareError": 99, +} + +func (x FailureType) Enum() *FailureType { + p := new(FailureType) + *p = x + return p +} +func (x FailureType) String() string { + return proto.EnumName(FailureType_name, int32(x)) +} +func (x *FailureType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FailureType_value, data, "FailureType") + if err != nil { + return err + } + *x = FailureType(value) + return nil +} +func (FailureType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +// * +// Type of script which will be used for transaction output +// @used_in TxOutputType +type OutputScriptType int32 + +const ( + OutputScriptType_PAYTOADDRESS OutputScriptType = 0 + OutputScriptType_PAYTOSCRIPTHASH OutputScriptType = 1 + OutputScriptType_PAYTOMULTISIG OutputScriptType = 2 + OutputScriptType_PAYTOOPRETURN OutputScriptType = 3 + OutputScriptType_PAYTOWITNESS OutputScriptType = 4 + OutputScriptType_PAYTOP2SHWITNESS OutputScriptType = 5 +) + +var OutputScriptType_name = map[int32]string{ + 0: "PAYTOADDRESS", + 1: "PAYTOSCRIPTHASH", + 2: "PAYTOMULTISIG", + 3: "PAYTOOPRETURN", + 4: "PAYTOWITNESS", + 5: "PAYTOP2SHWITNESS", +} +var OutputScriptType_value = map[string]int32{ + "PAYTOADDRESS": 0, + "PAYTOSCRIPTHASH": 1, + "PAYTOMULTISIG": 2, + "PAYTOOPRETURN": 3, + "PAYTOWITNESS": 4, + "PAYTOP2SHWITNESS": 5, +} + +func (x OutputScriptType) Enum() *OutputScriptType { + p := new(OutputScriptType) + *p = x + return p +} +func (x OutputScriptType) String() string { + return proto.EnumName(OutputScriptType_name, int32(x)) +} +func (x *OutputScriptType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(OutputScriptType_value, data, "OutputScriptType") + if err != nil { + return err + } + *x = OutputScriptType(value) + return nil +} +func (OutputScriptType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +// * +// Type of script which will be used for transaction output +// @used_in TxInputType +type InputScriptType int32 + +const ( + InputScriptType_SPENDADDRESS InputScriptType = 0 + InputScriptType_SPENDMULTISIG InputScriptType = 1 + InputScriptType_EXTERNAL InputScriptType = 2 + InputScriptType_SPENDWITNESS InputScriptType = 3 + InputScriptType_SPENDP2SHWITNESS InputScriptType = 4 +) + +var InputScriptType_name = map[int32]string{ + 0: "SPENDADDRESS", + 1: "SPENDMULTISIG", + 2: "EXTERNAL", + 3: "SPENDWITNESS", + 4: "SPENDP2SHWITNESS", +} +var InputScriptType_value = map[string]int32{ + "SPENDADDRESS": 0, + "SPENDMULTISIG": 1, + "EXTERNAL": 2, + "SPENDWITNESS": 3, + "SPENDP2SHWITNESS": 4, +} + +func (x InputScriptType) Enum() *InputScriptType { + p := new(InputScriptType) + *p = x + return p +} +func (x InputScriptType) String() string { + return proto.EnumName(InputScriptType_name, int32(x)) +} +func (x *InputScriptType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(InputScriptType_value, data, "InputScriptType") + if err != nil { + return err + } + *x = InputScriptType(value) + return nil +} +func (InputScriptType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +// * +// Type of information required by transaction signing process +// @used_in TxRequest +type RequestType int32 + +const ( + RequestType_TXINPUT RequestType = 0 + RequestType_TXOUTPUT RequestType = 1 + RequestType_TXMETA RequestType = 2 + RequestType_TXFINISHED RequestType = 3 + RequestType_TXEXTRADATA RequestType = 4 +) + +var RequestType_name = map[int32]string{ + 0: "TXINPUT", + 1: "TXOUTPUT", + 2: "TXMETA", + 3: "TXFINISHED", + 4: "TXEXTRADATA", +} +var RequestType_value = map[string]int32{ + "TXINPUT": 0, + "TXOUTPUT": 1, + "TXMETA": 2, + "TXFINISHED": 3, + "TXEXTRADATA": 4, +} + +func (x RequestType) Enum() *RequestType { + p := new(RequestType) + *p = x + return p +} +func (x RequestType) String() string { + return proto.EnumName(RequestType_name, int32(x)) +} +func (x *RequestType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(RequestType_value, data, "RequestType") + if err != nil { + return err + } + *x = RequestType(value) + return nil +} +func (RequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +// * +// Type of button request +// @used_in ButtonRequest +type ButtonRequestType int32 + +const ( + ButtonRequestType_ButtonRequest_Other ButtonRequestType = 1 + ButtonRequestType_ButtonRequest_FeeOverThreshold ButtonRequestType = 2 + ButtonRequestType_ButtonRequest_ConfirmOutput ButtonRequestType = 3 + ButtonRequestType_ButtonRequest_ResetDevice ButtonRequestType = 4 + ButtonRequestType_ButtonRequest_ConfirmWord ButtonRequestType = 5 + ButtonRequestType_ButtonRequest_WipeDevice ButtonRequestType = 6 + ButtonRequestType_ButtonRequest_ProtectCall ButtonRequestType = 7 + ButtonRequestType_ButtonRequest_SignTx ButtonRequestType = 8 + ButtonRequestType_ButtonRequest_FirmwareCheck ButtonRequestType = 9 + ButtonRequestType_ButtonRequest_Address ButtonRequestType = 10 + ButtonRequestType_ButtonRequest_PublicKey ButtonRequestType = 11 +) + +var ButtonRequestType_name = map[int32]string{ + 1: "ButtonRequest_Other", + 2: "ButtonRequest_FeeOverThreshold", + 3: "ButtonRequest_ConfirmOutput", + 4: "ButtonRequest_ResetDevice", + 5: "ButtonRequest_ConfirmWord", + 6: "ButtonRequest_WipeDevice", + 7: "ButtonRequest_ProtectCall", + 8: "ButtonRequest_SignTx", + 9: "ButtonRequest_FirmwareCheck", + 10: "ButtonRequest_Address", + 11: "ButtonRequest_PublicKey", +} +var ButtonRequestType_value = map[string]int32{ + "ButtonRequest_Other": 1, + "ButtonRequest_FeeOverThreshold": 2, + "ButtonRequest_ConfirmOutput": 3, + "ButtonRequest_ResetDevice": 4, + "ButtonRequest_ConfirmWord": 5, + "ButtonRequest_WipeDevice": 6, + "ButtonRequest_ProtectCall": 7, + "ButtonRequest_SignTx": 8, + "ButtonRequest_FirmwareCheck": 9, + "ButtonRequest_Address": 10, + "ButtonRequest_PublicKey": 11, +} + +func (x ButtonRequestType) Enum() *ButtonRequestType { + p := new(ButtonRequestType) + *p = x + return p +} +func (x ButtonRequestType) String() string { + return proto.EnumName(ButtonRequestType_name, int32(x)) +} +func (x *ButtonRequestType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(ButtonRequestType_value, data, "ButtonRequestType") + if err != nil { + return err + } + *x = ButtonRequestType(value) + return nil +} +func (ButtonRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +// * +// Type of PIN request +// @used_in PinMatrixRequest +type PinMatrixRequestType int32 + +const ( + PinMatrixRequestType_PinMatrixRequestType_Current PinMatrixRequestType = 1 + PinMatrixRequestType_PinMatrixRequestType_NewFirst PinMatrixRequestType = 2 + PinMatrixRequestType_PinMatrixRequestType_NewSecond PinMatrixRequestType = 3 +) + +var PinMatrixRequestType_name = map[int32]string{ + 1: "PinMatrixRequestType_Current", + 2: "PinMatrixRequestType_NewFirst", + 3: "PinMatrixRequestType_NewSecond", +} +var PinMatrixRequestType_value = map[string]int32{ + "PinMatrixRequestType_Current": 1, + "PinMatrixRequestType_NewFirst": 2, + "PinMatrixRequestType_NewSecond": 3, +} + +func (x PinMatrixRequestType) Enum() *PinMatrixRequestType { + p := new(PinMatrixRequestType) + *p = x + return p +} +func (x PinMatrixRequestType) String() string { + return proto.EnumName(PinMatrixRequestType_name, int32(x)) +} +func (x *PinMatrixRequestType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(PinMatrixRequestType_value, data, "PinMatrixRequestType") + if err != nil { + return err + } + *x = PinMatrixRequestType(value) + return nil +} +func (PinMatrixRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +// * +// Type of recovery procedure. These should be used as bitmask, e.g., +// `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix` +// listing every method supported by the host computer. +// +// Note that ScrambledWords must be supported by every implementation +// for backward compatibility; there is no way to not support it. +// +// @used_in RecoveryDevice +type RecoveryDeviceType int32 + +const ( + // use powers of two when extending this field + RecoveryDeviceType_RecoveryDeviceType_ScrambledWords RecoveryDeviceType = 0 + RecoveryDeviceType_RecoveryDeviceType_Matrix RecoveryDeviceType = 1 +) + +var RecoveryDeviceType_name = map[int32]string{ + 0: "RecoveryDeviceType_ScrambledWords", + 1: "RecoveryDeviceType_Matrix", +} +var RecoveryDeviceType_value = map[string]int32{ + "RecoveryDeviceType_ScrambledWords": 0, + "RecoveryDeviceType_Matrix": 1, +} + +func (x RecoveryDeviceType) Enum() *RecoveryDeviceType { + p := new(RecoveryDeviceType) + *p = x + return p +} +func (x RecoveryDeviceType) String() string { + return proto.EnumName(RecoveryDeviceType_name, int32(x)) +} +func (x *RecoveryDeviceType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(RecoveryDeviceType_value, data, "RecoveryDeviceType") + if err != nil { + return err + } + *x = RecoveryDeviceType(value) + return nil +} +func (RecoveryDeviceType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +// * +// Type of Recovery Word request +// @used_in WordRequest +type WordRequestType int32 + +const ( + WordRequestType_WordRequestType_Plain WordRequestType = 0 + WordRequestType_WordRequestType_Matrix9 WordRequestType = 1 + WordRequestType_WordRequestType_Matrix6 WordRequestType = 2 +) + +var WordRequestType_name = map[int32]string{ + 0: "WordRequestType_Plain", + 1: "WordRequestType_Matrix9", + 2: "WordRequestType_Matrix6", +} +var WordRequestType_value = map[string]int32{ + "WordRequestType_Plain": 0, + "WordRequestType_Matrix9": 1, + "WordRequestType_Matrix6": 2, +} + +func (x WordRequestType) Enum() *WordRequestType { + p := new(WordRequestType) + *p = x + return p +} +func (x WordRequestType) String() string { + return proto.EnumName(WordRequestType_name, int32(x)) +} +func (x *WordRequestType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(WordRequestType_value, data, "WordRequestType") + if err != nil { + return err + } + *x = WordRequestType(value) + return nil +} +func (WordRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +// * +// Structure representing BIP32 (hierarchical deterministic) node +// Used for imports of private key into the device and exporting public key out of device +// @used_in PublicKey +// @used_in LoadDevice +// @used_in DebugLinkState +// @used_in Storage +type HDNodeType struct { + Depth *uint32 `protobuf:"varint,1,req,name=depth" json:"depth,omitempty"` + Fingerprint *uint32 `protobuf:"varint,2,req,name=fingerprint" json:"fingerprint,omitempty"` + ChildNum *uint32 `protobuf:"varint,3,req,name=child_num,json=childNum" json:"child_num,omitempty"` + ChainCode []byte `protobuf:"bytes,4,req,name=chain_code,json=chainCode" json:"chain_code,omitempty"` + PrivateKey []byte `protobuf:"bytes,5,opt,name=private_key,json=privateKey" json:"private_key,omitempty"` + PublicKey []byte `protobuf:"bytes,6,opt,name=public_key,json=publicKey" json:"public_key,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *HDNodeType) Reset() { *m = HDNodeType{} } +func (m *HDNodeType) String() string { return proto.CompactTextString(m) } +func (*HDNodeType) ProtoMessage() {} +func (*HDNodeType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *HDNodeType) GetDepth() uint32 { + if m != nil && m.Depth != nil { + return *m.Depth + } + return 0 +} + +func (m *HDNodeType) GetFingerprint() uint32 { + if m != nil && m.Fingerprint != nil { + return *m.Fingerprint + } + return 0 +} + +func (m *HDNodeType) GetChildNum() uint32 { + if m != nil && m.ChildNum != nil { + return *m.ChildNum + } + return 0 +} + +func (m *HDNodeType) GetChainCode() []byte { + if m != nil { + return m.ChainCode + } + return nil +} + +func (m *HDNodeType) GetPrivateKey() []byte { + if m != nil { + return m.PrivateKey + } + return nil +} + +func (m *HDNodeType) GetPublicKey() []byte { + if m != nil { + return m.PublicKey + } + return nil +} + +type HDNodePathType struct { + Node *HDNodeType `protobuf:"bytes,1,req,name=node" json:"node,omitempty"` + AddressN []uint32 `protobuf:"varint,2,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *HDNodePathType) Reset() { *m = HDNodePathType{} } +func (m *HDNodePathType) String() string { return proto.CompactTextString(m) } +func (*HDNodePathType) ProtoMessage() {} +func (*HDNodePathType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *HDNodePathType) GetNode() *HDNodeType { + if m != nil { + return m.Node + } + return nil +} + +func (m *HDNodePathType) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +// * +// Structure representing Coin +// @used_in Features +type CoinType struct { + CoinName *string `protobuf:"bytes,1,opt,name=coin_name,json=coinName" json:"coin_name,omitempty"` + CoinShortcut *string `protobuf:"bytes,2,opt,name=coin_shortcut,json=coinShortcut" json:"coin_shortcut,omitempty"` + AddressType *uint32 `protobuf:"varint,3,opt,name=address_type,json=addressType,def=0" json:"address_type,omitempty"` + MaxfeeKb *uint64 `protobuf:"varint,4,opt,name=maxfee_kb,json=maxfeeKb" json:"maxfee_kb,omitempty"` + AddressTypeP2Sh *uint32 `protobuf:"varint,5,opt,name=address_type_p2sh,json=addressTypeP2sh,def=5" json:"address_type_p2sh,omitempty"` + SignedMessageHeader *string `protobuf:"bytes,8,opt,name=signed_message_header,json=signedMessageHeader" json:"signed_message_header,omitempty"` + XpubMagic *uint32 `protobuf:"varint,9,opt,name=xpub_magic,json=xpubMagic,def=76067358" json:"xpub_magic,omitempty"` + XprvMagic *uint32 `protobuf:"varint,10,opt,name=xprv_magic,json=xprvMagic,def=76066276" json:"xprv_magic,omitempty"` + Segwit *bool `protobuf:"varint,11,opt,name=segwit" json:"segwit,omitempty"` + Forkid *uint32 `protobuf:"varint,12,opt,name=forkid" json:"forkid,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *CoinType) Reset() { *m = CoinType{} } +func (m *CoinType) String() string { return proto.CompactTextString(m) } +func (*CoinType) ProtoMessage() {} +func (*CoinType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +const Default_CoinType_AddressType uint32 = 0 +const Default_CoinType_AddressTypeP2Sh uint32 = 5 +const Default_CoinType_XpubMagic uint32 = 76067358 +const Default_CoinType_XprvMagic uint32 = 76066276 + +func (m *CoinType) GetCoinName() string { + if m != nil && m.CoinName != nil { + return *m.CoinName + } + return "" +} + +func (m *CoinType) GetCoinShortcut() string { + if m != nil && m.CoinShortcut != nil { + return *m.CoinShortcut + } + return "" +} + +func (m *CoinType) GetAddressType() uint32 { + if m != nil && m.AddressType != nil { + return *m.AddressType + } + return Default_CoinType_AddressType +} + +func (m *CoinType) GetMaxfeeKb() uint64 { + if m != nil && m.MaxfeeKb != nil { + return *m.MaxfeeKb + } + return 0 +} + +func (m *CoinType) GetAddressTypeP2Sh() uint32 { + if m != nil && m.AddressTypeP2Sh != nil { + return *m.AddressTypeP2Sh + } + return Default_CoinType_AddressTypeP2Sh +} + +func (m *CoinType) GetSignedMessageHeader() string { + if m != nil && m.SignedMessageHeader != nil { + return *m.SignedMessageHeader + } + return "" +} + +func (m *CoinType) GetXpubMagic() uint32 { + if m != nil && m.XpubMagic != nil { + return *m.XpubMagic + } + return Default_CoinType_XpubMagic +} + +func (m *CoinType) GetXprvMagic() uint32 { + if m != nil && m.XprvMagic != nil { + return *m.XprvMagic + } + return Default_CoinType_XprvMagic +} + +func (m *CoinType) GetSegwit() bool { + if m != nil && m.Segwit != nil { + return *m.Segwit + } + return false +} + +func (m *CoinType) GetForkid() uint32 { + if m != nil && m.Forkid != nil { + return *m.Forkid + } + return 0 +} + +// * +// Type of redeem script used in input +// @used_in TxInputType +type MultisigRedeemScriptType struct { + Pubkeys []*HDNodePathType `protobuf:"bytes,1,rep,name=pubkeys" json:"pubkeys,omitempty"` + Signatures [][]byte `protobuf:"bytes,2,rep,name=signatures" json:"signatures,omitempty"` + M *uint32 `protobuf:"varint,3,opt,name=m" json:"m,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MultisigRedeemScriptType) Reset() { *m = MultisigRedeemScriptType{} } +func (m *MultisigRedeemScriptType) String() string { return proto.CompactTextString(m) } +func (*MultisigRedeemScriptType) ProtoMessage() {} +func (*MultisigRedeemScriptType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *MultisigRedeemScriptType) GetPubkeys() []*HDNodePathType { + if m != nil { + return m.Pubkeys + } + return nil +} + +func (m *MultisigRedeemScriptType) GetSignatures() [][]byte { + if m != nil { + return m.Signatures + } + return nil +} + +func (m *MultisigRedeemScriptType) GetM() uint32 { + if m != nil && m.M != nil { + return *m.M + } + return 0 +} + +// * +// Structure representing transaction input +// @used_in SimpleSignTx +// @used_in TransactionType +type TxInputType struct { + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + PrevHash []byte `protobuf:"bytes,2,req,name=prev_hash,json=prevHash" json:"prev_hash,omitempty"` + PrevIndex *uint32 `protobuf:"varint,3,req,name=prev_index,json=prevIndex" json:"prev_index,omitempty"` + ScriptSig []byte `protobuf:"bytes,4,opt,name=script_sig,json=scriptSig" json:"script_sig,omitempty"` + Sequence *uint32 `protobuf:"varint,5,opt,name=sequence,def=4294967295" json:"sequence,omitempty"` + ScriptType *InputScriptType `protobuf:"varint,6,opt,name=script_type,json=scriptType,enum=InputScriptType,def=0" json:"script_type,omitempty"` + Multisig *MultisigRedeemScriptType `protobuf:"bytes,7,opt,name=multisig" json:"multisig,omitempty"` + Amount *uint64 `protobuf:"varint,8,opt,name=amount" json:"amount,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TxInputType) Reset() { *m = TxInputType{} } +func (m *TxInputType) String() string { return proto.CompactTextString(m) } +func (*TxInputType) ProtoMessage() {} +func (*TxInputType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +const Default_TxInputType_Sequence uint32 = 4294967295 +const Default_TxInputType_ScriptType InputScriptType = InputScriptType_SPENDADDRESS + +func (m *TxInputType) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *TxInputType) GetPrevHash() []byte { + if m != nil { + return m.PrevHash + } + return nil +} + +func (m *TxInputType) GetPrevIndex() uint32 { + if m != nil && m.PrevIndex != nil { + return *m.PrevIndex + } + return 0 +} + +func (m *TxInputType) GetScriptSig() []byte { + if m != nil { + return m.ScriptSig + } + return nil +} + +func (m *TxInputType) GetSequence() uint32 { + if m != nil && m.Sequence != nil { + return *m.Sequence + } + return Default_TxInputType_Sequence +} + +func (m *TxInputType) GetScriptType() InputScriptType { + if m != nil && m.ScriptType != nil { + return *m.ScriptType + } + return Default_TxInputType_ScriptType +} + +func (m *TxInputType) GetMultisig() *MultisigRedeemScriptType { + if m != nil { + return m.Multisig + } + return nil +} + +func (m *TxInputType) GetAmount() uint64 { + if m != nil && m.Amount != nil { + return *m.Amount + } + return 0 +} + +// * +// Structure representing transaction output +// @used_in SimpleSignTx +// @used_in TransactionType +type TxOutputType struct { + Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + AddressN []uint32 `protobuf:"varint,2,rep,name=address_n,json=addressN" json:"address_n,omitempty"` + Amount *uint64 `protobuf:"varint,3,req,name=amount" json:"amount,omitempty"` + ScriptType *OutputScriptType `protobuf:"varint,4,req,name=script_type,json=scriptType,enum=OutputScriptType" json:"script_type,omitempty"` + Multisig *MultisigRedeemScriptType `protobuf:"bytes,5,opt,name=multisig" json:"multisig,omitempty"` + OpReturnData []byte `protobuf:"bytes,6,opt,name=op_return_data,json=opReturnData" json:"op_return_data,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TxOutputType) Reset() { *m = TxOutputType{} } +func (m *TxOutputType) String() string { return proto.CompactTextString(m) } +func (*TxOutputType) ProtoMessage() {} +func (*TxOutputType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *TxOutputType) GetAddress() string { + if m != nil && m.Address != nil { + return *m.Address + } + return "" +} + +func (m *TxOutputType) GetAddressN() []uint32 { + if m != nil { + return m.AddressN + } + return nil +} + +func (m *TxOutputType) GetAmount() uint64 { + if m != nil && m.Amount != nil { + return *m.Amount + } + return 0 +} + +func (m *TxOutputType) GetScriptType() OutputScriptType { + if m != nil && m.ScriptType != nil { + return *m.ScriptType + } + return OutputScriptType_PAYTOADDRESS +} + +func (m *TxOutputType) GetMultisig() *MultisigRedeemScriptType { + if m != nil { + return m.Multisig + } + return nil +} + +func (m *TxOutputType) GetOpReturnData() []byte { + if m != nil { + return m.OpReturnData + } + return nil +} + +// * +// Structure representing compiled transaction output +// @used_in TransactionType +type TxOutputBinType struct { + Amount *uint64 `protobuf:"varint,1,req,name=amount" json:"amount,omitempty"` + ScriptPubkey []byte `protobuf:"bytes,2,req,name=script_pubkey,json=scriptPubkey" json:"script_pubkey,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TxOutputBinType) Reset() { *m = TxOutputBinType{} } +func (m *TxOutputBinType) String() string { return proto.CompactTextString(m) } +func (*TxOutputBinType) ProtoMessage() {} +func (*TxOutputBinType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *TxOutputBinType) GetAmount() uint64 { + if m != nil && m.Amount != nil { + return *m.Amount + } + return 0 +} + +func (m *TxOutputBinType) GetScriptPubkey() []byte { + if m != nil { + return m.ScriptPubkey + } + return nil +} + +// * +// Structure representing transaction +// @used_in SimpleSignTx +type TransactionType struct { + Version *uint32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` + Inputs []*TxInputType `protobuf:"bytes,2,rep,name=inputs" json:"inputs,omitempty"` + BinOutputs []*TxOutputBinType `protobuf:"bytes,3,rep,name=bin_outputs,json=binOutputs" json:"bin_outputs,omitempty"` + Outputs []*TxOutputType `protobuf:"bytes,5,rep,name=outputs" json:"outputs,omitempty"` + LockTime *uint32 `protobuf:"varint,4,opt,name=lock_time,json=lockTime" json:"lock_time,omitempty"` + InputsCnt *uint32 `protobuf:"varint,6,opt,name=inputs_cnt,json=inputsCnt" json:"inputs_cnt,omitempty"` + OutputsCnt *uint32 `protobuf:"varint,7,opt,name=outputs_cnt,json=outputsCnt" json:"outputs_cnt,omitempty"` + ExtraData []byte `protobuf:"bytes,8,opt,name=extra_data,json=extraData" json:"extra_data,omitempty"` + ExtraDataLen *uint32 `protobuf:"varint,9,opt,name=extra_data_len,json=extraDataLen" json:"extra_data_len,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TransactionType) Reset() { *m = TransactionType{} } +func (m *TransactionType) String() string { return proto.CompactTextString(m) } +func (*TransactionType) ProtoMessage() {} +func (*TransactionType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *TransactionType) GetVersion() uint32 { + if m != nil && m.Version != nil { + return *m.Version + } + return 0 +} + +func (m *TransactionType) GetInputs() []*TxInputType { + if m != nil { + return m.Inputs + } + return nil +} + +func (m *TransactionType) GetBinOutputs() []*TxOutputBinType { + if m != nil { + return m.BinOutputs + } + return nil +} + +func (m *TransactionType) GetOutputs() []*TxOutputType { + if m != nil { + return m.Outputs + } + return nil +} + +func (m *TransactionType) GetLockTime() uint32 { + if m != nil && m.LockTime != nil { + return *m.LockTime + } + return 0 +} + +func (m *TransactionType) GetInputsCnt() uint32 { + if m != nil && m.InputsCnt != nil { + return *m.InputsCnt + } + return 0 +} + +func (m *TransactionType) GetOutputsCnt() uint32 { + if m != nil && m.OutputsCnt != nil { + return *m.OutputsCnt + } + return 0 +} + +func (m *TransactionType) GetExtraData() []byte { + if m != nil { + return m.ExtraData + } + return nil +} + +func (m *TransactionType) GetExtraDataLen() uint32 { + if m != nil && m.ExtraDataLen != nil { + return *m.ExtraDataLen + } + return 0 +} + +// * +// Structure representing request details +// @used_in TxRequest +type TxRequestDetailsType struct { + RequestIndex *uint32 `protobuf:"varint,1,opt,name=request_index,json=requestIndex" json:"request_index,omitempty"` + TxHash []byte `protobuf:"bytes,2,opt,name=tx_hash,json=txHash" json:"tx_hash,omitempty"` + ExtraDataLen *uint32 `protobuf:"varint,3,opt,name=extra_data_len,json=extraDataLen" json:"extra_data_len,omitempty"` + ExtraDataOffset *uint32 `protobuf:"varint,4,opt,name=extra_data_offset,json=extraDataOffset" json:"extra_data_offset,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TxRequestDetailsType) Reset() { *m = TxRequestDetailsType{} } +func (m *TxRequestDetailsType) String() string { return proto.CompactTextString(m) } +func (*TxRequestDetailsType) ProtoMessage() {} +func (*TxRequestDetailsType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *TxRequestDetailsType) GetRequestIndex() uint32 { + if m != nil && m.RequestIndex != nil { + return *m.RequestIndex + } + return 0 +} + +func (m *TxRequestDetailsType) GetTxHash() []byte { + if m != nil { + return m.TxHash + } + return nil +} + +func (m *TxRequestDetailsType) GetExtraDataLen() uint32 { + if m != nil && m.ExtraDataLen != nil { + return *m.ExtraDataLen + } + return 0 +} + +func (m *TxRequestDetailsType) GetExtraDataOffset() uint32 { + if m != nil && m.ExtraDataOffset != nil { + return *m.ExtraDataOffset + } + return 0 +} + +// * +// Structure representing serialized data +// @used_in TxRequest +type TxRequestSerializedType struct { + SignatureIndex *uint32 `protobuf:"varint,1,opt,name=signature_index,json=signatureIndex" json:"signature_index,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + SerializedTx []byte `protobuf:"bytes,3,opt,name=serialized_tx,json=serializedTx" json:"serialized_tx,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *TxRequestSerializedType) Reset() { *m = TxRequestSerializedType{} } +func (m *TxRequestSerializedType) String() string { return proto.CompactTextString(m) } +func (*TxRequestSerializedType) ProtoMessage() {} +func (*TxRequestSerializedType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +func (m *TxRequestSerializedType) GetSignatureIndex() uint32 { + if m != nil && m.SignatureIndex != nil { + return *m.SignatureIndex + } + return 0 +} + +func (m *TxRequestSerializedType) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func (m *TxRequestSerializedType) GetSerializedTx() []byte { + if m != nil { + return m.SerializedTx + } + return nil +} + +// * +// Structure representing identity data +// @used_in IdentityType +type IdentityType struct { + Proto *string `protobuf:"bytes,1,opt,name=proto" json:"proto,omitempty"` + User *string `protobuf:"bytes,2,opt,name=user" json:"user,omitempty"` + Host *string `protobuf:"bytes,3,opt,name=host" json:"host,omitempty"` + Port *string `protobuf:"bytes,4,opt,name=port" json:"port,omitempty"` + Path *string `protobuf:"bytes,5,opt,name=path" json:"path,omitempty"` + Index *uint32 `protobuf:"varint,6,opt,name=index,def=0" json:"index,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *IdentityType) Reset() { *m = IdentityType{} } +func (m *IdentityType) String() string { return proto.CompactTextString(m) } +func (*IdentityType) ProtoMessage() {} +func (*IdentityType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +const Default_IdentityType_Index uint32 = 0 + +func (m *IdentityType) GetProto() string { + if m != nil && m.Proto != nil { + return *m.Proto + } + return "" +} + +func (m *IdentityType) GetUser() string { + if m != nil && m.User != nil { + return *m.User + } + return "" +} + +func (m *IdentityType) GetHost() string { + if m != nil && m.Host != nil { + return *m.Host + } + return "" +} + +func (m *IdentityType) GetPort() string { + if m != nil && m.Port != nil { + return *m.Port + } + return "" +} + +func (m *IdentityType) GetPath() string { + if m != nil && m.Path != nil { + return *m.Path + } + return "" +} + +func (m *IdentityType) GetIndex() uint32 { + if m != nil && m.Index != nil { + return *m.Index + } + return Default_IdentityType_Index +} + +var E_WireIn = &proto.ExtensionDesc{ + ExtendedType: (*google_protobuf.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50002, + Name: "wire_in", + Tag: "varint,50002,opt,name=wire_in,json=wireIn", + Filename: "types.proto", +} + +var E_WireOut = &proto.ExtensionDesc{ + ExtendedType: (*google_protobuf.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50003, + Name: "wire_out", + Tag: "varint,50003,opt,name=wire_out,json=wireOut", + Filename: "types.proto", +} + +var E_WireDebugIn = &proto.ExtensionDesc{ + ExtendedType: (*google_protobuf.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50004, + Name: "wire_debug_in", + Tag: "varint,50004,opt,name=wire_debug_in,json=wireDebugIn", + Filename: "types.proto", +} + +var E_WireDebugOut = &proto.ExtensionDesc{ + ExtendedType: (*google_protobuf.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50005, + Name: "wire_debug_out", + Tag: "varint,50005,opt,name=wire_debug_out,json=wireDebugOut", + Filename: "types.proto", +} + +var E_WireTiny = &proto.ExtensionDesc{ + ExtendedType: (*google_protobuf.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50006, + Name: "wire_tiny", + Tag: "varint,50006,opt,name=wire_tiny,json=wireTiny", + Filename: "types.proto", +} + +var E_WireBootloader = &proto.ExtensionDesc{ + ExtendedType: (*google_protobuf.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50007, + Name: "wire_bootloader", + Tag: "varint,50007,opt,name=wire_bootloader,json=wireBootloader", + Filename: "types.proto", +} + +func init() { + proto.RegisterType((*HDNodeType)(nil), "HDNodeType") + proto.RegisterType((*HDNodePathType)(nil), "HDNodePathType") + proto.RegisterType((*CoinType)(nil), "CoinType") + proto.RegisterType((*MultisigRedeemScriptType)(nil), "MultisigRedeemScriptType") + proto.RegisterType((*TxInputType)(nil), "TxInputType") + proto.RegisterType((*TxOutputType)(nil), "TxOutputType") + proto.RegisterType((*TxOutputBinType)(nil), "TxOutputBinType") + proto.RegisterType((*TransactionType)(nil), "TransactionType") + proto.RegisterType((*TxRequestDetailsType)(nil), "TxRequestDetailsType") + proto.RegisterType((*TxRequestSerializedType)(nil), "TxRequestSerializedType") + proto.RegisterType((*IdentityType)(nil), "IdentityType") + proto.RegisterEnum("FailureType", FailureType_name, FailureType_value) + proto.RegisterEnum("OutputScriptType", OutputScriptType_name, OutputScriptType_value) + proto.RegisterEnum("InputScriptType", InputScriptType_name, InputScriptType_value) + proto.RegisterEnum("RequestType", RequestType_name, RequestType_value) + proto.RegisterEnum("ButtonRequestType", ButtonRequestType_name, ButtonRequestType_value) + proto.RegisterEnum("PinMatrixRequestType", PinMatrixRequestType_name, PinMatrixRequestType_value) + proto.RegisterEnum("RecoveryDeviceType", RecoveryDeviceType_name, RecoveryDeviceType_value) + proto.RegisterEnum("WordRequestType", WordRequestType_name, WordRequestType_value) + proto.RegisterExtension(E_WireIn) + proto.RegisterExtension(E_WireOut) + proto.RegisterExtension(E_WireDebugIn) + proto.RegisterExtension(E_WireDebugOut) + proto.RegisterExtension(E_WireTiny) + proto.RegisterExtension(E_WireBootloader) +} + +func init() { proto.RegisterFile("types.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 1899 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xdb, 0x72, 0x1a, 0xc9, + 0x19, 0xf6, 0x00, 0x92, 0xe0, 0x07, 0xc4, 0xa8, 0x7d, 0xd0, 0x78, 0x6d, 0xaf, 0x31, 0x76, 0x62, + 0x45, 0x55, 0x61, 0x77, 0xc9, 0x5a, 0x8e, 0x55, 0xa9, 0x24, 0x3a, 0xa0, 0x15, 0x65, 0x0b, 0x51, + 0xc3, 0x28, 0x56, 0x72, 0x33, 0x35, 0xcc, 0xb4, 0xa0, 0x4b, 0x43, 0x37, 0xe9, 0xe9, 0x91, 0xd1, + 0xde, 0xe4, 0x2a, 0xc9, 0x55, 0x5e, 0x23, 0x6f, 0x91, 0xaa, 0xbc, 0x41, 0xaa, 0x36, 0xa7, 0xcb, + 0xbc, 0x41, 0xae, 0xf2, 0x00, 0xa9, 0x3e, 0x0c, 0x02, 0xc9, 0xde, 0xd2, 0x1d, 0xfd, 0x7d, 0xff, + 0xf9, 0xd0, 0x3d, 0x40, 0x59, 0x5c, 0x4e, 0x70, 0xd2, 0x9c, 0x70, 0x26, 0xd8, 0x67, 0xf5, 0x21, + 0x63, 0xc3, 0x18, 0x7f, 0xa1, 0x4e, 0x83, 0xf4, 0xec, 0x8b, 0x08, 0x27, 0x21, 0x27, 0x13, 0xc1, + 0xb8, 0x96, 0x68, 0xfc, 0xd5, 0x02, 0x38, 0xdc, 0xef, 0xb2, 0x08, 0x7b, 0x97, 0x13, 0x8c, 0xee, + 0xc1, 0x52, 0x84, 0x27, 0x62, 0xe4, 0x58, 0xf5, 0xdc, 0x46, 0xd5, 0xd5, 0x07, 0x54, 0x87, 0xf2, + 0x19, 0xa1, 0x43, 0xcc, 0x27, 0x9c, 0x50, 0xe1, 0xe4, 0x14, 0x37, 0x0f, 0xa1, 0x47, 0x50, 0x0a, + 0x47, 0x24, 0x8e, 0x7c, 0x9a, 0x8e, 0x9d, 0xbc, 0xe2, 0x8b, 0x0a, 0xe8, 0xa6, 0x63, 0xf4, 0x04, + 0x20, 0x1c, 0x05, 0x84, 0xfa, 0x21, 0x8b, 0xb0, 0x53, 0xa8, 0xe7, 0x36, 0x2a, 0x6e, 0x49, 0x21, + 0x7b, 0x2c, 0xc2, 0xe8, 0x29, 0x94, 0x27, 0x9c, 0x5c, 0x04, 0x02, 0xfb, 0xe7, 0xf8, 0xd2, 0x59, + 0xaa, 0x5b, 0x1b, 0x15, 0x17, 0x0c, 0xf4, 0x16, 0x5f, 0x4a, 0xfd, 0x49, 0x3a, 0x88, 0x49, 0xa8, + 0xf8, 0x65, 0xc5, 0x97, 0x34, 0xf2, 0x16, 0x5f, 0x36, 0xba, 0xb0, 0xaa, 0x33, 0xe8, 0x05, 0x62, + 0xa4, 0xb2, 0x78, 0x0a, 0x05, 0x2a, 0x5d, 0xc9, 0x24, 0xca, 0xad, 0x72, 0xf3, 0x2a, 0x41, 0x57, + 0x11, 0x32, 0xdc, 0x20, 0x8a, 0x38, 0x4e, 0x12, 0x9f, 0x3a, 0xb9, 0x7a, 0x5e, 0x86, 0x6b, 0x80, + 0x6e, 0xe3, 0x7f, 0x39, 0x28, 0xee, 0x31, 0x42, 0x95, 0x29, 0x99, 0x18, 0x23, 0xd4, 0xa7, 0xc1, + 0x58, 0xda, 0xb3, 0x36, 0x4a, 0x6e, 0x51, 0x02, 0xdd, 0x60, 0x8c, 0xd1, 0x73, 0xa8, 0x2a, 0x32, + 0x19, 0x31, 0x2e, 0xc2, 0x54, 0x56, 0x46, 0x0a, 0x54, 0x24, 0xd8, 0x37, 0x18, 0x7a, 0x01, 0x95, + 0xcc, 0x97, 0x6c, 0x8d, 0x93, 0xaf, 0x5b, 0x1b, 0xd5, 0x6d, 0xeb, 0x4b, 0xb7, 0x6c, 0xe0, 0xcc, + 0xcf, 0x38, 0x98, 0x9e, 0x61, 0xec, 0x9f, 0x0f, 0x9c, 0x42, 0xdd, 0xda, 0x28, 0xb8, 0x45, 0x0d, + 0xbc, 0x1d, 0xa0, 0x1f, 0xc3, 0xda, 0xbc, 0x09, 0x7f, 0xd2, 0x4a, 0x46, 0xaa, 0x4e, 0xd5, 0x6d, + 0xeb, 0x95, 0x5b, 0x9b, 0xb3, 0xd3, 0x6b, 0x25, 0x23, 0xd4, 0x82, 0xfb, 0x09, 0x19, 0x52, 0x1c, + 0xf9, 0x63, 0x9c, 0x24, 0xc1, 0x10, 0xfb, 0x23, 0x1c, 0x44, 0x98, 0x3b, 0x45, 0x15, 0xde, 0x5d, + 0x4d, 0x1e, 0x69, 0xee, 0x50, 0x51, 0xe8, 0x25, 0xc0, 0x74, 0x92, 0x0e, 0xfc, 0x71, 0x30, 0x24, + 0xa1, 0x53, 0x52, 0xb6, 0x8b, 0xaf, 0xb7, 0xbe, 0xdc, 0x7a, 0xfd, 0x93, 0x57, 0x3f, 0x75, 0x4b, + 0x92, 0x3b, 0x92, 0x94, 0x16, 0xe4, 0x17, 0x46, 0x10, 0xae, 0x04, 0xb7, 0x5a, 0xaf, 0xb7, 0xa4, + 0x20, 0xbf, 0xd0, 0x82, 0x0f, 0x60, 0x39, 0xc1, 0xc3, 0x0f, 0x44, 0x38, 0xe5, 0xba, 0xb5, 0x51, + 0x74, 0xcd, 0x49, 0xe2, 0x67, 0x8c, 0x9f, 0x93, 0xc8, 0xa9, 0x48, 0x65, 0xd7, 0x9c, 0x1a, 0x09, + 0x38, 0x47, 0x69, 0x2c, 0x48, 0x42, 0x86, 0x2e, 0x8e, 0x30, 0x1e, 0xf7, 0xd5, 0xa4, 0xaa, 0xea, + 0xfc, 0x08, 0x56, 0x26, 0xe9, 0xe0, 0x1c, 0x5f, 0x26, 0x8e, 0x55, 0xcf, 0x6f, 0x94, 0x5b, 0xb5, + 0xe6, 0x62, 0xcb, 0xdd, 0x8c, 0x47, 0x9f, 0x03, 0xc8, 0xfc, 0x02, 0x91, 0x72, 0x9c, 0xa8, 0xde, + 0x56, 0xdc, 0x39, 0x04, 0x55, 0xc0, 0x1a, 0xeb, 0x1e, 0xb8, 0xd6, 0xb8, 0xf1, 0x97, 0x1c, 0x94, + 0xbd, 0x69, 0x87, 0x4e, 0x52, 0x91, 0xb5, 0xe1, 0x6a, 0x30, 0xac, 0xc5, 0xc1, 0x90, 0xe4, 0x84, + 0xe3, 0x0b, 0x7f, 0x14, 0x24, 0x23, 0xb5, 0x04, 0x15, 0xb7, 0x28, 0x81, 0xc3, 0x20, 0x19, 0xa9, + 0x21, 0x95, 0x24, 0xa1, 0x11, 0x9e, 0x9a, 0x15, 0x50, 0xe2, 0x1d, 0x09, 0x48, 0x5a, 0x6f, 0x9e, + 0x9f, 0x90, 0xa1, 0x6a, 0x70, 0xc5, 0x2d, 0x69, 0xa4, 0x4f, 0x86, 0xe8, 0x87, 0x50, 0x4c, 0xf0, + 0x6f, 0x53, 0x4c, 0x43, 0x6c, 0x1a, 0x0b, 0x5f, 0xb7, 0xde, 0x7c, 0xfd, 0x66, 0xeb, 0x75, 0xeb, + 0xcd, 0x2b, 0x77, 0xc6, 0xa1, 0x5f, 0x40, 0xd9, 0x98, 0x51, 0xb3, 0x24, 0x77, 0x61, 0xb5, 0x65, + 0x37, 0x55, 0x02, 0x57, 0xf5, 0xda, 0xae, 0xf4, 0x7b, 0xed, 0xee, 0xfe, 0xce, 0xfe, 0xbe, 0xdb, + 0xee, 0xf7, 0x5d, 0xe3, 0x59, 0x25, 0xf8, 0x0a, 0x8a, 0x63, 0x53, 0x65, 0x67, 0xa5, 0x6e, 0x6d, + 0x94, 0x5b, 0x0f, 0x9b, 0x9f, 0x2a, 0xbb, 0x3b, 0x13, 0x95, 0x4d, 0x0b, 0xc6, 0x2c, 0xa5, 0x42, + 0xcd, 0x50, 0xc1, 0x35, 0xa7, 0xc6, 0x7f, 0x2d, 0xa8, 0x78, 0xd3, 0xe3, 0x54, 0x64, 0x05, 0x74, + 0x60, 0xc5, 0xd4, 0xcb, 0x6c, 0x4b, 0x76, 0xfc, 0xde, 0x9d, 0x9b, 0xb3, 0x2f, 0x2b, 0x37, 0xb3, + 0x8f, 0x5a, 0x8b, 0xf9, 0xca, 0xbb, 0x63, 0xb5, 0xb5, 0xd6, 0xd4, 0x0e, 0xe7, 0x22, 0xfd, 0x54, + 0x8a, 0x4b, 0xb7, 0x4f, 0xf1, 0x05, 0xac, 0xb2, 0x89, 0xcf, 0xb1, 0x48, 0x39, 0xf5, 0xa3, 0x40, + 0x04, 0xe6, 0xa6, 0xa9, 0xb0, 0x89, 0xab, 0xc0, 0xfd, 0x40, 0x04, 0x8d, 0x2e, 0xd4, 0xb2, 0x7c, + 0x77, 0xcd, 0x15, 0x71, 0x15, 0xbb, 0xb5, 0x10, 0xfb, 0x73, 0xa8, 0x9a, 0xd8, 0xf5, 0x6c, 0x9a, + 0x91, 0xa9, 0x68, 0xb0, 0xa7, 0xb0, 0xc6, 0xdf, 0x72, 0x50, 0xf3, 0x78, 0x40, 0x93, 0x20, 0x14, + 0x84, 0xd1, 0xac, 0x86, 0x17, 0x98, 0x27, 0x84, 0x51, 0x55, 0xc3, 0xaa, 0x9b, 0x1d, 0xd1, 0x0b, + 0x58, 0x26, 0xb2, 0xd5, 0x7a, 0xb0, 0xcb, 0xad, 0x4a, 0x73, 0x6e, 0x78, 0x5d, 0xc3, 0xa1, 0xaf, + 0xa0, 0x3c, 0x20, 0xd4, 0x67, 0x2a, 0xca, 0xc4, 0xc9, 0x2b, 0x51, 0xbb, 0x79, 0x2d, 0x6e, 0x17, + 0x06, 0x84, 0x6a, 0x24, 0x41, 0x2f, 0x61, 0x25, 0x13, 0x5f, 0x52, 0xe2, 0xd5, 0xe6, 0x7c, 0x5b, + 0xdd, 0x8c, 0x95, 0x5d, 0x8c, 0x59, 0x78, 0xee, 0x0b, 0x32, 0xc6, 0x6a, 0x8c, 0xab, 0x6e, 0x51, + 0x02, 0x1e, 0x19, 0x63, 0x39, 0xe4, 0x3a, 0x04, 0x3f, 0xa4, 0x42, 0x95, 0xaf, 0xea, 0x96, 0x34, + 0xb2, 0x47, 0x85, 0xbc, 0xe8, 0x8d, 0x19, 0xc5, 0xaf, 0x28, 0x1e, 0x0c, 0x24, 0x05, 0x9e, 0x00, + 0xe0, 0xa9, 0xe0, 0x81, 0x2e, 0x7f, 0x51, 0x2f, 0x89, 0x42, 0x64, 0xed, 0x65, 0x87, 0xae, 0x68, + 0x3f, 0xc6, 0x54, 0xdf, 0x53, 0x6e, 0x65, 0x26, 0xf2, 0x0e, 0xd3, 0xc6, 0x9f, 0x2d, 0xb8, 0xe7, + 0x4d, 0x5d, 0xb9, 0x31, 0x89, 0xd8, 0xc7, 0x22, 0x20, 0xb1, 0xbe, 0x62, 0x9f, 0x43, 0x95, 0x6b, + 0xd4, 0x2c, 0xa9, 0x2e, 0x6e, 0xc5, 0x80, 0x7a, 0x4f, 0xd7, 0x61, 0x45, 0x4c, 0xb3, 0x0d, 0x97, + 0xfe, 0x97, 0xc5, 0x54, 0xed, 0xf7, 0x4d, 0xe7, 0xf9, 0x9b, 0xce, 0xd1, 0x26, 0xac, 0xcd, 0x49, + 0xb1, 0xb3, 0xb3, 0x04, 0x0b, 0x53, 0xa6, 0xda, 0x4c, 0xf0, 0x58, 0xc1, 0x8d, 0xdf, 0x5b, 0xb0, + 0x3e, 0x0b, 0xb4, 0x8f, 0x39, 0x09, 0x62, 0xf2, 0x2d, 0x8e, 0x54, 0xac, 0x2f, 0xa1, 0x36, 0xbb, + 0xb3, 0x16, 0xa2, 0x5d, 0x9d, 0xc1, 0x3a, 0xde, 0xc7, 0x50, 0x9a, 0x21, 0x26, 0xe2, 0x2b, 0x40, + 0x8d, 0xe0, 0xcc, 0xb0, 0x2f, 0xa6, 0x2a, 0x66, 0x39, 0x82, 0x57, 0xde, 0xa6, 0x8d, 0x3f, 0x59, + 0x50, 0xe9, 0x44, 0x98, 0x0a, 0x22, 0x2e, 0xb3, 0x8f, 0x00, 0xf5, 0x71, 0x60, 0x36, 0x58, 0x1f, + 0x10, 0x82, 0x42, 0x9a, 0x60, 0x6e, 0xde, 0x38, 0xf5, 0x5b, 0x62, 0x23, 0x96, 0x08, 0x65, 0xb6, + 0xe4, 0xaa, 0xdf, 0x12, 0x9b, 0x30, 0xae, 0xb3, 0x2e, 0xb9, 0xea, 0xb7, 0xc2, 0x02, 0xa1, 0xdf, + 0x2c, 0x89, 0x05, 0x62, 0x84, 0xd6, 0x61, 0x49, 0x27, 0xb6, 0x9c, 0x3d, 0x88, 0xfa, 0xbc, 0xf9, + 0x5d, 0x0e, 0xca, 0x07, 0x01, 0x89, 0x53, 0xae, 0xbf, 0x49, 0x9e, 0xc0, 0x43, 0x73, 0xf4, 0x4f, + 0x28, 0x9e, 0x4e, 0x70, 0x28, 0x66, 0xaf, 0x97, 0x6d, 0xa1, 0xcf, 0xe0, 0x41, 0x46, 0xef, 0xa6, + 0x42, 0x30, 0xda, 0x36, 0x22, 0x76, 0x0e, 0xdd, 0x87, 0xb5, 0x8c, 0x93, 0x85, 0x6f, 0x73, 0xce, + 0xb8, 0x9d, 0x47, 0x8f, 0x60, 0x3d, 0x83, 0x77, 0xd4, 0xda, 0xed, 0x05, 0x34, 0xc4, 0x71, 0x8c, + 0x23, 0xbb, 0x80, 0xd6, 0xe1, 0x6e, 0x46, 0xf6, 0xc8, 0x95, 0xb1, 0x25, 0xe4, 0xc0, 0xbd, 0x39, + 0xe2, 0x4a, 0x65, 0x19, 0x3d, 0x00, 0x34, 0xc7, 0x74, 0xe8, 0x45, 0x10, 0x93, 0xc8, 0x5e, 0x41, + 0x8f, 0xc1, 0xc9, 0x70, 0x03, 0xf6, 0xb3, 0xd6, 0xd8, 0xc5, 0x05, 0x7b, 0x9c, 0x85, 0x38, 0x49, + 0x74, 0x7c, 0xa5, 0xf9, 0x94, 0xba, 0x4c, 0xb4, 0x29, 0x4b, 0x87, 0xa3, 0x83, 0x94, 0x46, 0x89, + 0x0d, 0xd7, 0xb8, 0x0e, 0x25, 0xc2, 0x74, 0xd2, 0x2e, 0xa3, 0x87, 0x70, 0x3f, 0xe3, 0x0e, 0x08, + 0x1f, 0x7f, 0x08, 0x38, 0xd6, 0x26, 0xc3, 0xcd, 0x3f, 0x5a, 0x60, 0x5f, 0xbf, 0x35, 0x91, 0x0d, + 0x95, 0xde, 0xce, 0xaf, 0xbd, 0x63, 0xf3, 0x50, 0xd8, 0x77, 0xd0, 0x5d, 0xa8, 0x29, 0xa4, 0xbf, + 0xe7, 0x76, 0x7a, 0xde, 0xe1, 0x4e, 0xff, 0xd0, 0xb6, 0xd0, 0x1a, 0x54, 0x15, 0x78, 0x74, 0xf2, + 0xce, 0xeb, 0xf4, 0x3b, 0xdf, 0xd8, 0xb9, 0x19, 0x74, 0xdc, 0x73, 0xdb, 0xde, 0x89, 0xdb, 0xb5, + 0xf3, 0x33, 0x63, 0xef, 0x3b, 0x5e, 0x57, 0x1a, 0x2b, 0xa0, 0x7b, 0x60, 0x2b, 0xa4, 0xd7, 0xea, + 0x1f, 0x66, 0xe8, 0xd2, 0x66, 0x0c, 0xb5, 0x6b, 0xcf, 0x95, 0x54, 0x9d, 0x7f, 0xb0, 0xec, 0x3b, + 0xd2, 0xbe, 0x42, 0x66, 0x2e, 0x2d, 0x54, 0x81, 0x62, 0xfb, 0xd4, 0x6b, 0xbb, 0xdd, 0x9d, 0x77, + 0x76, 0x6e, 0xa6, 0x92, 0xd9, 0xcd, 0x4b, 0x6f, 0x0a, 0x99, 0xf7, 0x56, 0xd8, 0x3c, 0x81, 0xb2, + 0xd9, 0x30, 0xe5, 0xa9, 0x0c, 0x2b, 0xde, 0x69, 0xa7, 0xdb, 0x3b, 0xf1, 0xec, 0x3b, 0xd2, 0xa2, + 0x77, 0x7a, 0x7c, 0xe2, 0xc9, 0x93, 0x85, 0x00, 0x96, 0xbd, 0xd3, 0xa3, 0xb6, 0xb7, 0x63, 0xe7, + 0xd0, 0x2a, 0x80, 0x77, 0x7a, 0xd0, 0xe9, 0x76, 0xfa, 0x87, 0xed, 0x7d, 0x3b, 0x8f, 0x6a, 0x50, + 0xf6, 0x4e, 0xdb, 0xa7, 0x9e, 0xbb, 0xb3, 0xbf, 0xe3, 0xed, 0xd8, 0x85, 0xcd, 0xff, 0xe4, 0x60, + 0x4d, 0x4f, 0xdb, 0xbc, 0xf5, 0x75, 0xb8, 0xbb, 0x00, 0xfa, 0xc7, 0x62, 0x84, 0xb9, 0x6d, 0xa1, + 0x06, 0x7c, 0xbe, 0x48, 0x1c, 0x60, 0x7c, 0x7c, 0x81, 0xb9, 0x37, 0xe2, 0x38, 0x19, 0xb1, 0x58, + 0xce, 0xea, 0x53, 0x78, 0xb4, 0x28, 0xb3, 0xc7, 0xe8, 0x19, 0xe1, 0x63, 0xdd, 0x35, 0x3b, 0x2f, + 0xf7, 0x60, 0x51, 0xc0, 0xc5, 0x09, 0x16, 0xfb, 0xf8, 0x82, 0x84, 0xd8, 0x2e, 0xdc, 0xa4, 0x8d, + 0xfe, 0x7b, 0xc6, 0xe5, 0xf4, 0x3e, 0x06, 0x67, 0x91, 0x7e, 0x4f, 0x26, 0xd8, 0x28, 0x2f, 0xdf, + 0x54, 0xee, 0x71, 0x26, 0x70, 0x28, 0xf6, 0x82, 0x38, 0xb6, 0x57, 0xe4, 0xa8, 0x2e, 0xd2, 0x72, + 0x8e, 0xbd, 0xa9, 0x5d, 0xbc, 0x19, 0x75, 0x36, 0x78, 0x7b, 0x23, 0x1c, 0x9e, 0xdb, 0x25, 0x39, + 0x93, 0x8b, 0x02, 0x3b, 0xfa, 0xcd, 0xb7, 0x41, 0xae, 0xe1, 0x35, 0xa7, 0xd9, 0x37, 0xbd, 0x5d, + 0xde, 0xfc, 0x1d, 0xdc, 0xeb, 0x11, 0x7a, 0x14, 0x08, 0x4e, 0xa6, 0xf3, 0x35, 0xae, 0xc3, 0xe3, + 0x8f, 0xe1, 0xfe, 0x5e, 0xca, 0x39, 0xa6, 0xc2, 0xb6, 0xd0, 0x33, 0x78, 0xf2, 0x51, 0x89, 0x2e, + 0xfe, 0x70, 0x40, 0x78, 0x22, 0xec, 0x9c, 0xec, 0xc7, 0xa7, 0x44, 0xfa, 0x38, 0x64, 0x34, 0xb2, + 0xf3, 0x9b, 0xbf, 0x01, 0xe4, 0xe2, 0x90, 0x5d, 0x60, 0x7e, 0xa9, 0xcb, 0xa4, 0xdc, 0xff, 0x00, + 0x9e, 0xdd, 0x44, 0xfd, 0x7e, 0xc8, 0x83, 0xf1, 0x20, 0xc6, 0x91, 0x2c, 0x76, 0x62, 0xdf, 0x91, + 0xf5, 0xfc, 0x88, 0x98, 0x76, 0x68, 0x5b, 0x9b, 0x67, 0x50, 0x93, 0x92, 0xf3, 0x79, 0x3d, 0x84, + 0xfb, 0xd7, 0x20, 0xbf, 0x17, 0x07, 0x84, 0xda, 0x77, 0x64, 0x9d, 0xae, 0x53, 0xda, 0xd2, 0x1b, + 0xdb, 0xfa, 0x34, 0xb9, 0x65, 0xe7, 0xb6, 0x7f, 0x06, 0x2b, 0x1f, 0x88, 0x7a, 0x41, 0xd0, 0xb3, + 0xa6, 0xfe, 0x2f, 0xd8, 0xcc, 0xfe, 0x0b, 0x36, 0xdb, 0x34, 0x1d, 0xff, 0x2a, 0x88, 0x53, 0x7c, + 0x3c, 0x91, 0x77, 0x60, 0xe2, 0x7c, 0xf7, 0x87, 0xbc, 0xfe, 0x52, 0x97, 0x3a, 0x1d, 0xba, 0xfd, + 0x73, 0x28, 0x2a, 0x6d, 0x96, 0x8a, 0xdb, 0xa8, 0xff, 0xdd, 0xa8, 0x2b, 0x97, 0xc7, 0xa9, 0xd8, + 0xfe, 0x06, 0xaa, 0x4a, 0x3f, 0xc2, 0x83, 0x74, 0x78, 0xcb, 0x18, 0xfe, 0x61, 0x8c, 0x94, 0xa5, + 0xe6, 0xbe, 0x54, 0xec, 0xd0, 0xed, 0x0e, 0xac, 0xce, 0x19, 0xba, 0x65, 0x38, 0xff, 0x34, 0x96, + 0x2a, 0x33, 0x4b, 0x32, 0xa6, 0x5f, 0x42, 0x49, 0x99, 0x12, 0x84, 0x5e, 0xde, 0xc6, 0xca, 0xbf, + 0x8c, 0x15, 0x55, 0x09, 0x8f, 0xd0, 0xcb, 0xed, 0x77, 0x50, 0x53, 0x16, 0x06, 0x8c, 0x89, 0x98, + 0xa9, 0x3f, 0x4f, 0xb7, 0xb0, 0xf3, 0x6f, 0x63, 0x47, 0x25, 0xb2, 0x3b, 0x53, 0xdd, 0xfd, 0x0a, + 0x9e, 0x87, 0x6c, 0xdc, 0x4c, 0x02, 0xc1, 0x92, 0x11, 0x89, 0x83, 0x41, 0xd2, 0x14, 0x1c, 0x7f, + 0xcb, 0x78, 0x33, 0x26, 0x83, 0x99, 0xbd, 0x5d, 0xf0, 0x14, 0x28, 0xdb, 0xfb, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x70, 0x88, 0xcd, 0x71, 0xe2, 0x0f, 0x00, 0x00, +} diff --git a/accounts/usbwallet/internal/trezor/types.proto b/accounts/usbwallet/internal/trezor/types.proto new file mode 100644 index 000000000..3a358a584 --- /dev/null +++ b/accounts/usbwallet/internal/trezor/types.proto @@ -0,0 +1,276 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/types.proto +// dated 28.07.2017, commit dd8ec3231fb5f7992360aff9bdfe30bb58130f4b. + +/** + * Types for TREZOR communication + * + * @author Marek Palatinus <slush@satoshilabs.com> + * @version 1.2 + */ + +// Sugar for easier handling in Java +option java_package = "com.satoshilabs.trezor.lib.protobuf"; +option java_outer_classname = "TrezorType"; + +import "google/protobuf/descriptor.proto"; + +/** + * Options for specifying message direction and type of wire (normal/debug) + */ +extend google.protobuf.EnumValueOptions { + optional bool wire_in = 50002; // message can be transmitted via wire from PC to TREZOR + optional bool wire_out = 50003; // message can be transmitted via wire from TREZOR to PC + optional bool wire_debug_in = 50004; // message can be transmitted via debug wire from PC to TREZOR + optional bool wire_debug_out = 50005; // message can be transmitted via debug wire from TREZOR to PC + optional bool wire_tiny = 50006; // message is handled by TREZOR when the USB stack is in tiny mode + optional bool wire_bootloader = 50007; // message is only handled by TREZOR Bootloader +} + +/** + * Type of failures returned by Failure message + * @used_in Failure + */ +enum FailureType { + Failure_UnexpectedMessage = 1; + Failure_ButtonExpected = 2; + Failure_DataError = 3; + Failure_ActionCancelled = 4; + Failure_PinExpected = 5; + Failure_PinCancelled = 6; + Failure_PinInvalid = 7; + Failure_InvalidSignature = 8; + Failure_ProcessError = 9; + Failure_NotEnoughFunds = 10; + Failure_NotInitialized = 11; + Failure_FirmwareError = 99; +} + +/** + * Type of script which will be used for transaction output + * @used_in TxOutputType + */ +enum OutputScriptType { + PAYTOADDRESS = 0; // used for all addresses (bitcoin, p2sh, witness) + PAYTOSCRIPTHASH = 1; // p2sh address (deprecated; use PAYTOADDRESS) + PAYTOMULTISIG = 2; // only for change output + PAYTOOPRETURN = 3; // op_return + PAYTOWITNESS = 4; // only for change output + PAYTOP2SHWITNESS = 5; // only for change output +} + +/** + * Type of script which will be used for transaction output + * @used_in TxInputType + */ +enum InputScriptType { + SPENDADDRESS = 0; // standard p2pkh address + SPENDMULTISIG = 1; // p2sh multisig address + EXTERNAL = 2; // reserved for external inputs (coinjoin) + SPENDWITNESS = 3; // native segwit + SPENDP2SHWITNESS = 4; // segwit over p2sh (backward compatible) +} + +/** + * Type of information required by transaction signing process + * @used_in TxRequest + */ +enum RequestType { + TXINPUT = 0; + TXOUTPUT = 1; + TXMETA = 2; + TXFINISHED = 3; + TXEXTRADATA = 4; +} + +/** + * Type of button request + * @used_in ButtonRequest + */ +enum ButtonRequestType { + ButtonRequest_Other = 1; + ButtonRequest_FeeOverThreshold = 2; + ButtonRequest_ConfirmOutput = 3; + ButtonRequest_ResetDevice = 4; + ButtonRequest_ConfirmWord = 5; + ButtonRequest_WipeDevice = 6; + ButtonRequest_ProtectCall = 7; + ButtonRequest_SignTx = 8; + ButtonRequest_FirmwareCheck = 9; + ButtonRequest_Address = 10; + ButtonRequest_PublicKey = 11; +} + +/** + * Type of PIN request + * @used_in PinMatrixRequest + */ +enum PinMatrixRequestType { + PinMatrixRequestType_Current = 1; + PinMatrixRequestType_NewFirst = 2; + PinMatrixRequestType_NewSecond = 3; +} + +/** + * Type of recovery procedure. These should be used as bitmask, e.g., + * `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix` + * listing every method supported by the host computer. + * + * Note that ScrambledWords must be supported by every implementation + * for backward compatibility; there is no way to not support it. + * + * @used_in RecoveryDevice + */ +enum RecoveryDeviceType { + // use powers of two when extending this field + RecoveryDeviceType_ScrambledWords = 0; // words in scrambled order + RecoveryDeviceType_Matrix = 1; // matrix recovery type +} + +/** + * Type of Recovery Word request + * @used_in WordRequest + */ +enum WordRequestType { + WordRequestType_Plain = 0; + WordRequestType_Matrix9 = 1; + WordRequestType_Matrix6 = 2; +} + +/** + * Structure representing BIP32 (hierarchical deterministic) node + * Used for imports of private key into the device and exporting public key out of device + * @used_in PublicKey + * @used_in LoadDevice + * @used_in DebugLinkState + * @used_in Storage + */ +message HDNodeType { + required uint32 depth = 1; + required uint32 fingerprint = 2; + required uint32 child_num = 3; + required bytes chain_code = 4; + optional bytes private_key = 5; + optional bytes public_key = 6; +} + +message HDNodePathType { + required HDNodeType node = 1; // BIP-32 node in deserialized form + repeated uint32 address_n = 2; // BIP-32 path to derive the key from node +} + +/** + * Structure representing Coin + * @used_in Features + */ +message CoinType { + optional string coin_name = 1; + optional string coin_shortcut = 2; + optional uint32 address_type = 3 [default=0]; + optional uint64 maxfee_kb = 4; + optional uint32 address_type_p2sh = 5 [default=5]; + optional string signed_message_header = 8; + optional uint32 xpub_magic = 9 [default=76067358]; // default=0x0488b21e + optional uint32 xprv_magic = 10 [default=76066276]; // default=0x0488ade4 + optional bool segwit = 11; + optional uint32 forkid = 12; +} + +/** + * Type of redeem script used in input + * @used_in TxInputType + */ +message MultisigRedeemScriptType { + repeated HDNodePathType pubkeys = 1; // pubkeys from multisig address (sorted lexicographically) + repeated bytes signatures = 2; // existing signatures for partially signed input + optional uint32 m = 3; // "m" from n, how many valid signatures is necessary for spending +} + +/** + * Structure representing transaction input + * @used_in SimpleSignTx + * @used_in TransactionType + */ +message TxInputType { + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + required bytes prev_hash = 2; // hash of previous transaction output to spend by this input + required uint32 prev_index = 3; // index of previous output to spend + optional bytes script_sig = 4; // script signature, unset for tx to sign + optional uint32 sequence = 5 [default=4294967295]; // sequence (default=0xffffffff) + optional InputScriptType script_type = 6 [default=SPENDADDRESS]; // defines template of input script + optional MultisigRedeemScriptType multisig = 7; // Filled if input is going to spend multisig tx + optional uint64 amount = 8; // amount of previous transaction output (for segwit only) +} + +/** + * Structure representing transaction output + * @used_in SimpleSignTx + * @used_in TransactionType + */ +message TxOutputType { + optional string address = 1; // target coin address in Base58 encoding + repeated uint32 address_n = 2; // BIP-32 path to derive the key from master node; has higher priority than "address" + required uint64 amount = 3; // amount to spend in satoshis + required OutputScriptType script_type = 4; // output script type + optional MultisigRedeemScriptType multisig = 5; // defines multisig address; script_type must be PAYTOMULTISIG + optional bytes op_return_data = 6; // defines op_return data; script_type must be PAYTOOPRETURN, amount must be 0 +} + +/** + * Structure representing compiled transaction output + * @used_in TransactionType + */ +message TxOutputBinType { + required uint64 amount = 1; + required bytes script_pubkey = 2; +} + +/** + * Structure representing transaction + * @used_in SimpleSignTx + */ +message TransactionType { + optional uint32 version = 1; + repeated TxInputType inputs = 2; + repeated TxOutputBinType bin_outputs = 3; + repeated TxOutputType outputs = 5; + optional uint32 lock_time = 4; + optional uint32 inputs_cnt = 6; + optional uint32 outputs_cnt = 7; + optional bytes extra_data = 8; + optional uint32 extra_data_len = 9; +} + +/** + * Structure representing request details + * @used_in TxRequest + */ +message TxRequestDetailsType { + optional uint32 request_index = 1; // device expects TxAck message from the computer + optional bytes tx_hash = 2; // tx_hash of requested transaction + optional uint32 extra_data_len = 3; // length of requested extra data + optional uint32 extra_data_offset = 4; // offset of requested extra data +} + +/** + * Structure representing serialized data + * @used_in TxRequest + */ +message TxRequestSerializedType { + optional uint32 signature_index = 1; // 'signature' field contains signed input of this index + optional bytes signature = 2; // signature of the signature_index input + optional bytes serialized_tx = 3; // part of serialized and signed transaction +} + +/** + * Structure representing identity data + * @used_in IdentityType + */ +message IdentityType { + optional string proto = 1; // proto part of URI + optional string user = 2; // user part of URI + optional string host = 3; // host part of URI + optional string port = 4; // port part of URI + optional string path = 5; // path part of URI + optional uint32 index = 6 [default=0]; // identity index +} diff --git a/accounts/usbwallet/ledger.go b/accounts/usbwallet/ledger.go new file mode 100644 index 000000000..f5def61d2 --- /dev/null +++ b/accounts/usbwallet/ledger.go @@ -0,0 +1,464 @@ +// Copyright 2017 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/>. + +// This file contains the implementation for interacting with the Ledger hardware +// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo: +// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc + +package usbwallet + +import ( + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "io" + "math/big" + + "github.com/ethereum/go-ethereum/accounts" + "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/log" + "github.com/ethereum/go-ethereum/rlp" +) + +// ledgerOpcode is an enumeration encoding the supported Ledger opcodes. +type ledgerOpcode byte + +// ledgerParam1 is an enumeration encoding the supported Ledger parameters for +// specific opcodes. The same parameter values may be reused between opcodes. +type ledgerParam1 byte + +// ledgerParam2 is an enumeration encoding the supported Ledger parameters for +// specific opcodes. The same parameter values may be reused between opcodes. +type ledgerParam2 byte + +const ( + ledgerOpRetrieveAddress ledgerOpcode = 0x02 // Returns the public key and Ethereum address for a given BIP 32 path + ledgerOpSignTransaction ledgerOpcode = 0x04 // Signs an Ethereum transaction after having the user validate the parameters + ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration + + ledgerP1DirectlyFetchAddress ledgerParam1 = 0x00 // Return address directly from the wallet + ledgerP1ConfirmFetchAddress ledgerParam1 = 0x01 // Require a user confirmation before returning the address + ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing + ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing + ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address + ledgerP2ReturnAddressChainCode ledgerParam2 = 0x01 // Require a user confirmation before returning the address +) + +// errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange +// if the device replies with a mismatching header. This usually means the device +// is in browser mode. +var errLedgerReplyInvalidHeader = errors.New("ledger: invalid reply header") + +// errLedgerInvalidVersionReply is the error message returned by a Ledger version retrieval +// when a response does arrive, but it does not contain the expected data. +var errLedgerInvalidVersionReply = errors.New("ledger: invalid version reply") + +// ledgerDriver implements the communication with a Ledger hardware wallet. +type ledgerDriver struct { + device io.ReadWriter // USB device connection to communicate through + version [3]byte // Current version of the Ledger firmware (zero if app is offline) + browser bool // Flag whether the Ledger is in browser mode (reply channel mismatch) + failure error // Any failure that would make the device unusable + log log.Logger // Contextual logger to tag the ledger with its id +} + +// newLedgerDriver creates a new instance of a Ledger USB protocol driver. +func newLedgerDriver(logger log.Logger) driver { + return &ledgerDriver{ + log: logger, + } +} + +// Status implements usbwallet.driver, returning various states the Ledger can +// currently be in. +func (w *ledgerDriver) Status() (string, error) { + if w.failure != nil { + return fmt.Sprintf("Failed: %v", w.failure), w.failure + } + if w.browser { + return "Ethereum app in browser mode", w.failure + } + if w.offline() { + return "Ethereum app offline", w.failure + } + return fmt.Sprintf("Ethereum app v%d.%d.%d online", w.version[0], w.version[1], w.version[2]), w.failure +} + +// offline returns whether the wallet and the Ethereum app is offline or not. +// +// The method assumes that the state lock is held! +func (w *ledgerDriver) offline() bool { + return w.version == [3]byte{0, 0, 0} +} + +// Open implements usbwallet.driver, attempting to initialize the connection to the +// Ledger hardware wallet. The Ledger does not require a user passphrase, so that +// parameter is silently discarded. +func (w *ledgerDriver) Open(device io.ReadWriter, passphrase string) error { + w.device, w.failure = device, nil + + _, err := w.ledgerDerive(accounts.DefaultBaseDerivationPath) + if err != nil { + // Ethereum app is not running or in browser mode, nothing more to do, return + if err == errLedgerReplyInvalidHeader { + w.browser = true + } + return nil + } + // Try to resolve the Ethereum app's version, will fail prior to v1.0.2 + if w.version, err = w.ledgerVersion(); err != nil { + w.version = [3]byte{1, 0, 0} // Assume worst case, can't verify if v1.0.0 or v1.0.1 + } + return nil +} + +// Close implements usbwallet.driver, cleaning up and metadata maintained within +// the Ledger driver. +func (w *ledgerDriver) Close() error { + w.browser, w.version = false, [3]byte{} + return nil +} + +// Heartbeat implements usbwallet.driver, performing a sanity check against the +// Ledger to see if it's still online. +func (w *ledgerDriver) Heartbeat() error { + if _, err := w.ledgerVersion(); err != nil && err != errLedgerInvalidVersionReply { + w.failure = err + return err + } + return nil +} + +// Derive implements usbwallet.driver, sending a derivation request to the Ledger +// and returning the Ethereum address located on that derivation path. +func (w *ledgerDriver) Derive(path accounts.DerivationPath) (common.Address, error) { + return w.ledgerDerive(path) +} + +// SignTx implements usbwallet.driver, sending the transaction to the Ledger and +// waiting for the user to confirm or deny the transaction. +// +// Note, if the version of the Ethereum application running on the Ledger wallet is +// too old to sign EIP-155 transactions, but such is requested nonetheless, an error +// will be returned opposed to silently signing in Homestead mode. +func (w *ledgerDriver) SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) { + // If the Ethereum app doesn't run, abort + if w.offline() { + return common.Address{}, nil, accounts.ErrWalletClosed + } + // Ensure the wallet is capable of signing the given transaction + if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 { + return common.Address{}, nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2]) + } + // All infos gathered and metadata checks out, request signing + return w.ledgerSign(path, tx, chainID) +} + +// ledgerVersion retrieves the current version of the Ethereum wallet app running +// on the Ledger wallet. +// +// The version retrieval protocol is defined as follows: +// +// CLA | INS | P1 | P2 | Lc | Le +// ----+-----+----+----+----+--- +// E0 | 06 | 00 | 00 | 00 | 04 +// +// With no input data, and the output data being: +// +// Description | Length +// ---------------------------------------------------+-------- +// Flags 01: arbitrary data signature enabled by user | 1 byte +// Application major version | 1 byte +// Application minor version | 1 byte +// Application patch version | 1 byte +func (w *ledgerDriver) ledgerVersion() ([3]byte, error) { + // Send the request and wait for the response + reply, err := w.ledgerExchange(ledgerOpGetConfiguration, 0, 0, nil) + if err != nil { + return [3]byte{}, err + } + if len(reply) != 4 { + return [3]byte{}, errLedgerInvalidVersionReply + } + // Cache the version for future reference + var version [3]byte + copy(version[:], reply[1:]) + return version, nil +} + +// ledgerDerive retrieves the currently active Ethereum address from a Ledger +// wallet at the specified derivation path. +// +// The address derivation protocol is defined as follows: +// +// CLA | INS | P1 | P2 | Lc | Le +// ----+-----+----+----+-----+--- +// E0 | 02 | 00 return address +// 01 display address and confirm before returning +// | 00: do not return the chain code +// | 01: return the chain code +// | var | 00 +// +// Where the input data is: +// +// Description | Length +// -------------------------------------------------+-------- +// Number of BIP 32 derivations to perform (max 10) | 1 byte +// First derivation index (big endian) | 4 bytes +// ... | 4 bytes +// Last derivation index (big endian) | 4 bytes +// +// And the output data is: +// +// Description | Length +// ------------------------+------------------- +// Public Key length | 1 byte +// Uncompressed Public Key | arbitrary +// Ethereum address length | 1 byte +// Ethereum address | 40 bytes hex ascii +// Chain code if requested | 32 bytes +func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, error) { + // Flatten the derivation path into the Ledger request + path := make([]byte, 1+4*len(derivationPath)) + path[0] = byte(len(derivationPath)) + for i, component := range derivationPath { + binary.BigEndian.PutUint32(path[1+4*i:], component) + } + // Send the request and wait for the response + reply, err := w.ledgerExchange(ledgerOpRetrieveAddress, ledgerP1DirectlyFetchAddress, ledgerP2DiscardAddressChainCode, path) + if err != nil { + return common.Address{}, err + } + // Discard the public key, we don't need that for now + if len(reply) < 1 || len(reply) < 1+int(reply[0]) { + return common.Address{}, errors.New("reply lacks public key entry") + } + reply = reply[1+int(reply[0]):] + + // Extract the Ethereum hex address string + if len(reply) < 1 || len(reply) < 1+int(reply[0]) { + return common.Address{}, errors.New("reply lacks address entry") + } + hexstr := reply[1 : 1+int(reply[0])] + + // Decode the hex sting into an Ethereum address and return + var address common.Address + hex.Decode(address[:], hexstr) + return address, nil +} + +// ledgerSign sends the transaction to the Ledger wallet, and waits for the user +// to confirm or deny the transaction. +// +// The transaction signing protocol is defined as follows: +// +// CLA | INS | P1 | P2 | Lc | Le +// ----+-----+----+----+-----+--- +// E0 | 04 | 00: first transaction data block +// 80: subsequent transaction data block +// | 00 | variable | variable +// +// Where the input for the first transaction block (first 255 bytes) is: +// +// Description | Length +// -------------------------------------------------+---------- +// Number of BIP 32 derivations to perform (max 10) | 1 byte +// First derivation index (big endian) | 4 bytes +// ... | 4 bytes +// Last derivation index (big endian) | 4 bytes +// RLP transaction chunk | arbitrary +// +// And the input for subsequent transaction blocks (first 255 bytes) are: +// +// Description | Length +// ----------------------+---------- +// RLP transaction chunk | arbitrary +// +// And the output data is: +// +// Description | Length +// ------------+--------- +// signature V | 1 byte +// signature R | 32 bytes +// signature S | 32 bytes +func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) { + // Flatten the derivation path into the Ledger request + path := make([]byte, 1+4*len(derivationPath)) + path[0] = byte(len(derivationPath)) + for i, component := range derivationPath { + binary.BigEndian.PutUint32(path[1+4*i:], component) + } + // Create the transaction RLP based on whether legacy or EIP155 signing was requeste + var ( + txrlp []byte + err error + ) + if chainID == nil { + if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data()}); err != nil { + return common.Address{}, nil, err + } + } else { + if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), chainID, big.NewInt(0), big.NewInt(0)}); err != nil { + return common.Address{}, nil, err + } + } + payload := append(path, txrlp...) + + // Send the request and wait for the response + var ( + op = ledgerP1InitTransactionData + reply []byte + ) + for len(payload) > 0 { + // Calculate the size of the next data chunk + chunk := 255 + if chunk > len(payload) { + chunk = len(payload) + } + // Send the chunk over, ensuring it's processed correctly + reply, err = w.ledgerExchange(ledgerOpSignTransaction, op, 0, payload[:chunk]) + if err != nil { + return common.Address{}, nil, err + } + // Shift the payload and ensure subsequent chunks are marked as such + payload = payload[chunk:] + op = ledgerP1ContTransactionData + } + // Extract the Ethereum signature and do a sanity validation + if len(reply) != 65 { + return common.Address{}, nil, errors.New("reply lacks signature") + } + signature := append(reply[1:], reply[0]) + + // Create the correct signer and signature transform based on the chain ID + var signer types.Signer + if chainID == nil { + signer = new(types.HomesteadSigner) + } else { + signer = types.NewEIP155Signer(chainID) + signature[64] = signature[64] - byte(chainID.Uint64()*2+35) + } + signed, err := tx.WithSignature(signer, signature) + if err != nil { + return common.Address{}, nil, err + } + sender, err := types.Sender(signer, signed) + if err != nil { + return common.Address{}, nil, err + } + return sender, signed, nil +} + +// ledgerExchange performs a data exchange with the Ledger wallet, sending it a +// message and retrieving the response. +// +// The common transport header is defined as follows: +// +// Description | Length +// --------------------------------------+---------- +// Communication channel ID (big endian) | 2 bytes +// Command tag | 1 byte +// Packet sequence index (big endian) | 2 bytes +// Payload | arbitrary +// +// The Communication channel ID allows commands multiplexing over the same +// physical link. It is not used for the time being, and should be set to 0101 +// to avoid compatibility issues with implementations ignoring a leading 00 byte. +// +// The Command tag describes the message content. Use TAG_APDU (0x05) for standard +// APDU payloads, or TAG_PING (0x02) for a simple link test. +// +// The Packet sequence index describes the current sequence for fragmented payloads. +// The first fragment index is 0x00. +// +// APDU Command payloads are encoded as follows: +// +// Description | Length +// ----------------------------------- +// APDU length (big endian) | 2 bytes +// APDU CLA | 1 byte +// APDU INS | 1 byte +// APDU P1 | 1 byte +// APDU P2 | 1 byte +// APDU length | 1 byte +// Optional APDU data | arbitrary +func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) { + // Construct the message payload, possibly split into multiple chunks + apdu := make([]byte, 2, 7+len(data)) + + binary.BigEndian.PutUint16(apdu, uint16(5+len(data))) + apdu = append(apdu, []byte{0xe0, byte(opcode), byte(p1), byte(p2), byte(len(data))}...) + apdu = append(apdu, data...) + + // Stream all the chunks to the device + header := []byte{0x01, 0x01, 0x05, 0x00, 0x00} // Channel ID and command tag appended + chunk := make([]byte, 64) + space := len(chunk) - len(header) + + for i := 0; len(apdu) > 0; i++ { + // Construct the new message to stream + chunk = append(chunk[:0], header...) + binary.BigEndian.PutUint16(chunk[3:], uint16(i)) + + if len(apdu) > space { + chunk = append(chunk, apdu[:space]...) + apdu = apdu[space:] + } else { + chunk = append(chunk, apdu...) + apdu = nil + } + // Send over to the device + w.log.Trace("Data chunk sent to the Ledger", "chunk", hexutil.Bytes(chunk)) + if _, err := w.device.Write(chunk); err != nil { + return nil, err + } + } + // Stream the reply back from the wallet in 64 byte chunks + var reply []byte + chunk = chunk[:64] // Yeah, we surely have enough space + for { + // Read the next chunk from the Ledger wallet + if _, err := io.ReadFull(w.device, chunk); err != nil { + return nil, err + } + w.log.Trace("Data chunk received from the Ledger", "chunk", hexutil.Bytes(chunk)) + + // Make sure the transport header matches + if chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != 0x05 { + return nil, errLedgerReplyInvalidHeader + } + // If it's the first chunk, retrieve the total message length + var payload []byte + + if chunk[3] == 0x00 && chunk[4] == 0x00 { + reply = make([]byte, 0, int(binary.BigEndian.Uint16(chunk[5:7]))) + payload = chunk[7:] + } else { + payload = chunk[5:] + } + // Append to the reply and stop when filled up + if left := cap(reply) - len(reply); left > len(payload) { + reply = append(reply, payload...) + } else { + reply = append(reply, payload[:left]...) + break + } + } + return reply[:len(reply)-2], nil +} diff --git a/accounts/usbwallet/ledger_wallet.go b/accounts/usbwallet/ledger_wallet.go deleted file mode 100644 index f1beebb2c..000000000 --- a/accounts/usbwallet/ledger_wallet.go +++ /dev/null @@ -1,903 +0,0 @@ -// Copyright 2017 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/>. - -// This file contains the implementation for interacting with the Ledger hardware -// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo: -// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc - -package usbwallet - -import ( - "context" - "encoding/binary" - "encoding/hex" - "errors" - "fmt" - "io" - "math/big" - "sync" - "time" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts" - "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/log" - "github.com/ethereum/go-ethereum/rlp" - "github.com/karalabe/hid" -) - -// Maximum time between wallet health checks to detect USB unplugs. -const ledgerHeartbeatCycle = time.Second - -// Minimum time to wait between self derivation attempts, even it the user is -// requesting accounts like crazy. -const ledgerSelfDeriveThrottling = time.Second - -// ledgerOpcode is an enumeration encoding the supported Ledger opcodes. -type ledgerOpcode byte - -// ledgerParam1 is an enumeration encoding the supported Ledger parameters for -// specific opcodes. The same parameter values may be reused between opcodes. -type ledgerParam1 byte - -// ledgerParam2 is an enumeration encoding the supported Ledger parameters for -// specific opcodes. The same parameter values may be reused between opcodes. -type ledgerParam2 byte - -const ( - ledgerOpRetrieveAddress ledgerOpcode = 0x02 // Returns the public key and Ethereum address for a given BIP 32 path - ledgerOpSignTransaction ledgerOpcode = 0x04 // Signs an Ethereum transaction after having the user validate the parameters - ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration - - ledgerP1DirectlyFetchAddress ledgerParam1 = 0x00 // Return address directly from the wallet - ledgerP1ConfirmFetchAddress ledgerParam1 = 0x01 // Require a user confirmation before returning the address - ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing - ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing - ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address - ledgerP2ReturnAddressChainCode ledgerParam2 = 0x01 // Require a user confirmation before returning the address -) - -// errReplyInvalidHeader is the error message returned by a Ledger data exchange -// if the device replies with a mismatching header. This usually means the device -// is in browser mode. -var errReplyInvalidHeader = errors.New("invalid reply header") - -// errInvalidVersionReply is the error message returned by a Ledger version retrieval -// when a response does arrive, but it does not contain the expected data. -var errInvalidVersionReply = errors.New("invalid version reply") - -// ledgerWallet represents a live USB Ledger hardware wallet. -type ledgerWallet struct { - hub *LedgerHub // USB hub the device originates from (TODO(karalabe): remove if hotplug lands on Windows) - url *accounts.URL // Textual URL uniquely identifying this wallet - - info hid.DeviceInfo // Known USB device infos about the wallet - device *hid.Device // USB device advertising itself as a Ledger wallet - failure error // Any failure that would make the device unusable - - version [3]byte // Current version of the Ledger Ethereum app (zero if app is offline) - browser bool // Flag whether the Ledger is in browser mode (reply channel mismatch) - accounts []accounts.Account // List of derive accounts pinned on the Ledger - paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations - - deriveNextPath accounts.DerivationPath // Next derivation path for account auto-discovery - deriveNextAddr common.Address // Next derived account address for auto-discovery - deriveChain ethereum.ChainStateReader // Blockchain state reader to discover used account with - deriveReq chan chan struct{} // Channel to request a self-derivation on - deriveQuit chan chan error // Channel to terminate the self-deriver with - - healthQuit chan chan error - - // Locking a hardware wallet is a bit special. Since hardware devices are lower - // performing, any communication with them might take a non negligible amount of - // time. Worse still, waiting for user confirmation can take arbitrarily long, - // but exclusive communication must be upheld during. Locking the entire wallet - // in the mean time however would stall any parts of the system that don't want - // to communicate, just read some state (e.g. list the accounts). - // - // As such, a hardware wallet needs two locks to function correctly. A state - // lock can be used to protect the wallet's software-side internal state, which - // must not be held exlusively during hardware communication. A communication - // lock can be used to achieve exclusive access to the device itself, this one - // however should allow "skipping" waiting for operations that might want to - // use the device, but can live without too (e.g. account self-derivation). - // - // Since we have two locks, it's important to know how to properly use them: - // - Communication requires the `device` to not change, so obtaining the - // commsLock should be done after having a stateLock. - // - Communication must not disable read access to the wallet state, so it - // must only ever hold a *read* lock to stateLock. - commsLock chan struct{} // Mutex (buf=1) for the USB comms without keeping the state locked - stateLock sync.RWMutex // Protects read and write access to the wallet struct fields - - log log.Logger // Contextual logger to tag the ledger with its id -} - -// URL implements accounts.Wallet, returning the URL of the Ledger device. -func (w *ledgerWallet) URL() accounts.URL { - return *w.url // Immutable, no need for a lock -} - -// Status implements accounts.Wallet, always whether the Ledger is opened, closed -// or whether the Ethereum app was not started on it. -func (w *ledgerWallet) Status() string { - w.stateLock.RLock() // No device communication, state lock is enough - defer w.stateLock.RUnlock() - - if w.failure != nil { - return fmt.Sprintf("Failed: %v", w.failure) - } - if w.device == nil { - return "Closed" - } - if w.browser { - return "Ethereum app in browser mode" - } - if w.offline() { - return "Ethereum app offline" - } - return fmt.Sprintf("Ethereum app v%d.%d.%d online", w.version[0], w.version[1], w.version[2]) -} - -// offline returns whether the wallet and the Ethereum app is offline or not. -// -// The method assumes that the state lock is held! -func (w *ledgerWallet) offline() bool { - return w.version == [3]byte{0, 0, 0} -} - -// failed returns if the USB device wrapped by the wallet failed for some reason. -// This is used by the device scanner to report failed wallets as departed. -// -// The method assumes that the state lock is *not* held! -func (w *ledgerWallet) failed() bool { - w.stateLock.RLock() // No device communication, state lock is enough - defer w.stateLock.RUnlock() - - return w.failure != nil -} - -// Open implements accounts.Wallet, attempting to open a USB connection to the -// Ledger hardware wallet. The Ledger does not require a user passphrase, so that -// parameter is silently discarded. -func (w *ledgerWallet) Open(passphrase string) error { - w.stateLock.Lock() // State lock is enough since there's no connection yet at this point - defer w.stateLock.Unlock() - - // If the wallet was already opened, don't try to open again - if w.device != nil { - return accounts.ErrWalletAlreadyOpen - } - // Otherwise iterate over all USB devices and find this again (no way to directly do this) - device, err := w.info.Open() - if err != nil { - return err - } - // Wallet seems to be successfully opened, guess if the Ethereum app is running - w.device = device - w.commsLock = make(chan struct{}, 1) - w.commsLock <- struct{}{} // Enable lock - - w.paths = make(map[common.Address]accounts.DerivationPath) - - w.deriveReq = make(chan chan struct{}) - w.deriveQuit = make(chan chan error) - w.healthQuit = make(chan chan error) - - defer func() { - go w.heartbeat() - go w.selfDerive() - }() - - if _, err = w.ledgerDerive(accounts.DefaultBaseDerivationPath); err != nil { - // Ethereum app is not running or in browser mode, nothing more to do, return - if err == errReplyInvalidHeader { - w.browser = true - } - return nil - } - // Try to resolve the Ethereum app's version, will fail prior to v1.0.2 - if w.version, err = w.ledgerVersion(); err != nil { - w.version = [3]byte{1, 0, 0} // Assume worst case, can't verify if v1.0.0 or v1.0.1 - } - return nil -} - -// heartbeat is a health check loop for the Ledger wallets to periodically verify -// whether they are still present or if they malfunctioned. It is needed because: -// - libusb on Windows doesn't support hotplug, so we can't detect USB unplugs -// - communication timeout on the Ledger requires a device power cycle to fix -func (w *ledgerWallet) heartbeat() { - w.log.Debug("Ledger health-check started") - defer w.log.Debug("Ledger health-check stopped") - - // Execute heartbeat checks until termination or error - var ( - errc chan error - err error - ) - for errc == nil && err == nil { - // Wait until termination is requested or the heartbeat cycle arrives - select { - case errc = <-w.healthQuit: - // Termination requested - continue - case <-time.After(ledgerHeartbeatCycle): - // Heartbeat time - } - // Execute a tiny data exchange to see responsiveness - w.stateLock.RLock() - if w.device == nil { - // Terminated while waiting for the lock - w.stateLock.RUnlock() - continue - } - <-w.commsLock // Don't lock state while resolving version - _, err = w.ledgerVersion() - w.commsLock <- struct{}{} - w.stateLock.RUnlock() - - if err != nil && err != errInvalidVersionReply { - w.stateLock.Lock() // Lock state to tear the wallet down - w.failure = err - w.close() - w.stateLock.Unlock() - } - // Ignore non hardware related errors - err = nil - } - // In case of error, wait for termination - if err != nil { - w.log.Debug("Ledger health-check failed", "err", err) - errc = <-w.healthQuit - } - errc <- err -} - -// Close implements accounts.Wallet, closing the USB connection to the Ledger. -func (w *ledgerWallet) Close() error { - // Ensure the wallet was opened - w.stateLock.RLock() - hQuit, dQuit := w.healthQuit, w.deriveQuit - w.stateLock.RUnlock() - - // Terminate the health checks - var herr error - if hQuit != nil { - errc := make(chan error) - hQuit <- errc - herr = <-errc // Save for later, we *must* close the USB - } - // Terminate the self-derivations - var derr error - if dQuit != nil { - errc := make(chan error) - dQuit <- errc - derr = <-errc // Save for later, we *must* close the USB - } - // Terminate the device connection - w.stateLock.Lock() - defer w.stateLock.Unlock() - - w.healthQuit = nil - w.deriveQuit = nil - w.deriveReq = nil - - if err := w.close(); err != nil { - return err - } - if herr != nil { - return herr - } - return derr -} - -// close is the internal wallet closer that terminates the USB connection and -// resets all the fields to their defaults. -// -// Note, close assumes the state lock is held! -func (w *ledgerWallet) close() error { - // Allow duplicate closes, especially for health-check failures - if w.device == nil { - return nil - } - // Close the device, clear everything, then return - w.device.Close() - w.device = nil - - w.browser, w.version = false, [3]byte{} - w.accounts, w.paths = nil, nil - - return nil -} - -// Accounts implements accounts.Wallet, returning the list of accounts pinned to -// the Ledger hardware wallet. If self-derivation was enabled, the account list -// is periodically expanded based on current chain state. -func (w *ledgerWallet) Accounts() []accounts.Account { - // Attempt self-derivation if it's running - reqc := make(chan struct{}, 1) - select { - case w.deriveReq <- reqc: - // Self-derivation request accepted, wait for it - <-reqc - default: - // Self-derivation offline, throttled or busy, skip - } - // Return whatever account list we ended up with - w.stateLock.RLock() - defer w.stateLock.RUnlock() - - cpy := make([]accounts.Account, len(w.accounts)) - copy(cpy, w.accounts) - return cpy -} - -// selfDerive is an account derivation loop that upon request attempts to find -// new non-zero accounts. -func (w *ledgerWallet) selfDerive() { - w.log.Debug("Ledger self-derivation started") - defer w.log.Debug("Ledger self-derivation stopped") - - // Execute self-derivations until termination or error - var ( - reqc chan struct{} - errc chan error - err error - ) - for errc == nil && err == nil { - // Wait until either derivation or termination is requested - select { - case errc = <-w.deriveQuit: - // Termination requested - continue - case reqc = <-w.deriveReq: - // Account discovery requested - } - // Derivation needs a chain and device access, skip if either unavailable - w.stateLock.RLock() - if w.device == nil || w.deriveChain == nil || w.offline() { - w.stateLock.RUnlock() - reqc <- struct{}{} - continue - } - select { - case <-w.commsLock: - default: - w.stateLock.RUnlock() - reqc <- struct{}{} - continue - } - // Device lock obtained, derive the next batch of accounts - var ( - accs []accounts.Account - paths []accounts.DerivationPath - - nextAddr = w.deriveNextAddr - nextPath = w.deriveNextPath - - context = context.Background() - ) - for empty := false; !empty; { - // Retrieve the next derived Ethereum account - if nextAddr == (common.Address{}) { - if nextAddr, err = w.ledgerDerive(nextPath); err != nil { - w.log.Warn("Ledger account derivation failed", "err", err) - break - } - } - // Check the account's status against the current chain state - var ( - balance *big.Int - nonce uint64 - ) - balance, err = w.deriveChain.BalanceAt(context, nextAddr, nil) - if err != nil { - w.log.Warn("Ledger balance retrieval failed", "err", err) - break - } - nonce, err = w.deriveChain.NonceAt(context, nextAddr, nil) - if err != nil { - w.log.Warn("Ledger nonce retrieval failed", "err", err) - break - } - // If the next account is empty, stop self-derivation, but add it nonetheless - if balance.Sign() == 0 && nonce == 0 { - empty = true - } - // We've just self-derived a new account, start tracking it locally - path := make(accounts.DerivationPath, len(nextPath)) - copy(path[:], nextPath[:]) - paths = append(paths, path) - - account := accounts.Account{ - Address: nextAddr, - URL: accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)}, - } - accs = append(accs, account) - - // Display a log message to the user for new (or previously empty accounts) - if _, known := w.paths[nextAddr]; !known || (!empty && nextAddr == w.deriveNextAddr) { - w.log.Info("Ledger discovered new account", "address", nextAddr, "path", path, "balance", balance, "nonce", nonce) - } - // Fetch the next potential account - if !empty { - nextAddr = common.Address{} - nextPath[len(nextPath)-1]++ - } - } - // Self derivation complete, release device lock - w.commsLock <- struct{}{} - w.stateLock.RUnlock() - - // Insert any accounts successfully derived - w.stateLock.Lock() - for i := 0; i < len(accs); i++ { - if _, ok := w.paths[accs[i].Address]; !ok { - w.accounts = append(w.accounts, accs[i]) - w.paths[accs[i].Address] = paths[i] - } - } - // Shift the self-derivation forward - // TODO(karalabe): don't overwrite changes from wallet.SelfDerive - w.deriveNextAddr = nextAddr - w.deriveNextPath = nextPath - w.stateLock.Unlock() - - // Notify the user of termination and loop after a bit of time (to avoid trashing) - reqc <- struct{}{} - if err == nil { - select { - case errc = <-w.deriveQuit: - // Termination requested, abort - case <-time.After(ledgerSelfDeriveThrottling): - // Waited enough, willing to self-derive again - } - } - } - // In case of error, wait for termination - if err != nil { - w.log.Debug("Ledger self-derivation failed", "err", err) - errc = <-w.deriveQuit - } - errc <- err -} - -// Contains implements accounts.Wallet, returning whether a particular account is -// or is not pinned into this Ledger instance. Although we could attempt to resolve -// unpinned accounts, that would be an non-negligible hardware operation. -func (w *ledgerWallet) Contains(account accounts.Account) bool { - w.stateLock.RLock() - defer w.stateLock.RUnlock() - - _, exists := w.paths[account.Address] - return exists -} - -// Derive implements accounts.Wallet, deriving a new account at the specific -// derivation path. If pin is set to true, the account will be added to the list -// of tracked accounts. -func (w *ledgerWallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) { - // Try to derive the actual account and update its URL if successful - w.stateLock.RLock() // Avoid device disappearing during derivation - - if w.device == nil || w.offline() { - w.stateLock.RUnlock() - return accounts.Account{}, accounts.ErrWalletClosed - } - <-w.commsLock // Avoid concurrent hardware access - address, err := w.ledgerDerive(path) - w.commsLock <- struct{}{} - - w.stateLock.RUnlock() - - // If an error occurred or no pinning was requested, return - if err != nil { - return accounts.Account{}, err - } - account := accounts.Account{ - Address: address, - URL: accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)}, - } - if !pin { - return account, nil - } - // Pinning needs to modify the state - w.stateLock.Lock() - defer w.stateLock.Unlock() - - if _, ok := w.paths[address]; !ok { - w.accounts = append(w.accounts, account) - w.paths[address] = path - } - return account, nil -} - -// SelfDerive implements accounts.Wallet, trying to discover accounts that the -// user used previously (based on the chain state), but ones that he/she did not -// explicitly pin to the wallet manually. To avoid chain head monitoring, self -// derivation only runs during account listing (and even then throttled). -func (w *ledgerWallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) { - w.stateLock.Lock() - defer w.stateLock.Unlock() - - w.deriveNextPath = make(accounts.DerivationPath, len(base)) - copy(w.deriveNextPath[:], base[:]) - - w.deriveNextAddr = common.Address{} - w.deriveChain = chain -} - -// SignHash implements accounts.Wallet, however signing arbitrary data is not -// supported for Ledger wallets, so this method will always return an error. -func (w *ledgerWallet) SignHash(acc accounts.Account, hash []byte) ([]byte, error) { - return nil, accounts.ErrNotSupported -} - -// SignTx implements accounts.Wallet. It sends the transaction over to the Ledger -// wallet to request a confirmation from the user. It returns either the signed -// transaction or a failure if the user denied the transaction. -// -// Note, if the version of the Ethereum application running on the Ledger wallet is -// too old to sign EIP-155 transactions, but such is requested nonetheless, an error -// will be returned opposed to silently signing in Homestead mode. -func (w *ledgerWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - w.stateLock.RLock() // Comms have own mutex, this is for the state fields - defer w.stateLock.RUnlock() - - // If the wallet is closed, or the Ethereum app doesn't run, abort - if w.device == nil || w.offline() { - return nil, accounts.ErrWalletClosed - } - // Make sure the requested account is contained within - path, ok := w.paths[account.Address] - if !ok { - return nil, accounts.ErrUnknownAccount - } - // Ensure the wallet is capable of signing the given transaction - if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 { - return nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2]) - } - // All infos gathered and metadata checks out, request signing - <-w.commsLock - defer func() { w.commsLock <- struct{}{} }() - - // Ensure the device isn't screwed with while user confirmation is pending - // TODO(karalabe): remove if hotplug lands on Windows - w.hub.commsLock.Lock() - w.hub.commsPend++ - w.hub.commsLock.Unlock() - - defer func() { - w.hub.commsLock.Lock() - w.hub.commsPend-- - w.hub.commsLock.Unlock() - }() - return w.ledgerSign(path, account.Address, tx, chainID) -} - -// SignHashWithPassphrase implements accounts.Wallet, however signing arbitrary -// data is not supported for Ledger wallets, so this method will always return -// an error. -func (w *ledgerWallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) { - return nil, accounts.ErrNotSupported -} - -// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given -// transaction with the given account using passphrase as extra authentication. -// Since the Ledger does not support extra passphrases, it is silently ignored. -func (w *ledgerWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - return w.SignTx(account, tx, chainID) -} - -// ledgerVersion retrieves the current version of the Ethereum wallet app running -// on the Ledger wallet. -// -// The version retrieval protocol is defined as follows: -// -// CLA | INS | P1 | P2 | Lc | Le -// ----+-----+----+----+----+--- -// E0 | 06 | 00 | 00 | 00 | 04 -// -// With no input data, and the output data being: -// -// Description | Length -// ---------------------------------------------------+-------- -// Flags 01: arbitrary data signature enabled by user | 1 byte -// Application major version | 1 byte -// Application minor version | 1 byte -// Application patch version | 1 byte -func (w *ledgerWallet) ledgerVersion() ([3]byte, error) { - // Send the request and wait for the response - reply, err := w.ledgerExchange(ledgerOpGetConfiguration, 0, 0, nil) - if err != nil { - return [3]byte{}, err - } - if len(reply) != 4 { - return [3]byte{}, errInvalidVersionReply - } - // Cache the version for future reference - var version [3]byte - copy(version[:], reply[1:]) - return version, nil -} - -// ledgerDerive retrieves the currently active Ethereum address from a Ledger -// wallet at the specified derivation path. -// -// The address derivation protocol is defined as follows: -// -// CLA | INS | P1 | P2 | Lc | Le -// ----+-----+----+----+-----+--- -// E0 | 02 | 00 return address -// 01 display address and confirm before returning -// | 00: do not return the chain code -// | 01: return the chain code -// | var | 00 -// -// Where the input data is: -// -// Description | Length -// -------------------------------------------------+-------- -// Number of BIP 32 derivations to perform (max 10) | 1 byte -// First derivation index (big endian) | 4 bytes -// ... | 4 bytes -// Last derivation index (big endian) | 4 bytes -// -// And the output data is: -// -// Description | Length -// ------------------------+------------------- -// Public Key length | 1 byte -// Uncompressed Public Key | arbitrary -// Ethereum address length | 1 byte -// Ethereum address | 40 bytes hex ascii -// Chain code if requested | 32 bytes -func (w *ledgerWallet) ledgerDerive(derivationPath []uint32) (common.Address, error) { - // Flatten the derivation path into the Ledger request - path := make([]byte, 1+4*len(derivationPath)) - path[0] = byte(len(derivationPath)) - for i, component := range derivationPath { - binary.BigEndian.PutUint32(path[1+4*i:], component) - } - // Send the request and wait for the response - reply, err := w.ledgerExchange(ledgerOpRetrieveAddress, ledgerP1DirectlyFetchAddress, ledgerP2DiscardAddressChainCode, path) - if err != nil { - return common.Address{}, err - } - // Discard the public key, we don't need that for now - if len(reply) < 1 || len(reply) < 1+int(reply[0]) { - return common.Address{}, errors.New("reply lacks public key entry") - } - reply = reply[1+int(reply[0]):] - - // Extract the Ethereum hex address string - if len(reply) < 1 || len(reply) < 1+int(reply[0]) { - return common.Address{}, errors.New("reply lacks address entry") - } - hexstr := reply[1 : 1+int(reply[0])] - - // Decode the hex sting into an Ethereum address and return - var address common.Address - hex.Decode(address[:], hexstr) - return address, nil -} - -// ledgerSign sends the transaction to the Ledger wallet, and waits for the user -// to confirm or deny the transaction. -// -// The transaction signing protocol is defined as follows: -// -// CLA | INS | P1 | P2 | Lc | Le -// ----+-----+----+----+-----+--- -// E0 | 04 | 00: first transaction data block -// 80: subsequent transaction data block -// | 00 | variable | variable -// -// Where the input for the first transaction block (first 255 bytes) is: -// -// Description | Length -// -------------------------------------------------+---------- -// Number of BIP 32 derivations to perform (max 10) | 1 byte -// First derivation index (big endian) | 4 bytes -// ... | 4 bytes -// Last derivation index (big endian) | 4 bytes -// RLP transaction chunk | arbitrary -// -// And the input for subsequent transaction blocks (first 255 bytes) are: -// -// Description | Length -// ----------------------+---------- -// RLP transaction chunk | arbitrary -// -// And the output data is: -// -// Description | Length -// ------------+--------- -// signature V | 1 byte -// signature R | 32 bytes -// signature S | 32 bytes -func (w *ledgerWallet) ledgerSign(derivationPath []uint32, address common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { - // Flatten the derivation path into the Ledger request - path := make([]byte, 1+4*len(derivationPath)) - path[0] = byte(len(derivationPath)) - for i, component := range derivationPath { - binary.BigEndian.PutUint32(path[1+4*i:], component) - } - // Create the transaction RLP based on whether legacy or EIP155 signing was requeste - var ( - txrlp []byte - err error - ) - if chainID == nil { - if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data()}); err != nil { - return nil, err - } - } else { - if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), chainID, big.NewInt(0), big.NewInt(0)}); err != nil { - return nil, err - } - } - payload := append(path, txrlp...) - - // Send the request and wait for the response - var ( - op = ledgerP1InitTransactionData - reply []byte - ) - for len(payload) > 0 { - // Calculate the size of the next data chunk - chunk := 255 - if chunk > len(payload) { - chunk = len(payload) - } - // Send the chunk over, ensuring it's processed correctly - reply, err = w.ledgerExchange(ledgerOpSignTransaction, op, 0, payload[:chunk]) - if err != nil { - return nil, err - } - // Shift the payload and ensure subsequent chunks are marked as such - payload = payload[chunk:] - op = ledgerP1ContTransactionData - } - // Extract the Ethereum signature and do a sanity validation - if len(reply) != 65 { - return nil, errors.New("reply lacks signature") - } - signature := append(reply[1:], reply[0]) - - // Create the correct signer and signature transform based on the chain ID - var signer types.Signer - if chainID == nil { - signer = new(types.HomesteadSigner) - } else { - signer = types.NewEIP155Signer(chainID) - signature[64] = signature[64] - byte(chainID.Uint64()*2+35) - } - // Inject the final signature into the transaction and sanity check the sender - signed, err := tx.WithSignature(signer, signature) - if err != nil { - return nil, err - } - sender, err := types.Sender(signer, signed) - if err != nil { - return nil, err - } - if sender != address { - return nil, fmt.Errorf("signer mismatch: expected %s, got %s", address.Hex(), sender.Hex()) - } - return signed, nil -} - -// ledgerExchange performs a data exchange with the Ledger wallet, sending it a -// message and retrieving the response. -// -// The common transport header is defined as follows: -// -// Description | Length -// --------------------------------------+---------- -// Communication channel ID (big endian) | 2 bytes -// Command tag | 1 byte -// Packet sequence index (big endian) | 2 bytes -// Payload | arbitrary -// -// The Communication channel ID allows commands multiplexing over the same -// physical link. It is not used for the time being, and should be set to 0101 -// to avoid compatibility issues with implementations ignoring a leading 00 byte. -// -// The Command tag describes the message content. Use TAG_APDU (0x05) for standard -// APDU payloads, or TAG_PING (0x02) for a simple link test. -// -// The Packet sequence index describes the current sequence for fragmented payloads. -// The first fragment index is 0x00. -// -// APDU Command payloads are encoded as follows: -// -// Description | Length -// ----------------------------------- -// APDU length (big endian) | 2 bytes -// APDU CLA | 1 byte -// APDU INS | 1 byte -// APDU P1 | 1 byte -// APDU P2 | 1 byte -// APDU length | 1 byte -// Optional APDU data | arbitrary -func (w *ledgerWallet) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) { - // Construct the message payload, possibly split into multiple chunks - apdu := make([]byte, 2, 7+len(data)) - - binary.BigEndian.PutUint16(apdu, uint16(5+len(data))) - apdu = append(apdu, []byte{0xe0, byte(opcode), byte(p1), byte(p2), byte(len(data))}...) - apdu = append(apdu, data...) - - // Stream all the chunks to the device - header := []byte{0x01, 0x01, 0x05, 0x00, 0x00} // Channel ID and command tag appended - chunk := make([]byte, 64) - space := len(chunk) - len(header) - - for i := 0; len(apdu) > 0; i++ { - // Construct the new message to stream - chunk = append(chunk[:0], header...) - binary.BigEndian.PutUint16(chunk[3:], uint16(i)) - - if len(apdu) > space { - chunk = append(chunk, apdu[:space]...) - apdu = apdu[space:] - } else { - chunk = append(chunk, apdu...) - apdu = nil - } - // Send over to the device - w.log.Trace("Data chunk sent to the Ledger", "chunk", hexutil.Bytes(chunk)) - if _, err := w.device.Write(chunk); err != nil { - return nil, err - } - } - // Stream the reply back from the wallet in 64 byte chunks - var reply []byte - chunk = chunk[:64] // Yeah, we surely have enough space - for { - // Read the next chunk from the Ledger wallet - if _, err := io.ReadFull(w.device, chunk); err != nil { - return nil, err - } - w.log.Trace("Data chunk received from the Ledger", "chunk", hexutil.Bytes(chunk)) - - // Make sure the transport header matches - if chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != 0x05 { - return nil, errReplyInvalidHeader - } - // If it's the first chunk, retrieve the total message length - var payload []byte - - if chunk[3] == 0x00 && chunk[4] == 0x00 { - reply = make([]byte, 0, int(binary.BigEndian.Uint16(chunk[5:7]))) - payload = chunk[7:] - } else { - payload = chunk[5:] - } - // Append to the reply and stop when filled up - if left := cap(reply) - len(reply); left > len(payload) { - reply = append(reply, payload...) - } else { - reply = append(reply, payload[:left]...) - break - } - } - return reply[:len(reply)-2], nil -} diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go new file mode 100644 index 000000000..159cb2ea9 --- /dev/null +++ b/accounts/usbwallet/trezor.go @@ -0,0 +1,330 @@ +// Copyright 2017 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/>. + +// This file contains the implementation for interacting with the Trezor hardware +// wallets. The wire protocol spec can be found on the SatoshiLabs website: +// https://doc.satoshilabs.com/trezor-tech/api-protobuf.html + +package usbwallet + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "math/big" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor" + "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/log" + "github.com/golang/protobuf/proto" +) + +// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In +// this case, the calling application should display a pinpad and send back the +// encoded passphrase. +var ErrTrezorPINNeeded = errors.New("trezor: pin needed") + +// errTrezorReplyInvalidHeader is the error message returned by a Trezor data exchange +// if the device replies with a mismatching header. This usually means the device +// is in browser mode. +var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header") + +// trezorDriver implements the communication with a Trezor hardware wallet. +type trezorDriver struct { + device io.ReadWriter // USB device connection to communicate through + version [3]uint32 // Current version of the Trezor firmware + label string // Current textual label of the Trezor device + pinwait bool // Flags whether the device is waiting for PIN entry + failure error // Any failure that would make the device unusable + log log.Logger // Contextual logger to tag the trezor with its id +} + +// newTrezorDriver creates a new instance of a Trezor USB protocol driver. +func newTrezorDriver(logger log.Logger) driver { + return &trezorDriver{ + log: logger, + } +} + +// Status implements accounts.Wallet, always whether the Trezor is opened, closed +// or whether the Ethereum app was not started on it. +func (w *trezorDriver) Status() (string, error) { + if w.failure != nil { + return fmt.Sprintf("Failed: %v", w.failure), w.failure + } + if w.device == nil { + return "Closed", w.failure + } + if w.pinwait { + return fmt.Sprintf("Trezor v%d.%d.%d '%s' waiting for PIN", w.version[0], w.version[1], w.version[2], w.label), w.failure + } + return fmt.Sprintf("Trezor v%d.%d.%d '%s' online", w.version[0], w.version[1], w.version[2], w.label), w.failure +} + +// Open implements usbwallet.driver, attempting to initialize the connection to +// the Trezor hardware wallet. Initializing the Trezor is a two phase operation: +// * The first phase is to initialize the connection and read the wallet's +// features. This phase is invoked is the provided passphrase is empty. The +// device will display the pinpad as a result and will return an appropriate +// error to notify the user that a second open phase is needed. +// * The second phase is to unlock access to the Trezor, which is done by the +// user actually providing a passphrase mapping a keyboard keypad to the pin +// number of the user (shuffled according to the pinpad displayed). +func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error { + w.device, w.failure = device, nil + + // If phase 1 is requested, init the connection and wait for user callback + if passphrase == "" { + // If we're already waiting for a PIN entry, insta-return + if w.pinwait { + return ErrTrezorPINNeeded + } + // Initialize a connection to the device + features := new(trezor.Features) + if _, err := w.trezorExchange(&trezor.Initialize{}, features); err != nil { + return err + } + w.version = [3]uint32{features.GetMajorVersion(), features.GetMinorVersion(), features.GetPatchVersion()} + w.label = features.GetLabel() + + // Do a manual ping, forcing the device to ask for its PIN + askPin := true + res, err := w.trezorExchange(&trezor.Ping{PinProtection: &askPin}, new(trezor.PinMatrixRequest), new(trezor.Success)) + if err != nil { + return err + } + // Only return the PIN request if the device wasn't unlocked until now + if res == 1 { + return nil // Device responded with trezor.Success + } + w.pinwait = true + return ErrTrezorPINNeeded + } + // Phase 2 requested with actual PIN entry + w.pinwait = false + + if _, err := w.trezorExchange(&trezor.PinMatrixAck{Pin: &passphrase}, new(trezor.Success)); err != nil { + w.failure = err + return err + } + return nil +} + +// Close implements usbwallet.driver, cleaning up and metadata maintained within +// the Trezor driver. +func (w *trezorDriver) Close() error { + w.version, w.label, w.pinwait = [3]uint32{}, "", false + return nil +} + +// Heartbeat implements usbwallet.driver, performing a sanity check against the +// Trezor to see if it's still online. +func (w *trezorDriver) Heartbeat() error { + if _, err := w.trezorExchange(&trezor.Ping{}, new(trezor.Success)); err != nil { + w.failure = err + return err + } + return nil +} + +// Derive implements usbwallet.driver, sending a derivation request to the Trezor +// and returning the Ethereum address located on that derivation path. +func (w *trezorDriver) Derive(path accounts.DerivationPath) (common.Address, error) { + return w.trezorDerive(path) +} + +// SignTx implements usbwallet.driver, sending the transaction to the Trezor and +// waiting for the user to confirm or deny the transaction. +func (w *trezorDriver) SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) { + if w.device == nil { + return common.Address{}, nil, accounts.ErrWalletClosed + } + return w.trezorSign(path, tx, chainID) +} + +// trezorDerive sends a derivation request to the Trezor device and returns the +// Ethereum address located on that path. +func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, error) { + address := new(trezor.EthereumAddress) + if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil { + return common.Address{}, err + } + return common.BytesToAddress(address.GetAddress()), nil +} + +// trezorSign sends the transaction to the Trezor wallet, and waits for the user +// to confirm or deny the transaction. +func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) { + // Create the transaction initiation message + data := tx.Data() + length := uint32(len(data)) + + request := &trezor.EthereumSignTx{ + AddressN: derivationPath, + Nonce: new(big.Int).SetUint64(tx.Nonce()).Bytes(), + GasPrice: tx.GasPrice().Bytes(), + GasLimit: tx.Gas().Bytes(), + Value: tx.Value().Bytes(), + DataLength: &length, + } + if to := tx.To(); to != nil { + request.To = (*to)[:] // Non contract deploy, set recipient explicitly + } + if length > 1024 { // Send the data chunked if that was requested + request.DataInitialChunk, data = data[:1024], data[1024:] + } else { + request.DataInitialChunk, data = data, nil + } + if chainID != nil { // EIP-155 transaction, set chain ID explicitly (only 32 bit is supported!?) + id := uint32(chainID.Int64()) + request.ChainId = &id + } + // Send the initiation message and stream content until a signature is returned + response := new(trezor.EthereumTxRequest) + if _, err := w.trezorExchange(request, response); err != nil { + return common.Address{}, nil, err + } + for response.DataLength != nil && int(*response.DataLength) <= len(data) { + chunk := data[:*response.DataLength] + data = data[*response.DataLength:] + + if _, err := w.trezorExchange(&trezor.EthereumTxAck{DataChunk: chunk}, response); err != nil { + return common.Address{}, nil, err + } + } + // Extract the Ethereum signature and do a sanity validation + if len(response.GetSignatureR()) == 0 || len(response.GetSignatureS()) == 0 || response.GetSignatureV() == 0 { + return common.Address{}, nil, errors.New("reply lacks signature") + } + signature := append(append(response.GetSignatureR(), response.GetSignatureS()...), byte(response.GetSignatureV())) + + // Create the correct signer and signature transform based on the chain ID + var signer types.Signer + if chainID == nil { + signer = new(types.HomesteadSigner) + } else { + signer = types.NewEIP155Signer(chainID) + signature[64] = signature[64] - byte(chainID.Uint64()*2+35) + } + // Inject the final signature into the transaction and sanity check the sender + signed, err := tx.WithSignature(signer, signature) + if err != nil { + return common.Address{}, nil, err + } + sender, err := types.Sender(signer, signed) + if err != nil { + return common.Address{}, nil, err + } + return sender, signed, nil +} + +// trezorExchange performs a data exchange with the Trezor wallet, sending it a +// message and retrieving the response. If multiple responses are possible, the +// method will also return the index of the destination object used. +func (w *trezorDriver) trezorExchange(req proto.Message, results ...proto.Message) (int, error) { + // Construct the original message payload to chunk up + data, err := proto.Marshal(req) + if err != nil { + return 0, err + } + payload := make([]byte, 8+len(data)) + copy(payload, []byte{0x23, 0x23}) + binary.BigEndian.PutUint16(payload[2:], trezor.Type(req)) + binary.BigEndian.PutUint32(payload[4:], uint32(len(data))) + copy(payload[8:], data) + + // Stream all the chunks to the device + chunk := make([]byte, 64) + chunk[0] = 0x3f // Report ID magic number + + for len(payload) > 0 { + // Construct the new message to stream, padding with zeroes if needed + if len(payload) > 63 { + copy(chunk[1:], payload[:63]) + payload = payload[63:] + } else { + copy(chunk[1:], payload) + copy(chunk[1+len(payload):], make([]byte, 63-len(payload))) + payload = nil + } + // Send over to the device + w.log.Trace("Data chunk sent to the Trezor", "chunk", hexutil.Bytes(chunk)) + if _, err := w.device.Write(chunk); err != nil { + return 0, err + } + } + // Stream the reply back from the wallet in 64 byte chunks + var ( + kind uint16 + reply []byte + ) + for { + // Read the next chunk from the Trezor wallet + if _, err := io.ReadFull(w.device, chunk); err != nil { + return 0, err + } + w.log.Trace("Data chunk received from the Trezor", "chunk", hexutil.Bytes(chunk)) + + // Make sure the transport header matches + if chunk[0] != 0x3f || (len(reply) == 0 && (chunk[1] != 0x23 || chunk[2] != 0x23)) { + return 0, errTrezorReplyInvalidHeader + } + // If it's the first chunk, retrieve the reply message type and total message length + var payload []byte + + if len(reply) == 0 { + kind = binary.BigEndian.Uint16(chunk[3:5]) + reply = make([]byte, 0, int(binary.BigEndian.Uint32(chunk[5:9]))) + payload = chunk[9:] + } else { + payload = chunk[1:] + } + // Append to the reply and stop when filled up + if left := cap(reply) - len(reply); left > len(payload) { + reply = append(reply, payload...) + } else { + reply = append(reply, payload[:left]...) + break + } + } + // Try to parse the reply into the requested reply message + if kind == uint16(trezor.MessageType_MessageType_Failure) { + // Trezor returned a failure, extract and return the message + failure := new(trezor.Failure) + if err := proto.Unmarshal(reply, failure); err != nil { + return 0, err + } + return 0, errors.New("trezor: " + failure.GetMessage()) + } + if kind == uint16(trezor.MessageType_MessageType_ButtonRequest) { + // Trezor is waiting for user confirmation, ack and wait for the next message + return w.trezorExchange(&trezor.ButtonAck{}, results...) + } + for i, res := range results { + if trezor.Type(res) == kind { + return i, proto.Unmarshal(reply, res) + } + } + expected := make([]string, len(results)) + for i, res := range results { + expected[i] = trezor.Name(trezor.Type(res)) + } + return 0, fmt.Errorf("trezor: expected reply types %s, got %s", expected, trezor.Name(kind)) +} diff --git a/accounts/usbwallet/usbwallet.go b/accounts/usbwallet/usbwallet.go deleted file mode 100644 index 938ab1e6a..000000000 --- a/accounts/usbwallet/usbwallet.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017 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 usbwallet implements support for USB hardware wallets. -package usbwallet - -// deviceID is a combined vendor/product identifier to uniquely identify a USB -// hardware device. -type deviceID struct { - Vendor uint16 // The Vendor identifer - Product uint16 // The Product identifier -} diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go new file mode 100644 index 000000000..8b3b5a522 --- /dev/null +++ b/accounts/usbwallet/wallet.go @@ -0,0 +1,562 @@ +// Copyright 2017 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 usbwallet implements support for USB hardware wallets. +package usbwallet + +import ( + "context" + "fmt" + "io" + "math/big" + "sync" + "time" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/karalabe/hid" +) + +// Maximum time between wallet health checks to detect USB unplugs. +const heartbeatCycle = time.Second + +// Minimum time to wait between self derivation attempts, even it the user is +// requesting accounts like crazy. +const selfDeriveThrottling = time.Second + +// driver defines the vendor specific functionality hardware wallets instances +// must implement to allow using them with the wallet lifecycle management. +type driver interface { + // Status returns a textual status to aid the user in the current state of the + // wallet. It also returns an error indicating any failure the wallet might have + // encountered. + Status() (string, error) + + // Open initializes access to a wallet instance. The passphrase parameter may + // or may not be used by the implementation of a particular wallet instance. + Open(device io.ReadWriter, passphrase string) error + + // Close releases any resources held by an open wallet instance. + Close() error + + // Heartbeat performs a sanity check against the hardware wallet to see if it + // is still online and healthy. + Heartbeat() error + + // Derive sends a derivation request to the USB device and returns the Ethereum + // address located on that path. + Derive(path accounts.DerivationPath) (common.Address, error) + + // SignTx sends the transaction to the USB device and waits for the user to confirm + // or deny the transaction. + SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) +} + +// wallet represents the common functionality shared by all USB hardware +// wallets to prevent reimplementing the same complex maintenance mechanisms +// for different vendors. +type wallet struct { + hub *Hub // USB hub scanning + driver driver // Hardware implementation of the low level device operations + url *accounts.URL // Textual URL uniquely identifying this wallet + + info hid.DeviceInfo // Known USB device infos about the wallet + device *hid.Device // USB device advertising itself as a hardware wallet + + accounts []accounts.Account // List of derive accounts pinned on the hardware wallet + paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations + + deriveNextPath accounts.DerivationPath // Next derivation path for account auto-discovery + deriveNextAddr common.Address // Next derived account address for auto-discovery + deriveChain ethereum.ChainStateReader // Blockchain state reader to discover used account with + deriveReq chan chan struct{} // Channel to request a self-derivation on + deriveQuit chan chan error // Channel to terminate the self-deriver with + + healthQuit chan chan error + + // Locking a hardware wallet is a bit special. Since hardware devices are lower + // performing, any communication with them might take a non negligible amount of + // time. Worse still, waiting for user confirmation can take arbitrarily long, + // but exclusive communication must be upheld during. Locking the entire wallet + // in the mean time however would stall any parts of the system that don't want + // to communicate, just read some state (e.g. list the accounts). + // + // As such, a hardware wallet needs two locks to function correctly. A state + // lock can be used to protect the wallet's software-side internal state, which + // must not be held exlusively during hardware communication. A communication + // lock can be used to achieve exclusive access to the device itself, this one + // however should allow "skipping" waiting for operations that might want to + // use the device, but can live without too (e.g. account self-derivation). + // + // Since we have two locks, it's important to know how to properly use them: + // - Communication requires the `device` to not change, so obtaining the + // commsLock should be done after having a stateLock. + // - Communication must not disable read access to the wallet state, so it + // must only ever hold a *read* lock to stateLock. + commsLock chan struct{} // Mutex (buf=1) for the USB comms without keeping the state locked + stateLock sync.RWMutex // Protects read and write access to the wallet struct fields + + log log.Logger // Contextual logger to tag the base with its id +} + +// URL implements accounts.Wallet, returning the URL of the USB hardware device. +func (w *wallet) URL() accounts.URL { + return *w.url // Immutable, no need for a lock +} + +// Status implements accounts.Wallet, returning a custom status message from the +// underlying vendor-specific hardware wallet implementation. +func (w *wallet) Status() (string, error) { + w.stateLock.RLock() // No device communication, state lock is enough + defer w.stateLock.RUnlock() + + status, failure := w.driver.Status() + if w.device == nil { + return "Closed", failure + } + return status, failure +} + +// Open implements accounts.Wallet, attempting to open a USB connection to the +// hardware wallet. +func (w *wallet) Open(passphrase string) error { + w.stateLock.Lock() // State lock is enough since there's no connection yet at this point + defer w.stateLock.Unlock() + + // If the device was already opened once, refuse to try again + if w.paths != nil { + return accounts.ErrWalletAlreadyOpen + } + // Make sure the actual device connection is done only once + if w.device == nil { + device, err := w.info.Open() + if err != nil { + return err + } + w.device = device + w.commsLock = make(chan struct{}, 1) + w.commsLock <- struct{}{} // Enable lock + } + // Delegate device initialization to the underlying driver + if err := w.driver.Open(w.device, passphrase); err != nil { + return err + } + // Connection successful, start life-cycle management + w.paths = make(map[common.Address]accounts.DerivationPath) + + w.deriveReq = make(chan chan struct{}) + w.deriveQuit = make(chan chan error) + w.healthQuit = make(chan chan error) + + go w.heartbeat() + go w.selfDerive() + + // Notify anyone listening for wallet events that a new device is accessible + go w.hub.updateFeed.Send(accounts.WalletEvent{Wallet: w, Kind: accounts.WalletOpened}) + + return nil +} + +// heartbeat is a health check loop for the USB wallets to periodically verify +// whether they are still present or if they malfunctioned. +func (w *wallet) heartbeat() { + w.log.Debug("USB wallet health-check started") + defer w.log.Debug("USB wallet health-check stopped") + + // Execute heartbeat checks until termination or error + var ( + errc chan error + err error + ) + for errc == nil && err == nil { + // Wait until termination is requested or the heartbeat cycle arrives + select { + case errc = <-w.healthQuit: + // Termination requested + continue + case <-time.After(heartbeatCycle): + // Heartbeat time + } + // Execute a tiny data exchange to see responsiveness + w.stateLock.RLock() + if w.device == nil { + // Terminated while waiting for the lock + w.stateLock.RUnlock() + continue + } + <-w.commsLock // Don't lock state while resolving version + err = w.driver.Heartbeat() + w.commsLock <- struct{}{} + w.stateLock.RUnlock() + + if err != nil { + w.stateLock.Lock() // Lock state to tear the wallet down + w.close() + w.stateLock.Unlock() + } + // Ignore non hardware related errors + err = nil + } + // In case of error, wait for termination + if err != nil { + w.log.Debug("USB wallet health-check failed", "err", err) + errc = <-w.healthQuit + } + errc <- err +} + +// Close implements accounts.Wallet, closing the USB connection to the device. +func (w *wallet) Close() error { + // Ensure the wallet was opened + w.stateLock.RLock() + hQuit, dQuit := w.healthQuit, w.deriveQuit + w.stateLock.RUnlock() + + // Terminate the health checks + var herr error + if hQuit != nil { + errc := make(chan error) + hQuit <- errc + herr = <-errc // Save for later, we *must* close the USB + } + // Terminate the self-derivations + var derr error + if dQuit != nil { + errc := make(chan error) + dQuit <- errc + derr = <-errc // Save for later, we *must* close the USB + } + // Terminate the device connection + w.stateLock.Lock() + defer w.stateLock.Unlock() + + w.healthQuit = nil + w.deriveQuit = nil + w.deriveReq = nil + + if err := w.close(); err != nil { + return err + } + if herr != nil { + return herr + } + return derr +} + +// close is the internal wallet closer that terminates the USB connection and +// resets all the fields to their defaults. +// +// Note, close assumes the state lock is held! +func (w *wallet) close() error { + // Allow duplicate closes, especially for health-check failures + if w.device == nil { + return nil + } + // Close the device, clear everything, then return + w.device.Close() + w.device = nil + + w.accounts, w.paths = nil, nil + w.driver.Close() + + return nil +} + +// Accounts implements accounts.Wallet, returning the list of accounts pinned to +// the USB hardware wallet. If self-derivation was enabled, the account list is +// periodically expanded based on current chain state. +func (w *wallet) Accounts() []accounts.Account { + // Attempt self-derivation if it's running + reqc := make(chan struct{}, 1) + select { + case w.deriveReq <- reqc: + // Self-derivation request accepted, wait for it + <-reqc + default: + // Self-derivation offline, throttled or busy, skip + } + // Return whatever account list we ended up with + w.stateLock.RLock() + defer w.stateLock.RUnlock() + + cpy := make([]accounts.Account, len(w.accounts)) + copy(cpy, w.accounts) + return cpy +} + +// selfDerive is an account derivation loop that upon request attempts to find +// new non-zero accounts. +func (w *wallet) selfDerive() { + w.log.Debug("USB wallet self-derivation started") + defer w.log.Debug("USB wallet self-derivation stopped") + + // Execute self-derivations until termination or error + var ( + reqc chan struct{} + errc chan error + err error + ) + for errc == nil && err == nil { + // Wait until either derivation or termination is requested + select { + case errc = <-w.deriveQuit: + // Termination requested + continue + case reqc = <-w.deriveReq: + // Account discovery requested + } + // Derivation needs a chain and device access, skip if either unavailable + w.stateLock.RLock() + if w.device == nil || w.deriveChain == nil { + w.stateLock.RUnlock() + reqc <- struct{}{} + continue + } + select { + case <-w.commsLock: + default: + w.stateLock.RUnlock() + reqc <- struct{}{} + continue + } + // Device lock obtained, derive the next batch of accounts + var ( + accs []accounts.Account + paths []accounts.DerivationPath + + nextAddr = w.deriveNextAddr + nextPath = w.deriveNextPath + + context = context.Background() + ) + for empty := false; !empty; { + // Retrieve the next derived Ethereum account + if nextAddr == (common.Address{}) { + if nextAddr, err = w.driver.Derive(nextPath); err != nil { + w.log.Warn("USB wallet account derivation failed", "err", err) + break + } + } + // Check the account's status against the current chain state + var ( + balance *big.Int + nonce uint64 + ) + balance, err = w.deriveChain.BalanceAt(context, nextAddr, nil) + if err != nil { + w.log.Warn("USB wallet balance retrieval failed", "err", err) + break + } + nonce, err = w.deriveChain.NonceAt(context, nextAddr, nil) + if err != nil { + w.log.Warn("USB wallet nonce retrieval failed", "err", err) + break + } + // If the next account is empty, stop self-derivation, but add it nonetheless + if balance.Sign() == 0 && nonce == 0 { + empty = true + } + // We've just self-derived a new account, start tracking it locally + path := make(accounts.DerivationPath, len(nextPath)) + copy(path[:], nextPath[:]) + paths = append(paths, path) + + account := accounts.Account{ + Address: nextAddr, + URL: accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)}, + } + accs = append(accs, account) + + // Display a log message to the user for new (or previously empty accounts) + if _, known := w.paths[nextAddr]; !known || (!empty && nextAddr == w.deriveNextAddr) { + w.log.Info("USB wallet discovered new account", "address", nextAddr, "path", path, "balance", balance, "nonce", nonce) + } + // Fetch the next potential account + if !empty { + nextAddr = common.Address{} + nextPath[len(nextPath)-1]++ + } + } + // Self derivation complete, release device lock + w.commsLock <- struct{}{} + w.stateLock.RUnlock() + + // Insert any accounts successfully derived + w.stateLock.Lock() + for i := 0; i < len(accs); i++ { + if _, ok := w.paths[accs[i].Address]; !ok { + w.accounts = append(w.accounts, accs[i]) + w.paths[accs[i].Address] = paths[i] + } + } + // Shift the self-derivation forward + // TODO(karalabe): don't overwrite changes from wallet.SelfDerive + w.deriveNextAddr = nextAddr + w.deriveNextPath = nextPath + w.stateLock.Unlock() + + // Notify the user of termination and loop after a bit of time (to avoid trashing) + reqc <- struct{}{} + if err == nil { + select { + case errc = <-w.deriveQuit: + // Termination requested, abort + case <-time.After(selfDeriveThrottling): + // Waited enough, willing to self-derive again + } + } + } + // In case of error, wait for termination + if err != nil { + w.log.Debug("USB wallet self-derivation failed", "err", err) + errc = <-w.deriveQuit + } + errc <- err +} + +// Contains implements accounts.Wallet, returning whether a particular account is +// or is not pinned into this wallet instance. Although we could attempt to resolve +// unpinned accounts, that would be an non-negligible hardware operation. +func (w *wallet) Contains(account accounts.Account) bool { + w.stateLock.RLock() + defer w.stateLock.RUnlock() + + _, exists := w.paths[account.Address] + return exists +} + +// Derive implements accounts.Wallet, deriving a new account at the specific +// derivation path. If pin is set to true, the account will be added to the list +// of tracked accounts. +func (w *wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) { + // Try to derive the actual account and update its URL if successful + w.stateLock.RLock() // Avoid device disappearing during derivation + + if w.device == nil { + w.stateLock.RUnlock() + return accounts.Account{}, accounts.ErrWalletClosed + } + <-w.commsLock // Avoid concurrent hardware access + address, err := w.driver.Derive(path) + w.commsLock <- struct{}{} + + w.stateLock.RUnlock() + + // If an error occurred or no pinning was requested, return + if err != nil { + return accounts.Account{}, err + } + account := accounts.Account{ + Address: address, + URL: accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)}, + } + if !pin { + return account, nil + } + // Pinning needs to modify the state + w.stateLock.Lock() + defer w.stateLock.Unlock() + + if _, ok := w.paths[address]; !ok { + w.accounts = append(w.accounts, account) + w.paths[address] = path + } + return account, nil +} + +// SelfDerive implements accounts.Wallet, trying to discover accounts that the +// user used previously (based on the chain state), but ones that he/she did not +// explicitly pin to the wallet manually. To avoid chain head monitoring, self +// derivation only runs during account listing (and even then throttled). +func (w *wallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) { + w.stateLock.Lock() + defer w.stateLock.Unlock() + + w.deriveNextPath = make(accounts.DerivationPath, len(base)) + copy(w.deriveNextPath[:], base[:]) + + w.deriveNextAddr = common.Address{} + w.deriveChain = chain +} + +// SignHash implements accounts.Wallet, however signing arbitrary data is not +// supported for hardware wallets, so this method will always return an error. +func (w *wallet) SignHash(account accounts.Account, hash []byte) ([]byte, error) { + return nil, accounts.ErrNotSupported +} + +// SignTx implements accounts.Wallet. It sends the transaction over to the Ledger +// wallet to request a confirmation from the user. It returns either the signed +// transaction or a failure if the user denied the transaction. +// +// Note, if the version of the Ethereum application running on the Ledger wallet is +// too old to sign EIP-155 transactions, but such is requested nonetheless, an error +// will be returned opposed to silently signing in Homestead mode. +func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + w.stateLock.RLock() // Comms have own mutex, this is for the state fields + defer w.stateLock.RUnlock() + + // If the wallet is closed, abort + if w.device == nil { + return nil, accounts.ErrWalletClosed + } + // Make sure the requested account is contained within + path, ok := w.paths[account.Address] + if !ok { + return nil, accounts.ErrUnknownAccount + } + // All infos gathered and metadata checks out, request signing + <-w.commsLock + defer func() { w.commsLock <- struct{}{} }() + + // Ensure the device isn't screwed with while user confirmation is pending + // TODO(karalabe): remove if hotplug lands on Windows + w.hub.commsLock.Lock() + w.hub.commsPend++ + w.hub.commsLock.Unlock() + + defer func() { + w.hub.commsLock.Lock() + w.hub.commsPend-- + w.hub.commsLock.Unlock() + }() + // Sign the transaction and verify the sender to avoid hardware fault surprises + sender, signed, err := w.driver.SignTx(path, tx, chainID) + if err != nil { + return nil, err + } + if sender != account.Address { + return nil, fmt.Errorf("signer mismatch: expected %s, got %s", account.Address.Hex(), sender.Hex()) + } + return signed, nil +} + +// SignHashWithPassphrase implements accounts.Wallet, however signing arbitrary +// data is not supported for Ledger wallets, so this method will always return +// an error. +func (w *wallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) { + return w.SignHash(account, hash) +} + +// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given +// transaction with the given account using passphrase as extra authentication. +// Since USB wallets don't rely on passphrases, these are silently ignored. +func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + return w.SignTx(account, tx, chainID) +} diff --git a/build/ci.go b/build/ci.go index 6a52077d4..6fe03db71 100644 --- a/build/ci.go +++ b/build/ci.go @@ -119,7 +119,8 @@ var ( // Distros for which packages are created. // Note: vivid is unsupported because there is no golang-1.6 package for it. // Note: wily is unsupported because it was officially deprecated on lanchpad. - debDistros = []string{"trusty", "xenial", "yakkety", "zesty"} + // Note: yakkety is unsupported because it was officially deprecated on lanchpad. + debDistros = []string{"trusty", "xenial", "zesty"} ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) @@ -249,10 +250,7 @@ func goTool(subcmd string, args ...string) *exec.Cmd { } func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd { - gocmd := filepath.Join(runtime.GOROOT(), "bin", "go") - cmd := exec.Command(gocmd, subcmd) - cmd.Args = append(cmd.Args, args...) - + cmd := build.GoTool(subcmd, args...) if subcmd == "build" || subcmd == "install" || subcmd == "test" { // Go CGO has a Windows linker error prior to 1.8 (https://github.com/golang/go/issues/8756). // Work around issue by allowing multiple definitions for <1.8 builds. diff --git a/cmd/evm/disasm.go b/cmd/evm/disasm.go index a78b2a8e1..4a442cf78 100644 --- a/cmd/evm/disasm.go +++ b/cmd/evm/disasm.go @@ -46,8 +46,5 @@ func disasmCmd(ctx *cli.Context) error { code := strings.TrimSpace(string(in[:])) fmt.Printf("%v\n", code) - if err = asm.PrintDisassembled(code); err != nil { - return err - } - return nil + return asm.PrintDisassembled(code) } diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 1892ae3d3..a2e3b048e 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -53,7 +53,7 @@ var ( } CodeFileFlag = cli.StringFlag{ Name: "codefile", - Usage: "file containing EVM code", + Usage: "File containing EVM code. If '-' is specified, code is read from stdin ", } GasFlag = cli.Uint64Flag{ Name: "gas", @@ -102,6 +102,10 @@ var ( Name: "sender", Usage: "The transaction origin", } + ReceiverFlag = cli.StringFlag{ + Name: "receiver", + Usage: "The transaction receiver (execution context)", + } DisableMemoryFlag = cli.BoolFlag{ Name: "nomemory", Usage: "disable memory output", @@ -131,6 +135,7 @@ func init() { GenesisFlag, MachineFlag, SenderFlag, + ReceiverFlag, DisableMemoryFlag, DisableStackFlag, } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 3f95a0c93..ae5678110 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -84,6 +84,7 @@ func runCmd(ctx *cli.Context) error { statedb *state.StateDB chainConfig *params.ChainConfig sender = common.StringToAddress("sender") + receiver = common.StringToAddress("receiver") ) if ctx.GlobalBool(MachineFlag.Name) { tracer = NewJSONLogger(logconfig, os.Stdout) @@ -104,46 +105,52 @@ func runCmd(ctx *cli.Context) error { if ctx.GlobalString(SenderFlag.Name) != "" { sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) } - statedb.CreateAccount(sender) + if ctx.GlobalString(ReceiverFlag.Name) != "" { + receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) + } + var ( code []byte ret []byte err error ) - if fn := ctx.Args().First(); len(fn) > 0 { + // The '--code' or '--codefile' flag overrides code in state + if ctx.GlobalString(CodeFileFlag.Name) != "" { + var hexcode []byte + var err error + // If - is specified, it means that code comes from stdin + if ctx.GlobalString(CodeFileFlag.Name) == "-" { + //Try reading from stdin + if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil { + fmt.Printf("Could not load code from stdin: %v\n", err) + os.Exit(1) + } + } else { + // Codefile with hex assembly + if hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)); err != nil { + fmt.Printf("Could not load code from file: %v\n", err) + os.Exit(1) + } + } + code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) + + } else if ctx.GlobalString(CodeFlag.Name) != "" { + code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) + } else if fn := ctx.Args().First(); len(fn) > 0 { + // EASM-file to compile src, err := ioutil.ReadFile(fn) if err != nil { return err } - bin, err := compiler.Compile(fn, src, false) if err != nil { return err } code = common.Hex2Bytes(bin) - } else if ctx.GlobalString(CodeFlag.Name) != "" { - code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) - } else { - var hexcode []byte - if ctx.GlobalString(CodeFileFlag.Name) != "" { - var err error - hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)) - if err != nil { - fmt.Printf("Could not load code from file: %v\n", err) - os.Exit(1) - } - } else { - var err error - hexcode, err = ioutil.ReadAll(os.Stdin) - if err != nil { - fmt.Printf("Could not load code from stdin: %v\n", err) - os.Exit(1) - } - } - code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) } + initialGas := ctx.GlobalUint64(GasFlag.Name) runtimeConfig := runtime.Config{ Origin: sender, @@ -180,9 +187,9 @@ func runCmd(ctx *cli.Context) error { input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig) } else { - receiver := common.StringToAddress("receiver") - statedb.SetCode(receiver, code) - + if len(code) > 0 { + statedb.SetCode(receiver, code) + } ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig) } execTime := time.Since(tstart) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index c06c4365b..8cd62441e 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -413,8 +413,9 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { // Iterate over all the files and look for Ethereum addresses var address common.Address for _, file := range gist.Files { - if len(file.Content) == 2+common.AddressLength*2 { - address = common.HexToAddress(file.Content) + content := strings.TrimSpace(file.Content) + if len(content) == 2+common.AddressLength*2 { + address = common.HexToAddress(content) } } if address == (common.Address{}) { diff --git a/cmd/geth/accountcmd_test.go b/cmd/geth/accountcmd_test.go index e146323ee..66e3e02a4 100644 --- a/cmd/geth/accountcmd_test.go +++ b/cmd/geth/accountcmd_test.go @@ -146,7 +146,7 @@ Passphrase: {{.InputLine "foobar"}} wantMessages := []string{ "Unlocked account", - "=0xf466859ead1932d743d622cb74fc058882e8648a", + "=0xf466859eAD1932D743d622CB74FC058882E8648A", } for _, m := range wantMessages { if !strings.Contains(geth.StderrText(), m) { @@ -191,8 +191,8 @@ Passphrase: {{.InputLine "foobar"}} wantMessages := []string{ "Unlocked account", - "=0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8", - "=0x289d485d9771714cce91d3393d764e1311907acc", + "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", + "=0x289d485D9771714CCe91D3393D764E1311907ACc", } for _, m := range wantMessages { if !strings.Contains(geth.StderrText(), m) { @@ -211,8 +211,8 @@ func TestUnlockFlagPasswordFile(t *testing.T) { wantMessages := []string{ "Unlocked account", - "=0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8", - "=0x289d485d9771714cce91d3393d764e1311907acc", + "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", + "=0x289d485D9771714CCe91D3393D764E1311907ACc", } for _, m := range wantMessages { if !strings.Contains(geth.StderrText(), m) { @@ -261,7 +261,7 @@ In order to avoid this warning, you need to remove the following duplicate key f wantMessages := []string{ "Unlocked account", - "=0xf466859ead1932d743d622cb74fc058882e8648a", + "=0xf466859eAD1932D743d622CB74FC058882E8648A", } for _, m := range wantMessages { if !strings.Contains(geth.StderrText(), m) { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 607414bbb..8166c9ce8 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -21,6 +21,7 @@ import ( "fmt" "os" "runtime" + "sort" "strings" "time" @@ -67,6 +68,8 @@ var ( utils.EthashDatasetsInMemoryFlag, utils.EthashDatasetsOnDiskFlag, utils.TxPoolNoLocalsFlag, + utils.TxPoolJournalFlag, + utils.TxPoolRejournalFlag, utils.TxPoolPriceLimitFlag, utils.TxPoolPriceBumpFlag, utils.TxPoolAccountSlotsFlag, @@ -155,6 +158,7 @@ func init() { attachCommand, javascriptCommand, // See misccmd.go: + makecacheCommand, makedagCommand, versionCommand, bugCommand, @@ -162,6 +166,7 @@ func init() { // See config.go dumpConfigCommand, } + sort.Sort(cli.CommandsByName(app.Commands)) app.Flags = append(app.Flags, nodeFlags...) app.Flags = append(app.Flags, rpcFlags...) @@ -234,24 +239,30 @@ func startNode(ctx *cli.Context, stack *node.Node) { } stateReader := ethclient.NewClient(rpcClient) - // Open and self derive any wallets already attached + // Open any wallets already attached for _, wallet := range stack.AccountManager().Wallets() { if err := wallet.Open(""); err != nil { log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err) - } else { - wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader) } } // Listen for wallet event till termination for event := range events { - if event.Arrive { + switch event.Kind { + case accounts.WalletArrived: if err := event.Wallet.Open(""); err != nil { log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err) + } + case accounts.WalletOpened: + status, _ := event.Wallet.Status() + log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) + + if event.Wallet.URL().Scheme == "ledger" { + event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader) } else { - log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", event.Wallet.Status()) event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader) } - } else { + + case accounts.WalletDropped: log.Info("Old wallet dropped", "url", event.Wallet.URL()) event.Wallet.Close() } diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go index 62b93d65a..2e68dcda3 100644 --- a/cmd/geth/misccmd.go +++ b/cmd/geth/misccmd.go @@ -18,9 +18,7 @@ package main import ( "fmt" - "io/ioutil" "os" - "path/filepath" "runtime" "strconv" "strings" @@ -33,14 +31,27 @@ import ( ) var ( + makecacheCommand = cli.Command{ + Action: utils.MigrateFlags(makecache), + Name: "makecache", + Usage: "Generate ethash verification cache (for testing)", + ArgsUsage: "<blockNum> <outputDir>", + Category: "MISCELLANEOUS COMMANDS", + Description: ` +The makecache command generates an ethash cache in <outputDir>. + +This command exists to support the system testing project. +Regular users do not need to execute it. +`, + } makedagCommand = cli.Command{ Action: utils.MigrateFlags(makedag), Name: "makedag", - Usage: "Generate ethash DAG (for testing)", + Usage: "Generate ethash mining DAG (for testing)", ArgsUsage: "<blockNum> <outputDir>", Category: "MISCELLANEOUS COMMANDS", Description: ` -The makedag command generates an ethash DAG in /tmp/dag. +The makedag command generates an ethash DAG in <outputDir>. This command exists to support the system testing project. Regular users do not need to execute it. @@ -65,33 +76,33 @@ The output of this command is supposed to be machine-readable. } ) +// makecache generates an ethash verification cache into the provided folder. +func makecache(ctx *cli.Context) error { + args := ctx.Args() + if len(args) != 2 { + utils.Fatalf(`Usage: geth makecache <block number> <outputdir>`) + } + block, err := strconv.ParseUint(args[0], 0, 64) + if err != nil { + utils.Fatalf("Invalid block number: %v", err) + } + ethash.MakeCache(block, args[1]) + + return nil +} + +// makedag generates an ethash mining DAG into the provided folder. func makedag(ctx *cli.Context) error { args := ctx.Args() - wrongArgs := func() { + if len(args) != 2 { utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`) } - switch { - case len(args) == 2: - blockNum, err := strconv.ParseUint(args[0], 0, 64) - dir := args[1] - if err != nil { - wrongArgs() - } else { - dir = filepath.Clean(dir) - // seems to require a trailing slash - if !strings.HasSuffix(dir, "/") { - dir = dir + "/" - } - _, err = ioutil.ReadDir(dir) - if err != nil { - utils.Fatalf("Can't find dir") - } - fmt.Println("making DAG, this could take awhile...") - ethash.MakeDataset(blockNum, dir) - } - default: - wrongArgs() + block, err := strconv.ParseUint(args[0], 0, 64) + if err != nil { + utils.Fatalf("Invalid block number: %v", err) } + ethash.MakeDataset(block, args[1]) + return nil } diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 275aad674..80861d852 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -96,6 +96,8 @@ var AppHelpFlagGroups = []flagGroup{ Name: "TRANSACTION POOL", Flags: []cli.Flag{ utils.TxPoolNoLocalsFlag, + utils.TxPoolJournalFlag, + utils.TxPoolRejournalFlag, utils.TxPoolPriceLimitFlag, utils.TxPoolPriceBumpFlag, utils.TxPoolAccountSlotsFlag, diff --git a/cmd/puppeth/module_dashboard.go b/cmd/puppeth/module_dashboard.go index 17f119111..1cf6cab79 100644 --- a/cmd/puppeth/module_dashboard.go +++ b/cmd/puppeth/module_dashboard.go @@ -425,6 +425,11 @@ services: - "{{.Port}}:80"{{else}} environment: - VIRTUAL_HOST={{.VHost}}{{end}} + logging: + driver: "json-file" + options: + max-size: "1m" + max-file: "10" restart: always ` diff --git a/cmd/puppeth/module_ethstats.go b/cmd/puppeth/module_ethstats.go index 571df1454..5d3fa5fc0 100644 --- a/cmd/puppeth/module_ethstats.go +++ b/cmd/puppeth/module_ethstats.go @@ -42,7 +42,7 @@ RUN \ WORKDIR /eth-netstats EXPOSE 3000 -RUN echo 'module.exports = {trusted: [{{.Trusted}}], banned: []};' > lib/utils/config.js +RUN echo 'module.exports = {trusted: [{{.Trusted}}], banned: [{{.Banned}}]};' > lib/utils/config.js CMD ["npm", "start"] ` @@ -59,25 +59,37 @@ services: - "{{.Port}}:3000"{{end}} environment: - WS_SECRET={{.Secret}}{{if .VHost}} - - VIRTUAL_HOST={{.VHost}}{{end}} + - VIRTUAL_HOST={{.VHost}}{{end}}{{if .Banned}} + - BANNED={{.Banned}}{{end}} + logging: + driver: "json-file" + options: + max-size: "1m" + max-file: "10" restart: always ` // deployEthstats deploys a new ethstats container to a remote machine via SSH, // docker and docker-compose. If an instance with the specified network name // already exists there, it will be overwritten! -func deployEthstats(client *sshClient, network string, port int, secret string, vhost string, trusted []string) ([]byte, error) { +func deployEthstats(client *sshClient, network string, port int, secret string, vhost string, trusted []string, banned []string) ([]byte, error) { // Generate the content to upload to the server workdir := fmt.Sprintf("%d", rand.Int63()) files := make(map[string][]byte) + trustedLabels := make([]string, len(trusted)) for i, address := range trusted { - trusted[i] = fmt.Sprintf("\"%s\"", address) + trustedLabels[i] = fmt.Sprintf("\"%s\"", address) + } + bannedLabels := make([]string, len(banned)) + for i, address := range banned { + bannedLabels[i] = fmt.Sprintf("\"%s\"", address) } dockerfile := new(bytes.Buffer) template.Must(template.New("").Parse(ethstatsDockerfile)).Execute(dockerfile, map[string]interface{}{ - "Trusted": strings.Join(trusted, ", "), + "Trusted": strings.Join(trustedLabels, ", "), + "Banned": strings.Join(bannedLabels, ", "), }) files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() @@ -87,6 +99,7 @@ func deployEthstats(client *sshClient, network string, port int, secret string, "Port": port, "Secret": secret, "VHost": vhost, + "Banned": strings.Join(banned, ","), }) files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() @@ -107,11 +120,12 @@ type ethstatsInfos struct { port int secret string config string + banned []string } // String implements the stringer interface. func (info *ethstatsInfos) String() string { - return fmt.Sprintf("host=%s, port=%d, secret=%s", info.host, info.port, info.secret) + return fmt.Sprintf("host=%s, port=%d, secret=%s, banned=%v", info.host, info.port, info.secret, info.banned) } // checkEthstats does a health-check against an ethstats server to verify whether @@ -145,6 +159,9 @@ func checkEthstats(client *sshClient, network string) (*ethstatsInfos, error) { if port != 80 && port != 443 { config += fmt.Sprintf(":%d", port) } + // Retrieve the IP blacklist + banned := strings.Split(infos.envvars["BANNED"], ",") + // Run a sanity check to see if the port is reachable if err = checkPort(host, port); err != nil { log.Warn("Ethstats service seems unreachable", "server", host, "port", port, "err", err) @@ -155,5 +172,6 @@ func checkEthstats(client *sshClient, network string) (*ethstatsInfos, error) { port: port, secret: secret, config: config, + banned: banned, }, nil } diff --git a/cmd/puppeth/module_faucet.go b/cmd/puppeth/module_faucet.go index 5a5dc6506..acf1e4324 100644 --- a/cmd/puppeth/module_faucet.go +++ b/cmd/puppeth/module_faucet.go @@ -82,6 +82,11 @@ services: - CAPTCHA_SECRET={{.CaptchaSecret}}{{if .VHost}} - VIRTUAL_HOST={{.VHost}} - VIRTUAL_PORT=8080{{end}} + logging: + driver: "json-file" + options: + max-size: "1m" + max-file: "10" restart: always ` diff --git a/cmd/puppeth/module_nginx.go b/cmd/puppeth/module_nginx.go index 0eac5ace5..fd6d1d74e 100644 --- a/cmd/puppeth/module_nginx.go +++ b/cmd/puppeth/module_nginx.go @@ -43,6 +43,11 @@ services: - "{{.Port}}:80" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + logging: + driver: "json-file" + options: + max-size: "1m" + max-file: "10" restart: always ` diff --git a/cmd/puppeth/module_node.go b/cmd/puppeth/module_node.go index ce1d34135..9fe97c892 100644 --- a/cmd/puppeth/module_node.go +++ b/cmd/puppeth/module_node.go @@ -68,6 +68,11 @@ services: - MINER_NAME={{.Etherbase}} - GAS_TARGET={{.GasTarget}} - GAS_PRICE={{.GasPrice}} + logging: + driver: "json-file" + options: + max-size: "1m" + max-file: "10" restart: always ` diff --git a/cmd/puppeth/ssh.go b/cmd/puppeth/ssh.go index 93668945c..26f846685 100644 --- a/cmd/puppeth/ssh.go +++ b/cmd/puppeth/ssh.go @@ -122,7 +122,7 @@ func dial(server string, pubkey []byte) (*sshClient, error) { } } // If a public key exists for this SSH server, check that it matches - if bytes.Compare(pubkey, key.Marshal()) == 0 { + if bytes.Equal(pubkey, key.Marshal()) { return nil } // We have a mismatch, forbid connecting diff --git a/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go index 51e64688e..518741279 100644 --- a/cmd/puppeth/wizard.go +++ b/cmd/puppeth/wizard.go @@ -22,6 +22,7 @@ import ( "fmt" "io/ioutil" "math/big" + "net" "os" "path/filepath" "sort" @@ -106,17 +107,15 @@ func (w *wizard) readString() string { // readDefaultString reads a single line from stdin, trimming if from spaces. If // an empty line is entered, the default value is returned. func (w *wizard) readDefaultString(def string) string { - for { - fmt.Printf("> ") - text, err := w.in.ReadString('\n') - if err != nil { - log.Crit("Failed to read user input", "err", err) - } - if text = strings.TrimSpace(text); text != "" { - return text - } - return def + fmt.Printf("> ") + text, err := w.in.ReadString('\n') + if err != nil { + log.Crit("Failed to read user input", "err", err) + } + if text = strings.TrimSpace(text); text != "" { + return text } + return def } // readInt reads a single line from stdin, trimming if from spaces, enforcing it @@ -162,6 +161,7 @@ func (w *wizard) readDefaultInt(def int) int { } } +/* // readFloat reads a single line from stdin, trimming if from spaces, enforcing it // to parse into a float. func (w *wizard) readFloat() float64 { @@ -182,6 +182,7 @@ func (w *wizard) readFloat() float64 { return val } } +*/ // readDefaultFloat reads a single line from stdin, trimming if from spaces, enforcing // it to parse into a float. If an empty line is entered, the default value is returned. @@ -207,15 +208,13 @@ func (w *wizard) readDefaultFloat(def float64) float64 { // readPassword reads a single line from stdin, trimming it from the trailing new // line and returns it. The input will not be echoed. func (w *wizard) readPassword() string { - for { - fmt.Printf("> ") - text, err := terminal.ReadPassword(int(syscall.Stdin)) - if err != nil { - log.Crit("Failed to read password", "err", err) - } - fmt.Println() - return string(text) + fmt.Printf("> ") + text, err := terminal.ReadPassword(int(syscall.Stdin)) + if err != nil { + log.Crit("Failed to read password", "err", err) } + fmt.Println() + return string(text) } // readAddress reads a single line from stdin, trimming if from spaces and converts @@ -279,3 +278,26 @@ func (w *wizard) readJSON() string { return string(blob) } } + +// readIPAddress reads a single line from stdin, trimming if from spaces and +// converts it to a network IP address. +func (w *wizard) readIPAddress() net.IP { + for { + // Read the IP address from the user + fmt.Printf("> ") + text, err := w.in.ReadString('\n') + if err != nil { + log.Crit("Failed to read user input", "err", err) + } + if text = strings.TrimSpace(text); text == "" { + return nil + } + // Make sure it looks ok and return it if so + ip := net.ParseIP(text) + if ip == nil { + log.Error("Invalid IP address, please retry") + continue + } + return ip + } +} diff --git a/cmd/puppeth/wizard_ethstats.go b/cmd/puppeth/wizard_ethstats.go index c117a6027..504d8fd9c 100644 --- a/cmd/puppeth/wizard_ethstats.go +++ b/cmd/puppeth/wizard_ethstats.go @@ -60,6 +60,22 @@ func (w *wizard) deployEthstats() { fmt.Printf("What should be the secret password for the API? (default = %s)\n", infos.secret) infos.secret = w.readDefaultString(infos.secret) } + // Gather any blacklists to ban from reporting + fmt.Println() + fmt.Printf("Keep existing IP %v blacklist (y/n)? (default = yes)\n", infos.banned) + if w.readDefaultString("y") != "y" { + infos.banned = nil + + fmt.Println() + fmt.Println("Which IP addresses should be blacklisted?") + for { + if ip := w.readIPAddress(); ip != nil { + infos.banned = append(infos.banned, ip.String()) + continue + } + break + } + } // Try to deploy the ethstats server on the host trusted := make([]string, 0, len(w.servers)) for _, client := range w.servers { @@ -67,7 +83,7 @@ func (w *wizard) deployEthstats() { trusted = append(trusted, client.address) } } - if out, err := deployEthstats(client, w.network, infos.port, infos.secret, infos.host, trusted); err != nil { + if out, err := deployEthstats(client, w.network, infos.port, infos.secret, infos.host, trusted, infos.banned); err != nil { log.Error("Failed to deploy ethstats container", "err", err) if len(out) > 0 { fmt.Printf("%s\n", out) diff --git a/cmd/puppeth/wizard_network.go b/cmd/puppeth/wizard_network.go index 0455e1ef3..ff2ff74f5 100644 --- a/cmd/puppeth/wizard_network.go +++ b/cmd/puppeth/wizard_network.go @@ -71,22 +71,20 @@ func (w *wizard) makeServer() string { fmt.Println() fmt.Println("Please enter remote server's address:") - for { - // Read and fial the server to ensure docker is present - input := w.readString() - - client, err := dial(input, nil) - if err != nil { - log.Error("Server not ready for puppeth", "err", err) - return "" - } - // All checks passed, start tracking the server - w.servers[input] = client - w.conf.Servers[input] = client.pubkey - w.conf.flush() + // Read and fial the server to ensure docker is present + input := w.readString() - return input + client, err := dial(input, nil) + if err != nil { + log.Error("Server not ready for puppeth", "err", err) + return "" } + // All checks passed, start tracking the server + w.servers[input] = client + w.conf.Servers[input] = client.pubkey + w.conf.flush() + + return input } // selectServer lists the user all the currnetly known servers to choose from, diff --git a/cmd/swarm/cleandb.go b/cmd/swarm/cleandb.go deleted file mode 100644 index 268076062..000000000 --- a/cmd/swarm/cleandb.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/swarm/storage" - "gopkg.in/urfave/cli.v1" -) - -func cleandb(ctx *cli.Context) { - args := ctx.Args() - if len(args) != 1 { - utils.Fatalf("Need path to chunks database as the first and only argument") - } - - chunkDbPath := args[0] - hash := storage.MakeHashFunc("SHA3") - dbStore, err := storage.NewDbStore(chunkDbPath, hash, 10000000, 0) - if err != nil { - utils.Fatalf("Cannot initialise dbstore: %v", err) - } - dbStore.Cleanup() -} diff --git a/cmd/swarm/db.go b/cmd/swarm/db.go new file mode 100644 index 000000000..dfd2d069b --- /dev/null +++ b/cmd/swarm/db.go @@ -0,0 +1,116 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. + +package main + +import ( + "fmt" + "io" + "os" + "path/filepath" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/swarm/storage" + "gopkg.in/urfave/cli.v1" +) + +func dbExport(ctx *cli.Context) { + args := ctx.Args() + if len(args) != 2 { + utils.Fatalf("invalid arguments, please specify both <chunkdb> (path to a local chunk database) and <file> (path to write the tar archive to, - for stdout)") + } + + store, err := openDbStore(args[0]) + if err != nil { + utils.Fatalf("error opening local chunk database: %s", err) + } + defer store.Close() + + var out io.Writer + if args[1] == "-" { + out = os.Stdout + } else { + f, err := os.Create(args[1]) + if err != nil { + utils.Fatalf("error opening output file: %s", err) + } + defer f.Close() + out = f + } + + count, err := store.Export(out) + if err != nil { + utils.Fatalf("error exporting local chunk database: %s", err) + } + + log.Info(fmt.Sprintf("successfully exported %d chunks", count)) +} + +func dbImport(ctx *cli.Context) { + args := ctx.Args() + if len(args) != 2 { + utils.Fatalf("invalid arguments, please specify both <chunkdb> (path to a local chunk database) and <file> (path to read the tar archive from, - for stdin)") + } + + store, err := openDbStore(args[0]) + if err != nil { + utils.Fatalf("error opening local chunk database: %s", err) + } + defer store.Close() + + var in io.Reader + if args[1] == "-" { + in = os.Stdin + } else { + f, err := os.Open(args[1]) + if err != nil { + utils.Fatalf("error opening input file: %s", err) + } + defer f.Close() + in = f + } + + count, err := store.Import(in) + if err != nil { + utils.Fatalf("error importing local chunk database: %s", err) + } + + log.Info(fmt.Sprintf("successfully imported %d chunks", count)) +} + +func dbClean(ctx *cli.Context) { + args := ctx.Args() + if len(args) != 1 { + utils.Fatalf("invalid arguments, please specify <chunkdb> (path to a local chunk database)") + } + + store, err := openDbStore(args[0]) + if err != nil { + utils.Fatalf("error opening local chunk database: %s", err) + } + defer store.Close() + + store.Cleanup() +} + +func openDbStore(path string) (*storage.DbStore, error) { + if _, err := os.Stat(filepath.Join(path, "CURRENT")); err != nil { + return nil, fmt.Errorf("invalid chunkdb path: %s", err) + } + hash := storage.MakeHashFunc("SHA3") + return storage.NewDbStore(path, hash, 10000000, 0) +} diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go index 4ae06a1c9..603fd9b94 100644 --- a/cmd/swarm/main.go +++ b/cmd/swarm/main.go @@ -25,6 +25,7 @@ import ( "os" "os/signal" "runtime" + "sort" "strconv" "strings" "syscall" @@ -240,15 +241,69 @@ Removes a path from the manifest }, }, { - Action: cleandb, + Name: "db", + Usage: "manage the local chunk database", + ArgsUsage: "db COMMAND", + Description: ` +Manage the local chunk database. +`, + Subcommands: []cli.Command{ + { + Action: dbExport, + Name: "export", + Usage: "export a local chunk database as a tar archive (use - to send to stdout)", + ArgsUsage: "<chunkdb> <file>", + Description: ` +Export a local chunk database as a tar archive (use - to send to stdout). + + swarm db export ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar + +The export may be quite large, consider piping the output through the Unix +pv(1) tool to get a progress bar: + + swarm db export ~/.ethereum/swarm/bzz-KEY/chunks - | pv > chunks.tar +`, + }, + { + Action: dbImport, + Name: "import", + Usage: "import chunks from a tar archive into a local chunk database (use - to read from stdin)", + ArgsUsage: "<chunkdb> <file>", + Description: ` +Import chunks from a tar archive into a local chunk database (use - to read from stdin). + + swarm db import ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar + +The import may be quite large, consider piping the input through the Unix +pv(1) tool to get a progress bar: + + pv chunks.tar | swarm db import ~/.ethereum/swarm/bzz-KEY/chunks - +`, + }, + { + Action: dbClean, + Name: "clean", + Usage: "remove corrupt entries from a local chunk database", + ArgsUsage: "<chunkdb>", + Description: ` +Remove corrupt entries from a local chunk database. +`, + }, + }, + }, + { + Action: func(ctx *cli.Context) { + utils.Fatalf("ERROR: 'swarm cleandb' has been removed, please use 'swarm db clean'.") + }, Name: "cleandb", - Usage: "Cleans database of corrupted entries", + Usage: "DEPRECATED: use 'swarm db clean'", ArgsUsage: " ", Description: ` -Cleans database of corrupted entries. +DEPRECATED: use 'swarm db clean'. `, }, } + sort.Sort(cli.CommandsByName(app.Commands)) app.Flags = []cli.Flag{ utils.IdentityFlag, diff --git a/cmd/swarm/run_test.go b/cmd/swarm/run_test.go index 05cbb27f1..aaaf9e1e5 100644 --- a/cmd/swarm/run_test.go +++ b/cmd/swarm/run_test.go @@ -161,6 +161,7 @@ func newTestNode(t *testing.T, dir string) *testNode { conf := &node.Config{ DataDir: dir, IPCPath: "bzzd.ipc", + NoUSB: true, } n, err := node.New(conf) if err != nil { diff --git a/cmd/swarm/upload_test.go b/cmd/swarm/upload_test.go index 5b74dd4f1..5656186e1 100644 --- a/cmd/swarm/upload_test.go +++ b/cmd/swarm/upload_test.go @@ -27,8 +27,6 @@ import ( // TestCLISwarmUp tests that running 'swarm up' makes the resulting file // available from all nodes via the HTTP API func TestCLISwarmUp(t *testing.T) { - t.Skip("flaky test") - // start 3 node cluster t.Log("starting 3 node cluster") cluster := newTestCluster(t, 3) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 0159364af..04728b5c6 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -213,6 +213,16 @@ var ( Name: "txpool.nolocals", Usage: "Disables price exemptions for locally submitted transactions", } + TxPoolJournalFlag = cli.StringFlag{ + Name: "txpool.journal", + Usage: "Disk journal for local transaction to survive node restarts", + Value: core.DefaultTxPoolConfig.Journal, + } + TxPoolRejournalFlag = cli.DurationFlag{ + Name: "txpool.rejournal", + Usage: "Time interval to regenerate the local transaction journal", + Value: core.DefaultTxPoolConfig.Rejournal, + } TxPoolPriceLimitFlag = cli.Uint64Flag{ Name: "txpool.pricelimit", Usage: "Minimum gas price limit to enforce for acceptance into the pool", @@ -838,6 +848,12 @@ func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) } + if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { + cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) + } + if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { + cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) + } if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) } @@ -1077,7 +1093,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai engine := ethash.NewFaker() if !ctx.GlobalBool(FakePoWFlag.Name) { - engine = ethash.New("", 1, 0, "", 1, 0) + engine = ethash.New( + stack.ResolvePath(eth.DefaultConfig.EthashCacheDir), eth.DefaultConfig.EthashCachesInMem, eth.DefaultConfig.EthashCachesOnDisk, + stack.ResolvePath(eth.DefaultConfig.EthashDatasetDir), eth.DefaultConfig.EthashDatasetsInMem, eth.DefaultConfig.EthashDatasetsOnDisk, + ) } config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) if err != nil { diff --git a/common/bitutil/compress_test.go b/common/bitutil/compress_test.go index 805ab0369..9bd1de103 100644 --- a/common/bitutil/compress_test.go +++ b/common/bitutil/compress_test.go @@ -121,20 +121,20 @@ func TestCompression(t *testing.T) { in := hexutil.MustDecode("0x4912385c0e7b64000000") out := hexutil.MustDecode("0x80fe4912385c0e7b64") - if data := CompressBytes(in); bytes.Compare(data, out) != 0 { + if data := CompressBytes(in); !bytes.Equal(data, out) { t.Errorf("encoding mismatch for sparse data: have %x, want %x", data, out) } - if data, err := DecompressBytes(out, len(in)); err != nil || bytes.Compare(data, in) != 0 { + if data, err := DecompressBytes(out, len(in)); err != nil || !bytes.Equal(data, in) { t.Errorf("decoding mismatch for sparse data: have %x, want %x, error %v", data, in, err) } // Check the the compression returns the input if the bitset encoding is longer in = hexutil.MustDecode("0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb") out = hexutil.MustDecode("0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb") - if data := CompressBytes(in); bytes.Compare(data, out) != 0 { + if data := CompressBytes(in); !bytes.Equal(data, out) { t.Errorf("encoding mismatch for dense data: have %x, want %x", data, out) } - if data, err := DecompressBytes(out, len(in)); err != nil || bytes.Compare(data, in) != 0 { + if data, err := DecompressBytes(out, len(in)); err != nil || !bytes.Equal(data, in) { t.Errorf("decoding mismatch for dense data: have %x, want %x, error %v", data, in, err) } // Check that decompressing a longer input than the target fails diff --git a/common/hexutil/json.go b/common/hexutil/json.go index 943288fad..11e14cae7 100644 --- a/common/hexutil/json.go +++ b/common/hexutil/json.go @@ -26,11 +26,10 @@ import ( ) var ( - textZero = []byte(`0x0`) - bytesT = reflect.TypeOf(Bytes(nil)) - bigT = reflect.TypeOf((*Big)(nil)) - uintT = reflect.TypeOf(Uint(0)) - uint64T = reflect.TypeOf(Uint64(0)) + bytesT = reflect.TypeOf(Bytes(nil)) + bigT = reflect.TypeOf((*Big)(nil)) + uintT = reflect.TypeOf(Uint(0)) + uint64T = reflect.TypeOf(Uint64(0)) ) // Bytes marshals/unmarshals as a JSON string with 0x prefix. diff --git a/common/types.go b/common/types.go index 803726634..eaf8352fb 100644 --- a/common/types.go +++ b/common/types.go @@ -24,6 +24,7 @@ import ( "reflect" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto/sha3" ) const ( @@ -163,7 +164,28 @@ func (a Address) Str() string { return string(a[:]) } func (a Address) Bytes() []byte { return a[:] } func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) } func (a Address) Hash() Hash { return BytesToHash(a[:]) } -func (a Address) Hex() string { return hexutil.Encode(a[:]) } + +// Hex returns an EIP55-compliant hex string representation of the address. +func (a Address) Hex() string { + unchecksummed := hex.EncodeToString(a[:]) + sha := sha3.NewKeccak256() + sha.Write([]byte(unchecksummed)) + hash := sha.Sum(nil) + + result := []byte(unchecksummed) + for i := 0; i < len(result); i++ { + hashByte := hash[i/2] + if i%2 == 0 { + hashByte = hashByte >> 4 + } else { + hashByte &= 0xf + } + if result[i] > '9' && hashByte > 7 { + result[i] -= 32 + } + } + return "0x" + string(result) +} // String implements the stringer interface and is used also by the logger. func (a Address) String() string { diff --git a/common/types_test.go b/common/types_test.go index 154c33063..6f3b31576 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -94,3 +94,34 @@ func TestAddressUnmarshalJSON(t *testing.T) { } } } + +func TestAddressHexChecksum(t *testing.T) { + var tests = []struct { + Input string + Output string + }{ + // Test cases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#specification + {"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"}, + {"0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359", "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"}, + {"0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb", "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"}, + {"0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"}, + // Ensure that non-standard length input values are handled correctly + {"0xa", "0x000000000000000000000000000000000000000A"}, + {"0x0a", "0x000000000000000000000000000000000000000A"}, + {"0x00a", "0x000000000000000000000000000000000000000A"}, + {"0x000000000000000000000000000000000000000a", "0x000000000000000000000000000000000000000A"}, + } + for i, test := range tests { + output := HexToAddress(test.Input).Hex() + if output != test.Output { + t.Errorf("test #%d: failed to match when it should (%s != %s)", i, output, test.Output) + } + } +} + +func BenchmarkAddressHex(b *testing.B) { + testAddr := HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") + for n := 0; n < b.N; n++ { + testAddr.Hex() + } +} diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index 32a1191db..9ebdb8df1 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -229,9 +229,9 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { // Tally up the new vote from the signer var authorize bool switch { - case bytes.Compare(header.Nonce[:], nonceAuthVote) == 0: + case bytes.Equal(header.Nonce[:], nonceAuthVote): authorize = true - case bytes.Compare(header.Nonce[:], nonceDropVote) == 0: + case bytes.Equal(header.Nonce[:], nonceDropVote): authorize = false default: return nil, errInvalidVote diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index dd9c81fd4..01d97a470 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -287,8 +287,10 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * // given the parent block's time and difficulty. // TODO (karalabe): Move the chain maker into this package and make this private! func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int { - next := new(big.Int).Add(parent.Number, common.Big1) + next := new(big.Int).Add(parent.Number, big1) switch { + case config.IsMetropolis(next): + return calcDifficultyMetropolis(time, parent) case config.IsHomestead(next): return calcDifficultyHomestead(time, parent) default: @@ -299,10 +301,65 @@ func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Heade // Some weird constants to avoid constant memory allocs for them. var ( expDiffPeriod = big.NewInt(100000) + big1 = big.NewInt(1) + big2 = big.NewInt(2) + big9 = big.NewInt(9) big10 = big.NewInt(10) bigMinus99 = big.NewInt(-99) ) +// calcDifficultyMetropolis is the difficulty adjustment algorithm. It returns +// the difficulty that a new block should have when created at time given the +// parent block's time and difficulty. The calculation uses the Metropolis rules. +func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int { + // https://github.com/ethereum/EIPs/issues/100. + // algorithm: + // diff = (parent_diff + + // (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) + // ) + 2^(periodCount - 2) + + bigTime := new(big.Int).SetUint64(time) + bigParentTime := new(big.Int).Set(parent.Time) + + // holds intermediate values to make the algo easier to read & audit + x := new(big.Int) + y := new(big.Int) + + // (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9 + x.Sub(bigTime, bigParentTime) + x.Div(x, big9) + if parent.UncleHash == types.EmptyUncleHash { + x.Sub(big1, x) + } else { + x.Sub(big2, x) + } + // max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9, -99) + if x.Cmp(bigMinus99) < 0 { + x.Set(bigMinus99) + } + // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) + y.Div(parent.Difficulty, params.DifficultyBoundDivisor) + x.Mul(y, x) + x.Add(parent.Difficulty, x) + + // minimum difficulty can ever be (before exponential factor) + if x.Cmp(params.MinimumDifficulty) < 0 { + x.Set(params.MinimumDifficulty) + } + // for the exponential factor + periodCount := new(big.Int).Add(parent.Number, big1) + periodCount.Div(periodCount, expDiffPeriod) + + // the exponential factor, commonly referred to as "the bomb" + // diff = diff + 2^(periodCount - 2) + if periodCount.Cmp(big1) > 0 { + y.Sub(periodCount, big2) + y.Exp(big2, y, nil) + x.Add(x, y) + } + return x +} + // calcDifficultyHomestead is the difficulty adjustment algorithm. It returns // the difficulty that a new block should have when created at time given the // parent block's time and difficulty. The calculation uses the Homestead rules. @@ -320,12 +377,12 @@ func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int { x := new(big.Int) y := new(big.Int) - // 1 - (block_timestamp -parent_timestamp) // 10 + // 1 - (block_timestamp - parent_timestamp) // 10 x.Sub(bigTime, bigParentTime) x.Div(x, big10) - x.Sub(common.Big1, x) + x.Sub(big1, x) - // max(1 - (block_timestamp - parent_timestamp) // 10, -99))) + // max(1 - (block_timestamp - parent_timestamp) // 10, -99) if x.Cmp(bigMinus99) < 0 { x.Set(bigMinus99) } @@ -339,14 +396,14 @@ func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int { x.Set(params.MinimumDifficulty) } // for the exponential factor - periodCount := new(big.Int).Add(parent.Number, common.Big1) + periodCount := new(big.Int).Add(parent.Number, big1) periodCount.Div(periodCount, expDiffPeriod) // the exponential factor, commonly referred to as "the bomb" // diff = diff + 2^(periodCount - 2) - if periodCount.Cmp(common.Big1) > 0 { - y.Sub(periodCount, common.Big2) - y.Exp(common.Big2, y, nil) + if periodCount.Cmp(big1) > 0 { + y.Sub(periodCount, big2) + y.Exp(big2, y, nil) x.Add(x, y) } return x @@ -373,12 +430,12 @@ func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int { diff.Set(params.MinimumDifficulty) } - periodCount := new(big.Int).Add(parent.Number, common.Big1) + periodCount := new(big.Int).Add(parent.Number, big1) periodCount.Div(periodCount, expDiffPeriod) - if periodCount.Cmp(common.Big1) > 0 { + if periodCount.Cmp(big1) > 0 { // diff = diff + 2^(periodCount - 2) - expDiff := periodCount.Sub(periodCount, common.Big2) - expDiff.Exp(common.Big2, expDiff, nil) + expDiff := periodCount.Sub(periodCount, big2) + expDiff.Exp(big2, expDiff, nil) diff.Add(diff, expDiff) diff = math.BigMax(diff, params.MinimumDifficulty) } diff --git a/console/bridge.go b/console/bridge.go index 75be68188..b28cc438e 100644 --- a/console/bridge.go +++ b/console/bridge.go @@ -23,6 +23,7 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" "github.com/robertkrimen/otto" @@ -83,6 +84,49 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) { return ret } +// OpenWallet is a wrapper around personal.openWallet which can interpret and +// react to certain error messages, such as the Trezor PIN matrix request. +func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) { + // Make sure we have an wallet specified to open + if !call.Argument(0).IsString() { + throwJSException("first argument must be the wallet URL to open") + } + wallet := call.Argument(0) + + var passwd otto.Value + if call.Argument(1).IsUndefined() || call.Argument(1).IsNull() { + passwd, _ = otto.ToValue("") + } else { + passwd = call.Argument(1) + } + // Open the wallet and return if successful in itself + val, err := call.Otto.Call("jeth.openWallet", nil, wallet, passwd) + if err == nil { + return val + } + // Wallet open failed, report error unless it's a PIN entry + if !strings.HasSuffix(err.Error(), usbwallet.ErrTrezorPINNeeded.Error()) { + throwJSException(err.Error()) + } + // Trezor PIN matrix input requested, display the matrix to the user and fetch the data + fmt.Fprintf(b.printer, "Look at the device for number positions\n\n") + fmt.Fprintf(b.printer, "7 | 8 | 9\n") + fmt.Fprintf(b.printer, "--+---+--\n") + fmt.Fprintf(b.printer, "4 | 5 | 6\n") + fmt.Fprintf(b.printer, "--+---+--\n") + fmt.Fprintf(b.printer, "1 | 2 | 3\n\n") + + if input, err := b.prompter.PromptPassword("Please enter current PIN: "); err != nil { + throwJSException(err.Error()) + } else { + passwd, _ = otto.ToValue(input) + } + if val, err = call.Otto.Call("jeth.openWallet", nil, wallet, passwd); err != nil { + throwJSException(err.Error()) + } + return val +} + // UnlockAccount is a wrapper around the personal.unlockAccount RPC method that // uses a non-echoing password prompt to acquire the passphrase and executes the // original RPC method (saved in jeth.unlockAccount) with it to actually execute diff --git a/console/console.go b/console/console.go index 389d52858..3cd2ad34b 100644 --- a/console/console.go +++ b/console/console.go @@ -160,10 +160,15 @@ func (c *Console) init(preload []string) error { if err != nil { return err } - // Override the unlockAccount, newAccount and sign methods since these require user interaction. - // Assign these method in the Console the original web3 callbacks. These will be called by the jeth.* - // methods after they got the password from the user and send the original web3 request to the backend. + // Override the openWallet, unlockAccount, newAccount and sign methods since + // these require user interaction. Assign these method in the Console the + // original web3 callbacks. These will be called by the jeth.* methods after + // they got the password from the user and send the original web3 request to + // the backend. if obj := personal.Object(); obj != nil { // make sure the personal api is enabled over the interface + if _, err = c.jsre.Run(`jeth.openWallet = personal.openWallet;`); err != nil { + return fmt.Errorf("personal.openWallet: %v", err) + } if _, err = c.jsre.Run(`jeth.unlockAccount = personal.unlockAccount;`); err != nil { return fmt.Errorf("personal.unlockAccount: %v", err) } @@ -173,6 +178,7 @@ func (c *Console) init(preload []string) error { if _, err = c.jsre.Run(`jeth.sign = personal.sign;`); err != nil { return fmt.Errorf("personal.sign: %v", err) } + obj.Set("openWallet", bridge.OpenWallet) obj.Set("unlockAccount", bridge.UnlockAccount) obj.Set("newAccount", bridge.NewAccount) obj.Set("sign", bridge.Sign) diff --git a/console/console_test.go b/console/console_test.go index 0fc0e7051..8ac499bd1 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -77,8 +77,6 @@ type tester struct { console *Console input *hookedPrompter output *bytes.Buffer - - lastConfirm string } // newTester creates a test environment based on which the console can operate. diff --git a/contracts/chequebook/cheque.go b/contracts/chequebook/cheque.go index bd635705e..09daa9248 100644 --- a/contracts/chequebook/cheque.go +++ b/contracts/chequebook/cheque.go @@ -376,12 +376,12 @@ func (self *Chequebook) autoDeposit(interval time.Duration) { ticker := time.NewTicker(interval) self.quit = make(chan bool) quit := self.quit + go func() { - FOR: for { select { case <-quit: - break FOR + return case <-ticker.C: self.lock.Lock() if self.balance.Cmp(self.buffer) < 0 { @@ -395,7 +395,6 @@ func (self *Chequebook) autoDeposit(interval time.Duration) { } } }() - return } // Outbox can issue cheques from a single contract to a single beneficiary. @@ -436,7 +435,6 @@ type Inbox struct { sender common.Address // local peer's address to send cashing tx from signer *ecdsa.PublicKey // peer's public key txhash string // tx hash of last cashing tx - abigen bind.ContractBackend // blockchain API session *contract.ChequebookSession // abi contract backend with tx opts quit chan bool // when closed causes autocash to stop maxUncashed *big.Int // threshold that triggers autocashing @@ -525,12 +523,12 @@ func (self *Inbox) autoCash(cashInterval time.Duration) { ticker := time.NewTicker(cashInterval) self.quit = make(chan bool) quit := self.quit + go func() { - FOR: for { select { case <-quit: - break FOR + return case <-ticker.C: self.lock.Lock() if self.cheque != nil && self.cheque.Amount.Cmp(self.cashed) != 0 { @@ -543,7 +541,6 @@ func (self *Inbox) autoCash(cashInterval time.Duration) { } } }() - return } // Receive is called to deposit the latest cheque to the incoming Inbox. diff --git a/contracts/chequebook/cheque_test.go b/contracts/chequebook/cheque_test.go index 1f8b71129..5f6a54a1c 100644 --- a/contracts/chequebook/cheque_test.go +++ b/contracts/chequebook/cheque_test.go @@ -170,7 +170,6 @@ func TestVerifyErrors(t *testing.T) { t.Fatalf("expected no error, got %v", err) } - time.Sleep(5) chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend) if err != nil { t.Fatalf("expected no error, got %v", err) @@ -193,7 +192,7 @@ func TestVerifyErrors(t *testing.T) { received, err = chbox.Receive(ch1) t.Logf("correct error: %v", err) if err == nil { - t.Fatalf("expected receiver error, got none") + t.Fatalf("expected receiver error, got none and value %v", received) } ch2, err := chbook1.Issue(addr1, amount) @@ -203,7 +202,7 @@ func TestVerifyErrors(t *testing.T) { received, err = chbox.Receive(ch2) t.Logf("correct error: %v", err) if err == nil { - t.Fatalf("expected sender error, got none") + t.Fatalf("expected sender error, got none and value %v", received) } _, err = chbook1.Issue(addr1, new(big.Int).SetInt64(-1)) @@ -215,7 +214,7 @@ func TestVerifyErrors(t *testing.T) { received, err = chbox.Receive(ch0) t.Logf("correct error: %v", err) if err == nil { - t.Fatalf("expected incorrect amount error, got none") + t.Fatalf("expected incorrect amount error, got none and value %v", received) } } diff --git a/core/asm/lex_test.go b/core/asm/lex_test.go index 36e67bcf7..e6901d4e3 100644 --- a/core/asm/lex_test.go +++ b/core/asm/lex_test.go @@ -16,7 +16,10 @@ package asm -import "testing" +import ( + "reflect" + "testing" +) func lexAll(src string) []token { ch := Lex("test.asm", []byte(src), false) @@ -28,9 +31,41 @@ func lexAll(src string) []token { return tokens } -func TestComment(t *testing.T) { - tokens := lexAll(";; this is a comment") - if len(tokens) != 2 { // {new line, EOF} - t.Error("expected no tokens") +func TestLexer(t *testing.T) { + tests := []struct { + input string + tokens []token + }{ + { + input: ";; this is a comment", + tokens: []token{{typ: lineStart}, {typ: eof}}, + }, + { + input: "0x12345678", + tokens: []token{{typ: lineStart}, {typ: number, text: "0x12345678"}, {typ: eof}}, + }, + { + input: "0x123ggg", + tokens: []token{{typ: lineStart}, {typ: number, text: "0x123"}, {typ: element, text: "ggg"}, {typ: eof}}, + }, + { + input: "12345678", + tokens: []token{{typ: lineStart}, {typ: number, text: "12345678"}, {typ: eof}}, + }, + { + input: "123abc", + tokens: []token{{typ: lineStart}, {typ: number, text: "123"}, {typ: element, text: "abc"}, {typ: eof}}, + }, + { + input: "0123abc", + tokens: []token{{typ: lineStart}, {typ: number, text: "0123"}, {typ: element, text: "abc"}, {typ: eof}}, + }, + } + + for _, test := range tests { + tokens := lexAll(test.input) + if !reflect.DeepEqual(tokens, test.tokens) { + t.Errorf("input %q\ngot: %+v\nwant: %+v", test.input, tokens, test.tokens) + } } } diff --git a/core/asm/lexer.go b/core/asm/lexer.go index 2770bd35f..d784e5d50 100644 --- a/core/asm/lexer.go +++ b/core/asm/lexer.go @@ -254,7 +254,7 @@ func lexInsideString(l *lexer) stateFn { func lexNumber(l *lexer) stateFn { acceptance := Numbers - if l.accept("0") && l.accept("xX") { + if l.accept("0") || l.accept("xX") { acceptance = HexadecimalNumbers } l.acceptRun(acceptance) diff --git a/core/bench_test.go b/core/bench_test.go index 20676fc97..b9250f7d3 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -300,6 +300,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { } } + chain.Stop() db.Close() } } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index abe1766b4..c0afc2955 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -44,6 +44,7 @@ func TestHeaderVerification(t *testing.T) { } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer chain.Stop() for i := 0; i < len(blocks); i++ { for j, valid := range []bool{true, false} { @@ -108,9 +109,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { if valid { chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) _, results = chain.engine.VerifyHeaders(chain, headers, seals) + chain.Stop() } else { chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), new(event.TypeMux), vm.Config{}) _, results = chain.engine.VerifyHeaders(chain, headers, seals) + chain.Stop() } // Wait for all the verification results checks := make(map[int]error) @@ -172,6 +175,8 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { // Start the verifications and immediately abort chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), new(event.TypeMux), vm.Config{}) + defer chain.Stop() + abort, results := chain.engine.VerifyHeaders(chain, headers, seals) close(abort) diff --git a/core/blockchain.go b/core/blockchain.go index bb1c14f43..3fb8be15f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -827,6 +827,11 @@ func (bc *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err er bc.mu.Lock() defer bc.mu.Unlock() + if bc.HasBlock(block.Hash()) { + log.Trace("Block existed", "hash", block.Hash()) + return + } + localTd := bc.GetTd(bc.currentBlock.Hash(), bc.currentBlock.NumberU64()) externTd := new(big.Int).Add(block.Difficulty(), ptd) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 5fa671e2b..4a0f44940 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -20,6 +20,7 @@ import ( "fmt" "math/big" "math/rand" + "sync" "testing" "time" @@ -61,6 +62,8 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara if err != nil { t.Fatal("could not make new canonical in testFork", err) } + defer blockchain2.Stop() + // Assert the chains have the same header/block at #i var hash1, hash2 common.Hash if full { @@ -182,6 +185,8 @@ func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t * func TestLastBlock(t *testing.T) { bchain := newTestBlockChain(false) + defer bchain.Stop() + block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0] bchain.insert(block) if block.Hash() != GetHeadBlockHash(bchain.chainDb) { @@ -202,6 +207,8 @@ func testExtendCanonical(t *testing.T, full bool) { if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } + defer processor.Stop() + // Define the difficulty comparator better := func(td1, td2 *big.Int) { if td2.Cmp(td1) <= 0 { @@ -228,6 +235,8 @@ func testShorterFork(t *testing.T, full bool) { if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } + defer processor.Stop() + // Define the difficulty comparator worse := func(td1, td2 *big.Int) { if td2.Cmp(td1) >= 0 { @@ -256,6 +265,8 @@ func testLongerFork(t *testing.T, full bool) { if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } + defer processor.Stop() + // Define the difficulty comparator better := func(td1, td2 *big.Int) { if td2.Cmp(td1) <= 0 { @@ -284,6 +295,8 @@ func testEqualFork(t *testing.T, full bool) { if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } + defer processor.Stop() + // Define the difficulty comparator equal := func(td1, td2 *big.Int) { if td2.Cmp(td1) != 0 { @@ -309,6 +322,8 @@ func testBrokenChain(t *testing.T, full bool) { if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } + defer blockchain.Stop() + // Create a forked chain, and try to insert with a missing link if full { chain := makeBlockChain(blockchain.CurrentBlock(), 5, db, forkSeed)[1:] @@ -385,6 +400,7 @@ func testReorgShort(t *testing.T, full bool) { func testReorg(t *testing.T, first, second []int, td int64, full bool) { bc := newTestBlockChain(true) + defer bc.Stop() // Insert an easy and a difficult chain afterwards if full { @@ -429,6 +445,7 @@ func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } func testBadHashes(t *testing.T, full bool) { bc := newTestBlockChain(true) + defer bc.Stop() // Create a chain, ban a hash and try to import var err error @@ -453,6 +470,7 @@ func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } func testReorgBadHashes(t *testing.T, full bool) { bc := newTestBlockChain(true) + defer bc.Stop() // Create a chain, import and ban afterwards headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) @@ -483,6 +501,8 @@ func testReorgBadHashes(t *testing.T, full bool) { if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } + defer ncm.Stop() + if full { if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() { t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash()) @@ -508,6 +528,8 @@ func testInsertNonceError(t *testing.T, full bool) { if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } + defer blockchain.Stop() + // Create and insert a chain with a failing nonce var ( failAt int @@ -589,15 +611,16 @@ func TestFastVsFullChains(t *testing.T) { archiveDb, _ := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } - // Fast import the chain as a non-archive node to test fastDb, _ := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer fast.Stop() headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -678,6 +701,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } + defer archive.Stop() + assert(t, "archive", archive, height, height, height) archive.Rollback(remove) assert(t, "archive", archive, height/2, height/2, height/2) @@ -686,6 +711,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { fastDb, _ := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer fast.Stop() headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -709,6 +735,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } + defer light.Stop() + assert(t, "light", light, height, 0, 0) light.Rollback(remove) assert(t, "light", light, height/2, 0, 0) @@ -777,6 +805,7 @@ func TestChainTxReorgs(t *testing.T) { if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } + defer blockchain.Stop() // overwrite the old chain chain, _ = GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) { @@ -845,6 +874,7 @@ func TestLogReorgs(t *testing.T) { var evmux event.TypeMux blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), &evmux, vm.Config{}) + defer blockchain.Stop() subs := evmux.Subscribe(RemovedLogsEvent{}) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) { @@ -886,6 +916,7 @@ func TestReorgSideEvent(t *testing.T) { evmux := &event.TypeMux{} blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), evmux, vm.Config{}) + defer blockchain.Stop() chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {}) if _, err := blockchain.InsertChain(chain); err != nil { @@ -955,11 +986,18 @@ done: // Tests if the canonical block can be fetched from the database during chain insertion. func TestCanonicalBlockRetrieval(t *testing.T) { - bc := newTestBlockChain(false) + bc := newTestBlockChain(true) + defer bc.Stop() + chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {}) + var pend sync.WaitGroup + pend.Add(len(chain)) + for i := range chain { go func(block *types.Block) { + defer pend.Done() + // try to retrieve a block by its canonical hash and see if the block data can be retrieved. for { ch := GetCanonicalHash(bc.chainDb, block.NumberU64()) @@ -980,8 +1018,11 @@ func TestCanonicalBlockRetrieval(t *testing.T) { } }(chain[i]) - bc.InsertChain(types.Blocks{chain[i]}) + if _, err := bc.InsertChain(types.Blocks{chain[i]}); err != nil { + t.Fatalf("failed to insert block %d: %v", i, err) + } } + pend.Wait() } func TestEIP155Transition(t *testing.T) { @@ -1001,6 +1042,8 @@ func TestEIP155Transition(t *testing.T) { ) blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), &mux, vm.Config{}) + defer blockchain.Stop() + blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) { var ( tx *types.Transaction @@ -1104,10 +1147,12 @@ func TestEIP161AccountRemoval(t *testing.T) { }, Alloc: GenesisAlloc{address: {Balance: funds}}, } - genesis = gspec.MustCommit(db) - mux event.TypeMux - blockchain, _ = NewBlockChain(db, gspec.Config, ethash.NewFaker(), &mux, vm.Config{}) + genesis = gspec.MustCommit(db) + mux event.TypeMux ) + blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), &mux, vm.Config{}) + defer blockchain.Stop() + blocks, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, block *BlockGen) { var ( tx *types.Transaction diff --git a/core/chain_indexer.go b/core/chain_indexer.go new file mode 100644 index 000000000..9a88a5b1b --- /dev/null +++ b/core/chain_indexer.go @@ -0,0 +1,396 @@ +// Copyright 2017 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 core + +import ( + "encoding/binary" + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" +) + +// ChainIndexerBackend defines the methods needed to process chain segments in +// the background and write the segment results into the database. These can be +// used to create filter blooms or CHTs. +type ChainIndexerBackend interface { + // Reset initiates the processing of a new chain segment, potentially terminating + // any partially completed operations (in case of a reorg). + Reset(section uint64) + + // Process crunches through the next header in the chain segment. The caller + // will ensure a sequential order of headers. + Process(header *types.Header) + + // Commit finalizes the section metadata and stores it into the database. This + // interface will usually be a batch writer. + Commit(db ethdb.Database) error +} + +// ChainIndexer does a post-processing job for equally sized sections of the +// canonical chain (like BlooomBits and CHT structures). A ChainIndexer is +// connected to the blockchain through the event system by starting a +// ChainEventLoop in a goroutine. +// +// Further child ChainIndexers can be added which use the output of the parent +// section indexer. These child indexers receive new head notifications only +// after an entire section has been finished or in case of rollbacks that might +// affect already finished sections. +type ChainIndexer struct { + chainDb ethdb.Database // Chain database to index the data from + indexDb ethdb.Database // Prefixed table-view of the db to write index metadata into + backend ChainIndexerBackend // Background processor generating the index data content + children []*ChainIndexer // Child indexers to cascade chain updates to + + active uint32 // Flag whether the event loop was started + update chan struct{} // Notification channel that headers should be processed + quit chan chan error // Quit channel to tear down running goroutines + + sectionSize uint64 // Number of blocks in a single chain segment to process + confirmsReq uint64 // Number of confirmations before processing a completed segment + + storedSections uint64 // Number of sections successfully indexed into the database + knownSections uint64 // Number of sections known to be complete (block wise) + cascadedHead uint64 // Block number of the last completed section cascaded to subindexers + + throttling time.Duration // Disk throttling to prevent a heavy upgrade from hogging resources + + log log.Logger + lock sync.RWMutex +} + +// NewChainIndexer creates a new chain indexer to do background processing on +// chain segments of a given size after certain number of confirmations passed. +// The throttling parameter might be used to prevent database thrashing. +func NewChainIndexer(chainDb, indexDb ethdb.Database, backend ChainIndexerBackend, section, confirm uint64, throttling time.Duration, kind string) *ChainIndexer { + c := &ChainIndexer{ + chainDb: chainDb, + indexDb: indexDb, + backend: backend, + update: make(chan struct{}, 1), + quit: make(chan chan error), + sectionSize: section, + confirmsReq: confirm, + throttling: throttling, + log: log.New("type", kind), + } + // Initialize database dependent fields and start the updater + c.loadValidSections() + go c.updateLoop() + + return c +} + +// Start creates a goroutine to feed chain head events into the indexer for +// cascading background processing. +func (c *ChainIndexer) Start(currentHeader *types.Header, eventMux *event.TypeMux) { + go c.eventLoop(currentHeader, eventMux) +} + +// Close tears down all goroutines belonging to the indexer and returns any error +// that might have occurred internally. +func (c *ChainIndexer) Close() error { + var errs []error + + // Tear down the primary update loop + errc := make(chan error) + c.quit <- errc + if err := <-errc; err != nil { + errs = append(errs, err) + } + // If needed, tear down the secondary event loop + if atomic.LoadUint32(&c.active) != 0 { + c.quit <- errc + if err := <-errc; err != nil { + errs = append(errs, err) + } + } + // Return any failures + switch { + case len(errs) == 0: + return nil + + case len(errs) == 1: + return errs[0] + + default: + return fmt.Errorf("%v", errs) + } +} + +// eventLoop is a secondary - optional - event loop of the indexer which is only +// started for the outermost indexer to push chain head events into a processing +// queue. +func (c *ChainIndexer) eventLoop(currentHeader *types.Header, eventMux *event.TypeMux) { + // Mark the chain indexer as active, requiring an additional teardown + atomic.StoreUint32(&c.active, 1) + + // Subscribe to chain head events + sub := eventMux.Subscribe(ChainEvent{}) + defer sub.Unsubscribe() + + // Fire the initial new head event to start any outstanding processing + c.newHead(currentHeader.Number.Uint64(), false) + + var ( + prevHeader = currentHeader + prevHash = currentHeader.Hash() + ) + for { + select { + case errc := <-c.quit: + // Chain indexer terminating, report no failure and abort + errc <- nil + return + + case ev, ok := <-sub.Chan(): + // Received a new event, ensure it's not nil (closing) and update + if !ok { + errc := <-c.quit + errc <- nil + return + } + header := ev.Data.(ChainEvent).Block.Header() + if header.ParentHash != prevHash { + c.newHead(FindCommonAncestor(c.chainDb, prevHeader, header).Number.Uint64(), true) + } + c.newHead(header.Number.Uint64(), false) + + prevHeader, prevHash = header, header.Hash() + } + } +} + +// newHead notifies the indexer about new chain heads and/or reorgs. +func (c *ChainIndexer) newHead(head uint64, reorg bool) { + c.lock.Lock() + defer c.lock.Unlock() + + // If a reorg happened, invalidate all sections until that point + if reorg { + // Revert the known section number to the reorg point + changed := head / c.sectionSize + if changed < c.knownSections { + c.knownSections = changed + } + // Revert the stored sections from the database to the reorg point + if changed < c.storedSections { + c.setValidSections(changed) + } + // Update the new head number to te finalized section end and notify children + head = changed * c.sectionSize + + if head < c.cascadedHead { + c.cascadedHead = head + for _, child := range c.children { + child.newHead(c.cascadedHead, true) + } + } + return + } + // No reorg, calculate the number of newly known sections and update if high enough + var sections uint64 + if head >= c.confirmsReq { + sections = (head + 1 - c.confirmsReq) / c.sectionSize + if sections > c.knownSections { + c.knownSections = sections + + select { + case c.update <- struct{}{}: + default: + } + } + } +} + +// updateLoop is the main event loop of the indexer which pushes chain segments +// down into the processing backend. +func (c *ChainIndexer) updateLoop() { + var updated time.Time + + for { + select { + case errc := <-c.quit: + // Chain indexer terminating, report no failure and abort + errc <- nil + return + + case <-c.update: + // Section headers completed (or rolled back), update the index + c.lock.Lock() + if c.knownSections > c.storedSections { + // Periodically print an upgrade log message to the user + if time.Since(updated) > 8*time.Second { + if c.knownSections > c.storedSections+1 { + c.log.Info("Upgrading chain index", "percentage", c.storedSections*100/c.knownSections) + } + updated = time.Now() + } + // Cache the current section count and head to allow unlocking the mutex + section := c.storedSections + var oldHead common.Hash + if section > 0 { + oldHead = c.sectionHead(section - 1) + } + // Process the newly defined section in the background + c.lock.Unlock() + newHead, err := c.processSection(section, oldHead) + c.lock.Lock() + + // If processing succeeded and no reorgs occcurred, mark the section completed + if err == nil && oldHead == c.sectionHead(section-1) { + c.setSectionHead(section, newHead) + c.setValidSections(section + 1) + + c.cascadedHead = c.storedSections*c.sectionSize - 1 + for _, child := range c.children { + c.log.Trace("Cascading chain index update", "head", c.cascadedHead) + child.newHead(c.cascadedHead, false) + } + } else { + // If processing failed, don't retry until further notification + c.log.Debug("Chain index processing failed", "section", section, "err", err) + c.knownSections = c.storedSections + } + } + // If there are still further sections to process, reschedule + if c.knownSections > c.storedSections { + time.AfterFunc(c.throttling, func() { + select { + case c.update <- struct{}{}: + default: + } + }) + } + c.lock.Unlock() + } + } +} + +// processSection processes an entire section by calling backend functions while +// ensuring the continuity of the passed headers. Since the chain mutex is not +// held while processing, the continuity can be broken by a long reorg, in which +// case the function returns with an error. +func (c *ChainIndexer) processSection(section uint64, lastHead common.Hash) (common.Hash, error) { + c.log.Trace("Processing new chain section", "section", section) + + // Reset and partial processing + c.backend.Reset(section) + + for number := section * c.sectionSize; number < (section+1)*c.sectionSize; number++ { + hash := GetCanonicalHash(c.chainDb, number) + if hash == (common.Hash{}) { + return common.Hash{}, fmt.Errorf("canonical block #%d unknown", number) + } + header := GetHeader(c.chainDb, hash, number) + if header == nil { + return common.Hash{}, fmt.Errorf("block #%d [%x…] not found", number, hash[:4]) + } else if header.ParentHash != lastHead { + return common.Hash{}, fmt.Errorf("chain reorged during section processing") + } + c.backend.Process(header) + lastHead = header.Hash() + } + if err := c.backend.Commit(c.chainDb); err != nil { + return common.Hash{}, err + } + return lastHead, nil +} + +// Sections returns the number of processed sections maintained by the indexer +// and also the information about the last header indexed for potential canonical +// verifications. +func (c *ChainIndexer) Sections() (uint64, uint64, common.Hash) { + c.lock.Lock() + defer c.lock.Unlock() + + return c.storedSections, c.storedSections*c.sectionSize - 1, c.sectionHead(c.storedSections - 1) +} + +// AddChildIndexer adds a child ChainIndexer that can use the output of this one +func (c *ChainIndexer) AddChildIndexer(indexer *ChainIndexer) { + c.lock.Lock() + defer c.lock.Unlock() + + c.children = append(c.children, indexer) + + // Cascade any pending updates to new children too + if c.storedSections > 0 { + indexer.newHead(c.storedSections*c.sectionSize-1, false) + } +} + +// loadValidSections reads the number of valid sections from the index database +// and caches is into the local state. +func (c *ChainIndexer) loadValidSections() { + data, _ := c.indexDb.Get([]byte("count")) + if len(data) == 8 { + c.storedSections = binary.BigEndian.Uint64(data[:]) + } +} + +// setValidSections writes the number of valid sections to the index database +func (c *ChainIndexer) setValidSections(sections uint64) { + // Set the current number of valid sections in the database + var data [8]byte + binary.BigEndian.PutUint64(data[:], sections) + c.indexDb.Put([]byte("count"), data[:]) + + // Remove any reorged sections, caching the valids in the mean time + for c.storedSections > sections { + c.storedSections-- + c.removeSectionHead(c.storedSections) + } + c.storedSections = sections // needed if new > old +} + +// sectionHead retrieves the last block hash of a processed section from the +// index database. +func (c *ChainIndexer) sectionHead(section uint64) common.Hash { + var data [8]byte + binary.BigEndian.PutUint64(data[:], section) + + hash, _ := c.indexDb.Get(append([]byte("shead"), data[:]...)) + if len(hash) == len(common.Hash{}) { + return common.BytesToHash(hash) + } + return common.Hash{} +} + +// setSectionHead writes the last block hash of a processed section to the index +// database. +func (c *ChainIndexer) setSectionHead(section uint64, hash common.Hash) { + var data [8]byte + binary.BigEndian.PutUint64(data[:], section) + + c.indexDb.Put(append([]byte("shead"), data[:]...), hash.Bytes()) +} + +// removeSectionHead removes the reference to a processed section from the index +// database. +func (c *ChainIndexer) removeSectionHead(section uint64) { + var data [8]byte + binary.BigEndian.PutUint64(data[:], section) + + c.indexDb.Delete(append([]byte("shead"), data[:]...)) +} diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go new file mode 100644 index 000000000..780e46e43 --- /dev/null +++ b/core/chain_indexer_test.go @@ -0,0 +1,234 @@ +// Copyright 2017 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 core + +import ( + "fmt" + "math/big" + "math/rand" + "testing" + "time" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" +) + +// Runs multiple tests with randomized parameters. +func TestChainIndexerSingle(t *testing.T) { + for i := 0; i < 10; i++ { + testChainIndexer(t, 1) + } +} + +// Runs multiple tests with randomized parameters and different number of +// chain backends. +func TestChainIndexerWithChildren(t *testing.T) { + for i := 2; i < 8; i++ { + testChainIndexer(t, i) + } +} + +// testChainIndexer runs a test with either a single chain indexer or a chain of +// multiple backends. The section size and required confirmation count parameters +// are randomized. +func testChainIndexer(t *testing.T, count int) { + db, _ := ethdb.NewMemDatabase() + defer db.Close() + + // Create a chain of indexers and ensure they all report empty + backends := make([]*testChainIndexBackend, count) + for i := 0; i < count; i++ { + var ( + sectionSize = uint64(rand.Intn(100) + 1) + confirmsReq = uint64(rand.Intn(10)) + ) + backends[i] = &testChainIndexBackend{t: t, processCh: make(chan uint64)} + backends[i].indexer = NewChainIndexer(db, ethdb.NewTable(db, string([]byte{byte(i)})), backends[i], sectionSize, confirmsReq, 0, fmt.Sprintf("indexer-%d", i)) + defer backends[i].indexer.Close() + + if sections, _, _ := backends[i].indexer.Sections(); sections != 0 { + t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, 0) + } + if i > 0 { + backends[i-1].indexer.AddChildIndexer(backends[i].indexer) + } + } + // notify pings the root indexer about a new head or reorg, then expect + // processed blocks if a section is processable + notify := func(headNum, failNum uint64, reorg bool) { + backends[0].indexer.newHead(headNum, reorg) + if reorg { + for _, backend := range backends { + headNum = backend.reorg(headNum) + backend.assertSections() + } + return + } + var cascade bool + for _, backend := range backends { + headNum, cascade = backend.assertBlocks(headNum, failNum) + if !cascade { + break + } + backend.assertSections() + } + } + // inject inserts a new random canonical header into the database directly + inject := func(number uint64) { + header := &types.Header{Number: big.NewInt(int64(number)), Extra: big.NewInt(rand.Int63()).Bytes()} + if number > 0 { + header.ParentHash = GetCanonicalHash(db, number-1) + } + WriteHeader(db, header) + WriteCanonicalHash(db, header.Hash(), number) + } + // Start indexer with an already existing chain + for i := uint64(0); i <= 100; i++ { + inject(i) + } + notify(100, 100, false) + + // Add new blocks one by one + for i := uint64(101); i <= 1000; i++ { + inject(i) + notify(i, i, false) + } + // Do a reorg + notify(500, 500, true) + + // Create new fork + for i := uint64(501); i <= 1000; i++ { + inject(i) + notify(i, i, false) + } + for i := uint64(1001); i <= 1500; i++ { + inject(i) + } + // Failed processing scenario where less blocks are available than notified + notify(2000, 1500, false) + + // Notify about a reorg (which could have caused the missing blocks if happened during processing) + notify(1500, 1500, true) + + // Create new fork + for i := uint64(1501); i <= 2000; i++ { + inject(i) + notify(i, i, false) + } +} + +// testChainIndexBackend implements ChainIndexerBackend +type testChainIndexBackend struct { + t *testing.T + indexer *ChainIndexer + section, headerCnt, stored uint64 + processCh chan uint64 +} + +// assertSections verifies if a chain indexer has the correct number of section. +func (b *testChainIndexBackend) assertSections() { + // Keep trying for 3 seconds if it does not match + var sections uint64 + for i := 0; i < 300; i++ { + sections, _, _ = b.indexer.Sections() + if sections == b.stored { + return + } + time.Sleep(10 * time.Millisecond) + } + b.t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, b.stored) +} + +// assertBlocks expects processing calls after new blocks have arrived. If the +// failNum < headNum then we are simulating a scenario where a reorg has happened +// after the processing has started and the processing of a section fails. +func (b *testChainIndexBackend) assertBlocks(headNum, failNum uint64) (uint64, bool) { + var sections uint64 + if headNum >= b.indexer.confirmsReq { + sections = (headNum + 1 - b.indexer.confirmsReq) / b.indexer.sectionSize + if sections > b.stored { + // expect processed blocks + for expectd := b.stored * b.indexer.sectionSize; expectd < sections*b.indexer.sectionSize; expectd++ { + if expectd > failNum { + // rolled back after processing started, no more process calls expected + // wait until updating is done to make sure that processing actually fails + var updating bool + for i := 0; i < 300; i++ { + b.indexer.lock.Lock() + updating = b.indexer.knownSections > b.indexer.storedSections + b.indexer.lock.Unlock() + if !updating { + break + } + time.Sleep(10 * time.Millisecond) + } + if updating { + b.t.Fatalf("update did not finish") + } + sections = expectd / b.indexer.sectionSize + break + } + select { + case <-time.After(10 * time.Second): + b.t.Fatalf("Expected processed block #%d, got nothing", expectd) + case processed := <-b.processCh: + if processed != expectd { + b.t.Errorf("Expected processed block #%d, got #%d", expectd, processed) + } + } + } + b.stored = sections + } + } + if b.stored == 0 { + return 0, false + } + return b.stored*b.indexer.sectionSize - 1, true +} + +func (b *testChainIndexBackend) reorg(headNum uint64) uint64 { + firstChanged := headNum / b.indexer.sectionSize + if firstChanged < b.stored { + b.stored = firstChanged + } + return b.stored * b.indexer.sectionSize +} + +func (b *testChainIndexBackend) Reset(section uint64) { + b.section = section + b.headerCnt = 0 +} + +func (b *testChainIndexBackend) Process(header *types.Header) { + b.headerCnt++ + if b.headerCnt > b.indexer.sectionSize { + b.t.Error("Processing too many headers") + } + //t.processCh <- header.Number.Uint64() + select { + case <-time.After(10 * time.Second): + b.t.Fatal("Unexpected call to Process") + case b.processCh <- header.Number.Uint64(): + } +} + +func (b *testChainIndexBackend) Commit(db ethdb.Database) error { + if b.headerCnt != b.indexer.sectionSize { + b.t.Error("Not enough headers processed") + } + return nil +} diff --git a/core/chain_makers.go b/core/chain_makers.go index 38a69d42a..976a8114d 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -218,6 +218,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St Number: parent.Number(), Time: new(big.Int).Sub(time, big.NewInt(10)), Difficulty: parent.Difficulty(), + UncleHash: parent.UncleHash(), }), GasLimit: CalcGasLimit(parent), GasUsed: new(big.Int), diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 3a7c62396..28eb76c63 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -81,7 +81,10 @@ func ExampleGenerateChain() { // Import the chain. This runs all block validation rules. evmux := &event.TypeMux{} + blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), evmux, vm.Config{}) + defer blockchain.Stop() + if i, err := blockchain.InsertChain(chain); err != nil { fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err) return diff --git a/core/dao_test.go b/core/dao_test.go index bc9f3f394..99bf1ecae 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -43,11 +43,13 @@ func TestDAOForkRangeExtradata(t *testing.T) { gspec.MustCommit(proDb) proConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true} proBc, _ := NewBlockChain(proDb, proConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer proBc.Stop() conDb, _ := ethdb.NewMemDatabase() gspec.MustCommit(conDb) conConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false} conBc, _ := NewBlockChain(conDb, conConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { t.Fatalf("pro-fork: failed to import chain prefix: %v", err) @@ -60,7 +62,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a pro-fork block, and try to feed into the no-fork chain db, _ = ethdb.NewMemDatabase() gspec.MustCommit(db) + bc, _ := NewBlockChain(db, conConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) for j := 0; j < len(blocks)/2; j++ { @@ -81,7 +85,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a no-fork block, and try to feed into the pro-fork chain db, _ = ethdb.NewMemDatabase() gspec.MustCommit(db) + bc, _ = NewBlockChain(db, proConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) for j := 0; j < len(blocks)/2; j++ { @@ -103,7 +109,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that contra-forkers accept pro-fork extra-datas after forking finishes db, _ = ethdb.NewMemDatabase() gspec.MustCommit(db) + bc, _ := NewBlockChain(db, conConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) for j := 0; j < len(blocks)/2; j++ { @@ -119,7 +127,9 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that pro-forkers accept contra-fork extra-datas after forking finishes db, _ = ethdb.NewMemDatabase() gspec.MustCommit(db) + bc, _ = NewBlockChain(db, proConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) + defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) for j := 0; j < len(blocks)/2; j++ { diff --git a/core/filter_test.go b/core/filter_test.go deleted file mode 100644 index 58e71e305..000000000 --- a/core/filter_test.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 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 core diff --git a/core/gen_genesis.go b/core/gen_genesis.go index 1f3b4a8aa..4d75704a6 100644 --- a/core/gen_genesis.go +++ b/core/gen_genesis.go @@ -13,8 +13,6 @@ import ( "github.com/ethereum/go-ethereum/params" ) -var _ = (*genesisSpecMarshaling)(nil) - func (g Genesis) MarshalJSON() ([]byte, error) { type Genesis struct { Config *params.ChainConfig `json:"config"` @@ -26,7 +24,7 @@ func (g Genesis) MarshalJSON() ([]byte, error) { Mixhash common.Hash `json:"mixHash"` Coinbase common.Address `json:"coinbase"` Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"` - Number uint64 `json:"number"` + Number math.HexOrDecimal64 `json:"number"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` ParentHash common.Hash `json:"parentHash"` } @@ -45,7 +43,7 @@ func (g Genesis) MarshalJSON() ([]byte, error) { enc.Alloc[common.UnprefixedAddress(k)] = v } } - enc.Number = g.Number + enc.Number = math.HexOrDecimal64(g.Number) enc.GasUsed = math.HexOrDecimal64(g.GasUsed) enc.ParentHash = g.ParentHash return json.Marshal(&enc) @@ -62,7 +60,7 @@ func (g *Genesis) UnmarshalJSON(input []byte) error { Mixhash *common.Hash `json:"mixHash"` Coinbase *common.Address `json:"coinbase"` Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"` - Number *uint64 `json:"number"` + Number *math.HexOrDecimal64 `json:"number"` GasUsed *math.HexOrDecimal64 `json:"gasUsed"` ParentHash *common.Hash `json:"parentHash"` } @@ -104,7 +102,7 @@ func (g *Genesis) UnmarshalJSON(input []byte) error { g.Alloc[common.Address(k)] = v } if dec.Number != nil { - g.Number = *dec.Number + g.Number = uint64(*dec.Number) } if dec.GasUsed != nil { g.GasUsed = uint64(*dec.GasUsed) diff --git a/core/genesis.go b/core/genesis.go index a507d522b..fd6ed6115 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -92,6 +92,7 @@ type genesisSpecMarshaling struct { ExtraData hexutil.Bytes GasLimit math.HexOrDecimal64 GasUsed math.HexOrDecimal64 + Number math.HexOrDecimal64 Difficulty *math.HexOrDecimal256 Alloc map[common.UnprefixedAddress]GenesisAccount } diff --git a/core/genesis_test.go b/core/genesis_test.go index bc82fe54e..8b193759f 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -120,6 +120,8 @@ func TestSetupGenesis(t *testing.T) { // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) bc, _ := NewBlockChain(db, oldcustomg.Config, ethash.NewFullFaker(), new(event.TypeMux), vm.Config{}) + defer bc.Stop() + bc.SetValidator(bproc{}) bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0)) bc.CurrentBlock() diff --git a/core/state_processor.go b/core/state_processor.go index 90f5a4f60..4489cfce2 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -104,11 +104,17 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common } // Update the state with pending changes + var root []byte + if config.IsMetropolis(header.Number) { + statedb.Finalise() + } else { + root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() + } usedGas.Add(usedGas, gas) + // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing wether the root touch-delete accounts. - root := statedb.IntermediateRoot(config.IsEIP158(header.Number)) - receipt := types.NewReceipt(root.Bytes(), usedGas) + receipt := types.NewReceipt(root, usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) // if the transaction created a contract, store the creation address in the receipt. diff --git a/core/tx_journal.go b/core/tx_journal.go new file mode 100644 index 000000000..94a9ff9b8 --- /dev/null +++ b/core/tx_journal.go @@ -0,0 +1,150 @@ +// Copyright 2017 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 core + +import ( + "errors" + "io" + "os" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" +) + +// errNoActiveJournal is returned if a transaction is attempted to be inserted +// into the journal, but no such file is currently open. +var errNoActiveJournal = errors.New("no active journal") + +// txJournal is a rotating log of transactions with the aim of storing locally +// created transactions to allow non-executed ones to survive node restarts. +type txJournal struct { + path string // Filesystem path to store the transactions at + writer io.WriteCloser // Output stream to write new transactions into +} + +// newTxJournal creates a new transaction journal to +func newTxJournal(path string) *txJournal { + return &txJournal{ + path: path, + } +} + +// load parses a transaction journal dump from disk, loading its contents into +// the specified pool. +func (journal *txJournal) load(add func(*types.Transaction) error) error { + // Skip the parsing if the journal file doens't exist at all + if _, err := os.Stat(journal.path); os.IsNotExist(err) { + return nil + } + // Open the journal for loading any past transactions + input, err := os.Open(journal.path) + if err != nil { + return err + } + defer input.Close() + + // Inject all transactions from the journal into the pool + stream := rlp.NewStream(input, 0) + total, dropped := 0, 0 + + var failure error + for { + // Parse the next transaction and terminate on error + tx := new(types.Transaction) + if err = stream.Decode(tx); err != nil { + if err != io.EOF { + failure = err + } + break + } + // Import the transaction and bump the appropriate progress counters + total++ + if err = add(tx); err != nil { + log.Debug("Failed to add journaled transaction", "err", err) + dropped++ + continue + } + } + log.Info("Loaded local transaction journal", "transactions", total, "dropped", dropped) + + return failure +} + +// insert adds the specified transaction to the local disk journal. +func (journal *txJournal) insert(tx *types.Transaction) error { + if journal.writer == nil { + return errNoActiveJournal + } + if err := rlp.Encode(journal.writer, tx); err != nil { + return err + } + return nil +} + +// rotate regenerates the transaction journal based on the current contents of +// the transaction pool. +func (journal *txJournal) rotate(all map[common.Address]types.Transactions) error { + // Close the current journal (if any is open) + if journal.writer != nil { + if err := journal.writer.Close(); err != nil { + return err + } + journal.writer = nil + } + // Generate a new journal with the contents of the current pool + replacement, err := os.OpenFile(journal.path+".new", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + return err + } + journaled := 0 + for _, txs := range all { + for _, tx := range txs { + if err = rlp.Encode(replacement, tx); err != nil { + replacement.Close() + return err + } + } + journaled += len(txs) + } + replacement.Close() + + // Replace the live journal with the newly generated one + if err = os.Rename(journal.path+".new", journal.path); err != nil { + return err + } + sink, err := os.OpenFile(journal.path, os.O_WRONLY|os.O_APPEND, 0755) + if err != nil { + return err + } + journal.writer = sink + log.Info("Regenerated local transaction journal", "transactions", journaled, "accounts", len(all)) + + return nil +} + +// close flushes the transaction journal contents to disk and closes the file. +func (journal *txJournal) close() error { + var err error + + if journal.writer != nil { + err = journal.writer.Close() + journal.writer = nil + } + return err +} diff --git a/core/tx_pool.go b/core/tx_pool.go index 8e2d1b31d..b0c251f92 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -99,7 +99,9 @@ type stateFn func() (*state.StateDB, error) // TxPoolConfig are the configuration parameters of the transaction pool. type TxPoolConfig struct { - NoLocals bool // Whether local transaction handling should be disabled + NoLocals bool // Whether local transaction handling should be disabled + Journal string // Journal of local transactions to survive node restarts + Rejournal time.Duration // Time interval to regenerate the local transaction journal PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce) @@ -115,6 +117,9 @@ type TxPoolConfig struct { // DefaultTxPoolConfig contains the default configurations for the transaction // pool. var DefaultTxPoolConfig = TxPoolConfig{ + Journal: "transactions.rlp", + Rejournal: time.Hour, + PriceLimit: 1, PriceBump: 10, @@ -130,6 +135,10 @@ var DefaultTxPoolConfig = TxPoolConfig{ // unreasonable or unworkable. func (config *TxPoolConfig) sanitize() TxPoolConfig { conf := *config + if conf.Rejournal < time.Second { + log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) + conf.Rejournal = time.Second + } if conf.PriceLimit < 1 { log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit) conf.PriceLimit = DefaultTxPoolConfig.PriceLimit @@ -157,18 +166,19 @@ type TxPool struct { gasPrice *big.Int eventMux *event.TypeMux events *event.TypeMuxSubscription - locals *accountSet signer types.Signer mu sync.RWMutex + locals *accountSet // Set of local transaction to exepmt from evicion rules + journal *txJournal // Journal of local transaction to back up to disk + pending map[common.Address]*txList // All currently processable transactions queue map[common.Address]*txList // Queued but non-processable transactions beats map[common.Address]time.Time // Last heartbeat from each known account all map[common.Hash]*types.Transaction // All transactions to allow lookups priced *txPricedList // All transactions sorted by price - wg sync.WaitGroup // for shutdown sync - quit chan struct{} + wg sync.WaitGroup // for shutdown sync homestead bool } @@ -194,32 +204,48 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, eventMux *e gasPrice: new(big.Int).SetUint64(config.PriceLimit), pendingState: nil, events: eventMux.Subscribe(ChainHeadEvent{}, RemovedTransactionEvent{}), - quit: make(chan struct{}), } pool.locals = newAccountSet(pool.signer) pool.priced = newTxPricedList(&pool.all) - pool.resetState() + pool.reset() - // Start the various events loops and return - pool.wg.Add(2) - go pool.eventLoop() - go pool.expirationLoop() + // If local transactions and journaling is enabled, load from disk + if !config.NoLocals && config.Journal != "" { + pool.journal = newTxJournal(config.Journal) + + if err := pool.journal.load(pool.AddLocal); err != nil { + log.Warn("Failed to load transaction journal", "err", err) + } + if err := pool.journal.rotate(pool.local()); err != nil { + log.Warn("Failed to rotate transaction journal", "err", err) + } + } + // Start the event loop and return + pool.wg.Add(1) + go pool.loop() return pool } -func (pool *TxPool) eventLoop() { +// loop is the transaction pool's main event loop, waiting for and reacting to +// outside blockchain events as well as for various reporting and transaction +// eviction events. +func (pool *TxPool) loop() { defer pool.wg.Done() - // Start a ticker and keep track of interesting pool stats to report + // Start the stats reporting and transaction eviction tickers var prevPending, prevQueued, prevStales int report := time.NewTicker(statsReportInterval) defer report.Stop() - // Track chain events. When a chain events occurs (new chain canon block) - // we need to know the new state. The new state will help us determine - // the nonces in the managed state + evict := time.NewTicker(evictionInterval) + defer evict.Stop() + + journal := time.NewTicker(pool.config.Rejournal) + defer journal.Stop() + + // Keep waiting for and reacting to the various events for { select { // Handle any events fired by the system @@ -235,7 +261,7 @@ func (pool *TxPool) eventLoop() { pool.homestead = true } } - pool.resetState() + pool.reset() pool.mu.Unlock() case RemovedTransactionEvent: @@ -253,11 +279,49 @@ func (pool *TxPool) eventLoop() { log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales) prevPending, prevQueued, prevStales = pending, queued, stales } + + // Handle inactive account transaction eviction + case <-evict.C: + pool.mu.Lock() + for addr := range pool.queue { + // Skip local transactions from the eviction mechanism + if pool.locals.contains(addr) { + continue + } + // Any non-locals old enough should be removed + if time.Since(pool.beats[addr]) > pool.config.Lifetime { + for _, tx := range pool.queue[addr].Flatten() { + pool.removeTx(tx.Hash()) + } + } + } + pool.mu.Unlock() + + // Handle local transaction journal rotation + case <-journal.C: + if pool.journal != nil { + pool.mu.Lock() + if err := pool.journal.rotate(pool.local()); err != nil { + log.Warn("Failed to rotate local tx journal", "err", err) + } + pool.mu.Unlock() + } } } } -func (pool *TxPool) resetState() { +// lockedReset is a wrapper around reset to allow calling it in a thread safe +// manner. This method is only ever used in the tester! +func (pool *TxPool) lockedReset() { + pool.mu.Lock() + defer pool.mu.Unlock() + + pool.reset() +} + +// reset retrieves the current state of the blockchain and ensures the content +// of the transaction pool is valid with regard to the chain state. +func (pool *TxPool) reset() { currentState, err := pool.currentState() if err != nil { log.Error("Failed reset txpool state", "err", err) @@ -284,9 +348,11 @@ func (pool *TxPool) resetState() { // Stop terminates the transaction pool. func (pool *TxPool) Stop() { pool.events.Unsubscribe() - close(pool.quit) pool.wg.Wait() + if pool.journal != nil { + pool.journal.close() + } log.Info("Transaction pool stopped") } @@ -373,6 +439,22 @@ func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { return pending, nil } +// local retrieves all currently known local transactions, groupped by origin +// account and sorted by nonce. The returned transaction set is a copy and can be +// freely modified by calling code. +func (pool *TxPool) local() map[common.Address]types.Transactions { + txs := make(map[common.Address]types.Transactions) + for addr := range pool.locals.accounts { + if pending := pool.pending[addr]; pending != nil { + txs[addr] = append(txs[addr], pending.Flatten()...) + } + if queued := pool.queue[addr]; queued != nil { + txs[addr] = append(txs[addr], queued.Flatten()...) + } + } + return txs +} + // validateTx checks whether a transaction is valid according to the consensus // rules and adheres to some heuristic limits of the local node (price and size). func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { @@ -473,18 +555,22 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { } pool.all[tx.Hash()] = tx pool.priced.Put(tx) + pool.journalTx(from, tx) log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) return old != nil, nil } - // New transaction isn't replacing a pending one, push into queue and potentially mark local + // New transaction isn't replacing a pending one, push into queue replace, err := pool.enqueueTx(hash, tx) if err != nil { return false, err } + // Mark local addresses and journal local transactions if local { pool.locals.add(from) } + pool.journalTx(from, tx) + log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) return replace, nil } @@ -515,6 +601,18 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, er return old != nil, nil } +// journalTx adds the specified transaction to the local disk journal if it is +// deemed to have been sent from a local account. +func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { + // Only journal if it's enabled and the transaction is local + if pool.journal == nil || !pool.locals.contains(from) { + return + } + if err := pool.journal.insert(tx); err != nil { + log.Warn("Failed to journal local transaction", "err", err) + } +} + // promoteTx adds a transaction to the pending (processable) list of transactions. // // Note, this method assumes the pool lock is held! @@ -910,39 +1008,6 @@ func (pool *TxPool) demoteUnexecutables(state *state.StateDB) { } } -// expirationLoop is a loop that periodically iterates over all accounts with -// queued transactions and drop all that have been inactive for a prolonged amount -// of time. -func (pool *TxPool) expirationLoop() { - defer pool.wg.Done() - - evict := time.NewTicker(evictionInterval) - defer evict.Stop() - - for { - select { - case <-evict.C: - pool.mu.Lock() - for addr := range pool.queue { - // Skip local transactions from the eviction mechanism - if pool.locals.contains(addr) { - continue - } - // Any non-locals old enough should be removed - if time.Since(pool.beats[addr]) > pool.config.Lifetime { - for _, tx := range pool.queue[addr].Flatten() { - pool.removeTx(tx.Hash()) - } - } - } - pool.mu.Unlock() - - case <-pool.quit: - return - } - } -} - // addressByHeartbeat is an account address tagged with its last activity timestamp. type addressByHeartbeat struct { address common.Address @@ -955,7 +1020,7 @@ func (a addresssByHeartbeat) Len() int { return len(a) } func (a addresssByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } func (a addresssByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -// accountSet is simply a set of addresses to check for existance, and a signer +// accountSet is simply a set of addresses to check for existence, and a signer // capable of deriving addresses from transactions. type accountSet struct { accounts map[common.Address]struct{} diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 03ece3886..fcb330051 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -19,8 +19,10 @@ package core import ( "crypto/ecdsa" "fmt" + "io/ioutil" "math/big" "math/rand" + "os" "testing" "time" @@ -33,6 +35,15 @@ import ( "github.com/ethereum/go-ethereum/params" ) +// testTxPoolConfig is a transaction pool configuration without stateful disk +// sideeffects used during testing. +var testTxPoolConfig TxPoolConfig + +func init() { + testTxPoolConfig = DefaultTxPoolConfig + testTxPoolConfig.Journal = "" +} + func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { return pricedTransaction(nonce, gaslimit, big.NewInt(1), key) } @@ -47,8 +58,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) key, _ := crypto.GenerateKey() - pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) - pool.resetState() + pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) return pool, key } @@ -125,9 +135,8 @@ func TestStateChangeDuringPoolReset(t *testing.T) { gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) } - pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, mux, stateFunc, gasLimitFunc) + pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, mux, stateFunc, gasLimitFunc) defer pool.Stop() - pool.resetState() nonce := pool.State().GetNonce(address) if nonce != 0 { @@ -144,7 +153,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) { // trigger state change in the background trigger = true - pool.resetState() + pool.lockedReset() pendingTx, err := pool.Pending() if err != nil { @@ -204,7 +213,7 @@ func TestTransactionQueue(t *testing.T) { from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1000)) - pool.resetState() + pool.lockedReset() pool.enqueueTx(tx.Hash(), tx) pool.promoteExecutables(currentState, []common.Address{from}) @@ -226,13 +235,15 @@ func TestTransactionQueue(t *testing.T) { } pool, key = setupTxPool() + defer pool.Stop() + tx1 := transaction(0, big.NewInt(100), key) tx2 := transaction(10, big.NewInt(100), key) tx3 := transaction(11, big.NewInt(100), key) from, _ = deriveSender(tx1) currentState, _ = pool.currentState() currentState.AddBalance(from, big.NewInt(1000)) - pool.resetState() + pool.lockedReset() pool.enqueueTx(tx1.Hash(), tx1) pool.enqueueTx(tx2.Hash(), tx2) @@ -303,7 +314,7 @@ func TestTransactionChainFork(t *testing.T) { pool.currentState = func() (*state.StateDB, error) { return statedb, nil } currentState, _ := pool.currentState() currentState.AddBalance(addr, big.NewInt(100000000000000)) - pool.resetState() + pool.lockedReset() } resetState() @@ -331,7 +342,7 @@ func TestTransactionDoubleNonce(t *testing.T) { pool.currentState = func() (*state.StateDB, error) { return statedb, nil } currentState, _ := pool.currentState() currentState.AddBalance(addr, big.NewInt(100000000000000)) - pool.resetState() + pool.lockedReset() } resetState() @@ -401,14 +412,14 @@ func TestNonceRecovery(t *testing.T) { currentState, _ := pool.currentState() currentState.SetNonce(addr, n) currentState.AddBalance(addr, big.NewInt(100000000000000)) - pool.resetState() + pool.lockedReset() tx := transaction(n, big.NewInt(100000), key) if err := pool.AddRemote(tx); err != nil { t.Error(err) } // simulate some weird re-order of transactions and missing nonce(s) currentState.SetNonce(addr, n-1) - pool.resetState() + pool.lockedReset() if fn := pool.pendingState.GetNonce(addr); fn != n+1 { t.Errorf("expected nonce to be %d, got %d", n+1, fn) } @@ -422,7 +433,7 @@ func TestRemovedTxEvent(t *testing.T) { from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1000000000000)) - pool.resetState() + pool.lockedReset() pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}}) pool.eventMux.Post(ChainHeadEvent{nil}) if pool.pending[from].Len() != 1 { @@ -471,7 +482,7 @@ func TestTransactionDropping(t *testing.T) { if len(pool.all) != 6 { t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6) } - pool.resetState() + pool.lockedReset() if pool.pending[account].Len() != 3 { t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), 3) } @@ -483,7 +494,7 @@ func TestTransactionDropping(t *testing.T) { } // Reduce the balance of the account, and check that invalidated transactions are dropped state.AddBalance(account, big.NewInt(-650)) - pool.resetState() + pool.lockedReset() if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { t.Errorf("funded pending transaction missing: %v", tx0) @@ -508,7 +519,7 @@ func TestTransactionDropping(t *testing.T) { } // Reduce the block gas limit, check that invalidated transactions are dropped pool.gasLimit = func() *big.Int { return big.NewInt(100) } - pool.resetState() + pool.lockedReset() if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { t.Errorf("funded pending transaction missing: %v", tx0) @@ -562,7 +573,7 @@ func TestTransactionPostponing(t *testing.T) { if len(pool.all) != len(txns) { t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)) } - pool.resetState() + pool.lockedReset() if pool.pending[account].Len() != len(txns) { t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns)) } @@ -574,7 +585,7 @@ func TestTransactionPostponing(t *testing.T) { } // Reduce the balance of the account, and check that transactions are reorganised state.AddBalance(account, big.NewInt(-750)) - pool.resetState() + pool.lockedReset() if _, ok := pool.pending[account].txs.items[txns[0].Nonce()]; !ok { t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0]) @@ -615,28 +626,28 @@ func TestTransactionQueueAccountLimiting(t *testing.T) { state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) - pool.resetState() + pool.lockedReset() // Keep queuing up transactions and make sure all above a limit are dropped - for i := uint64(1); i <= DefaultTxPoolConfig.AccountQueue+5; i++ { + for i := uint64(1); i <= testTxPoolConfig.AccountQueue+5; i++ { if err := pool.AddRemote(transaction(i, big.NewInt(100000), key)); err != nil { t.Fatalf("tx %d: failed to add transaction: %v", i, err) } if len(pool.pending) != 0 { t.Errorf("tx %d: pending pool size mismatch: have %d, want %d", i, len(pool.pending), 0) } - if i <= DefaultTxPoolConfig.AccountQueue { + if i <= testTxPoolConfig.AccountQueue { if pool.queue[account].Len() != int(i) { t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), i) } } else { - if pool.queue[account].Len() != int(DefaultTxPoolConfig.AccountQueue) { - t.Errorf("tx %d: queue limit mismatch: have %d, want %d", i, pool.queue[account].Len(), DefaultTxPoolConfig.AccountQueue) + if pool.queue[account].Len() != int(testTxPoolConfig.AccountQueue) { + t.Errorf("tx %d: queue limit mismatch: have %d, want %d", i, pool.queue[account].Len(), testTxPoolConfig.AccountQueue) } } } - if len(pool.all) != int(DefaultTxPoolConfig.AccountQueue) { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), DefaultTxPoolConfig.AccountQueue) + if len(pool.all) != int(testTxPoolConfig.AccountQueue) { + t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue) } } @@ -657,13 +668,12 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - config := DefaultTxPoolConfig + config := testTxPoolConfig config.NoLocals = nolocals config.GlobalQueue = config.AccountQueue*3 - 1 // reduce the queue limits to shorten test time (-1 to make it non divisible) pool := NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) defer pool.Stop() - pool.resetState() // Create a number of test accounts and fund them (last one will be the local) state, _ := pool.currentState() @@ -742,19 +752,18 @@ func TestTransactionQueueTimeLimitingNoLocals(t *testing.T) { testTransactionQue func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { // Reduce the eviction interval to a testable amount defer func(old time.Duration) { evictionInterval = old }(evictionInterval) - evictionInterval = 250 * time.Millisecond + evictionInterval = time.Second // Create the pool to test the non-expiration enforcement db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - config := DefaultTxPoolConfig - config.Lifetime = 250 * time.Millisecond + config := testTxPoolConfig + config.Lifetime = time.Second config.NoLocals = nolocals pool := NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) defer pool.Stop() - pool.resetState() // Create two test accounts to ensure remotes expire but locals do not local, _ := crypto.GenerateKey() @@ -771,7 +780,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { if err := pool.AddRemote(pricedTransaction(1, big.NewInt(100000), big.NewInt(1), remote)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } - pending, queued := pool.stats() + pending, queued := pool.Stats() if pending != 0 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) } @@ -784,7 +793,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { // Wait a bit for eviction to run and clean up any leftovers, and ensure only the local remains time.Sleep(2 * config.Lifetime) - pending, queued = pool.stats() + pending, queued = pool.Stats() if pending != 0 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) } @@ -814,10 +823,10 @@ func TestTransactionPendingLimiting(t *testing.T) { state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) - pool.resetState() + pool.lockedReset() // Keep queuing up transactions and make sure all above a limit are dropped - for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ { + for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { if err := pool.AddRemote(transaction(i, big.NewInt(100000), key)); err != nil { t.Fatalf("tx %d: failed to add transaction: %v", i, err) } @@ -828,8 +837,8 @@ func TestTransactionPendingLimiting(t *testing.T) { t.Errorf("tx %d: queue size mismatch: have %d, want %d", i, pool.queue[account].Len(), 0) } } - if len(pool.all) != int(DefaultTxPoolConfig.AccountQueue+5) { - t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), DefaultTxPoolConfig.AccountQueue+5) + if len(pool.all) != int(testTxPoolConfig.AccountQueue+5) { + t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue+5) } } @@ -841,23 +850,27 @@ func TestTransactionPendingLimitingEquivalency(t *testing.T) { testTransactionLi func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { // Add a batch of transactions to a pool one by one pool1, key1 := setupTxPool() + defer pool1.Stop() + account1, _ := deriveSender(transaction(0, big.NewInt(0), key1)) state1, _ := pool1.currentState() state1.AddBalance(account1, big.NewInt(1000000)) - for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ { + for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { if err := pool1.AddRemote(transaction(origin+i, big.NewInt(100000), key1)); err != nil { t.Fatalf("tx %d: failed to add transaction: %v", i, err) } } // Add a batch of transactions to a pool in one big batch pool2, key2 := setupTxPool() + defer pool2.Stop() + account2, _ := deriveSender(transaction(0, big.NewInt(0), key2)) state2, _ := pool2.currentState() state2.AddBalance(account2, big.NewInt(1000000)) txns := []*types.Transaction{} - for i := uint64(0); i < DefaultTxPoolConfig.AccountQueue+5; i++ { + for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { txns = append(txns, transaction(origin+i, big.NewInt(100000), key2)) } pool2.AddRemotes(txns) @@ -888,12 +901,11 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - config := DefaultTxPoolConfig + config := testTxPoolConfig config.GlobalSlots = config.AccountSlots * 10 pool := NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) defer pool.Stop() - pool.resetState() // Create a number of test accounts and fund them state, _ := pool.currentState() @@ -935,14 +947,13 @@ func TestTransactionCapClearsFromAll(t *testing.T) { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - config := DefaultTxPoolConfig + config := testTxPoolConfig config.AccountSlots = 2 config.AccountQueue = 2 config.GlobalSlots = 8 pool := NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) defer pool.Stop() - pool.resetState() // Create a number of test accounts and fund them state, _ := pool.currentState() @@ -970,12 +981,11 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - config := DefaultTxPoolConfig + config := testTxPoolConfig config.GlobalSlots = 0 pool := NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) defer pool.Stop() - pool.resetState() // Create a number of test accounts and fund them state, _ := pool.currentState() @@ -1019,9 +1029,8 @@ func TestTransactionPoolRepricing(t *testing.T) { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) defer pool.Stop() - pool.resetState() // Create a number of test accounts and fund them state, _ := pool.currentState() @@ -1048,7 +1057,7 @@ func TestTransactionPoolRepricing(t *testing.T) { pool.AddRemotes(txs) pool.AddLocal(ltx) - pending, queued := pool.stats() + pending, queued := pool.Stats() if pending != 4 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) } @@ -1061,7 +1070,7 @@ func TestTransactionPoolRepricing(t *testing.T) { // Reprice the pool and check that underpriced transactions get dropped pool.SetGasPrice(big.NewInt(2)) - pending, queued = pool.stats() + pending, queued = pool.Stats() if pending != 2 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) } @@ -1086,7 +1095,7 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := pool.AddLocal(tx); err != nil { t.Fatalf("failed to add underpriced local transaction: %v", err) } - if pending, _ = pool.stats(); pending != 3 { + if pending, _ = pool.Stats(); pending != 3 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) } if err := validateTxPoolInternals(pool); err != nil { @@ -1104,13 +1113,12 @@ func TestTransactionPoolUnderpricing(t *testing.T) { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - config := DefaultTxPoolConfig + config := testTxPoolConfig config.GlobalSlots = 2 config.GlobalQueue = 2 pool := NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) defer pool.Stop() - pool.resetState() // Create a number of test accounts and fund them state, _ := pool.currentState() @@ -1134,7 +1142,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { pool.AddRemotes(txs) pool.AddLocal(ltx) - pending, queued := pool.stats() + pending, queued := pool.Stats() if pending != 3 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) } @@ -1158,7 +1166,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if err := pool.AddRemote(pricedTransaction(3, big.NewInt(100000), big.NewInt(5), keys[1])); err != nil { t.Fatalf("failed to add well priced transaction: %v", err) } - pending, queued = pool.stats() + pending, queued = pool.Stats() if pending != 2 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) } @@ -1173,7 +1181,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if err := pool.AddLocal(tx); err != nil { t.Fatalf("failed to add underpriced local transaction: %v", err) } - pending, queued = pool.stats() + pending, queued = pool.Stats() if pending != 2 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) } @@ -1192,9 +1200,8 @@ func TestTransactionReplacement(t *testing.T) { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - pool := NewTxPool(DefaultTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) defer pool.Stop() - pool.resetState() // Create a test account to add transactions with key, _ := crypto.GenerateKey() @@ -1204,7 +1211,7 @@ func TestTransactionReplacement(t *testing.T) { // Add pending transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) price := int64(100) - threshold := (price * (100 + int64(DefaultTxPoolConfig.PriceBump))) / 100 + threshold := (price * (100 + int64(testTxPoolConfig.PriceBump))) / 100 if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), key)); err != nil { t.Fatalf("failed to add original cheap pending transaction: %v", err) @@ -1250,6 +1257,114 @@ func TestTransactionReplacement(t *testing.T) { } } +// Tests that local transactions are journaled to disk, but remote transactions +// get discarded between restarts. +func TestTransactionJournaling(t *testing.T) { testTransactionJournaling(t, false) } +func TestTransactionJournalingNoLocals(t *testing.T) { testTransactionJournaling(t, true) } + +func testTransactionJournaling(t *testing.T, nolocals bool) { + // Create a temporary file for the journal + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("failed to create temporary journal: %v", err) + } + journal := file.Name() + defer os.Remove(journal) + + // Clean up the temporary file, we only need the path for now + file.Close() + os.Remove(journal) + + // Create the original pool to inject transaction into the journal + db, _ := ethdb.NewMemDatabase() + statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) + + config := testTxPoolConfig + config.NoLocals = nolocals + config.Journal = journal + config.Rejournal = time.Second + + pool := NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + + // Create two test accounts to ensure remotes expire but locals do not + local, _ := crypto.GenerateKey() + remote, _ := crypto.GenerateKey() + + statedb, _ = pool.currentState() + statedb.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(1000000000)) + statedb.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) + + // Add three local and a remote transactions and ensure they are queued up + if err := pool.AddLocal(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), local)); err != nil { + t.Fatalf("failed to add local transaction: %v", err) + } + if err := pool.AddLocal(pricedTransaction(1, big.NewInt(100000), big.NewInt(1), local)); err != nil { + t.Fatalf("failed to add local transaction: %v", err) + } + if err := pool.AddLocal(pricedTransaction(2, big.NewInt(100000), big.NewInt(1), local)); err != nil { + t.Fatalf("failed to add local transaction: %v", err) + } + if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), remote)); err != nil { + t.Fatalf("failed to add remote transaction: %v", err) + } + pending, queued := pool.Stats() + if pending != 4 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4) + } + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) + } + if err := validateTxPoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } + // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive + pool.Stop() + statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) + pool = NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + + pending, queued = pool.Stats() + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) + } + if nolocals { + if pending != 0 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) + } + } else { + if pending != 2 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) + } + } + if err := validateTxPoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } + // Bump the nonce temporarily and ensure the newly invalidated transaction is removed + statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 2) + pool.lockedReset() + time.Sleep(2 * config.Rejournal) + pool.Stop() + statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) + pool = NewTxPool(config, params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + + pending, queued = pool.Stats() + if pending != 0 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0) + } + if nolocals { + if queued != 0 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) + } + } else { + if queued != 1 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) + } + } + if err := validateTxPoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } + pool.Stop() +} + // Benchmarks the speed of validating the contents of the pending queue of the // transaction pool. func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) } diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index edbd64ba4..eb2e5d42b 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -13,7 +13,7 @@ import ( func (r Receipt) MarshalJSON() ([]byte, error) { type Receipt struct { - PostState hexutil.Bytes `json:"root" gencodec:"required"` + PostState hexutil.Bytes `json:"root"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -34,7 +34,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { func (r *Receipt) UnmarshalJSON(input []byte) error { type Receipt struct { - PostState hexutil.Bytes `json:"root" gencodec:"required"` + PostState hexutil.Bytes `json:"root"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` Bloom *Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -46,10 +46,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { if err := json.Unmarshal(input, &dec); err != nil { return err } - if dec.PostState == nil { - return errors.New("missing required field 'root' for Receipt") + if dec.PostState != nil { + r.PostState = dec.PostState } - r.PostState = dec.PostState if dec.CumulativeGasUsed == nil { return errors.New("missing required field 'cumulativeGasUsed' for Receipt") } diff --git a/core/types/receipt.go b/core/types/receipt.go index ef6f6a2bb..c9906b015 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -31,7 +31,7 @@ import ( // Receipt represents the results of a transaction. type Receipt struct { // Consensus fields - PostState []byte `json:"root" gencodec:"required"` + PostState []byte `json:"root"` CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -48,35 +48,88 @@ type receiptMarshaling struct { GasUsed *hexutil.Big } +// homesteadReceiptRLP contains the receipt's Homestead consensus fields, used +// during RLP serialization. +type homesteadReceiptRLP struct { + PostState []byte + CumulativeGasUsed *big.Int + Bloom Bloom + Logs []*Log +} + +// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used +// during RLP serialization. +type metropolisReceiptRLP struct { + CumulativeGasUsed *big.Int + Bloom Bloom + Logs []*Log +} + // NewReceipt creates a barebone transaction receipt, copying the init fields. func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} } // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt -// into an RLP stream. +// into an RLP stream. If no post state is present, metropolis fork is assumed. func (r *Receipt) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs}) + if r.PostState == nil { + return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs}) + } + return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs}) } // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt // from an RLP stream. func (r *Receipt) DecodeRLP(s *rlp.Stream) error { - var receipt struct { - PostState []byte - CumulativeGasUsed *big.Int - Bloom Bloom - Logs []*Log + // Load the raw bytes since we have multiple possible formats + raw, err := s.Raw() + if err != nil { + return err } - if err := s.Decode(&receipt); err != nil { + list, _, err := rlp.SplitList(raw) + if err != nil { return err } - r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs - return nil + items, err := rlp.CountValues(list) + if err != nil { + return err + } + // Deserialize based on the number of content items + switch items { + case 3: + // Metropolis receipts have 3 components + var metro metropolisReceiptRLP + if err := rlp.DecodeBytes(raw, &metro); err != nil { + return err + } + r.CumulativeGasUsed = metro.CumulativeGasUsed + r.Bloom = metro.Bloom + r.Logs = metro.Logs + return nil + + case 4: + // Homestead receipts have 4 components + var home homesteadReceiptRLP + if err := rlp.DecodeBytes(raw, &home); err != nil { + return err + } + r.PostState = home.PostState[:] + r.CumulativeGasUsed = home.CumulativeGasUsed + r.Bloom = home.Bloom + r.Logs = home.Logs + return nil + + default: + return fmt.Errorf("invalid receipt components: %v", items) + } } // String implements the Stringer interface. func (r *Receipt) String() string { + if r.PostState == nil { + return fmt.Sprintf("receipt{cgas=%v bloom=%x logs=%v}", r.CumulativeGasUsed, r.Bloom, r.Logs) + } return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs) } diff --git a/core/vm/common.go b/core/vm/common.go index 779cee006..17de38dec 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -34,7 +34,21 @@ func calcMemSize(off, l *big.Int) *big.Int { // getData returns a slice from the data based on the start and size and pads // up to size with zero's. This function is overflow safe. -func getData(data []byte, start, size *big.Int) []byte { +func getData(data []byte, start uint64, size uint64) []byte { + length := uint64(len(data)) + if start > length { + start = length + } + end := start + size + if end > length { + end = length + } + return common.RightPadBytes(data[start:end], int(size)) +} + +// getDataBig returns a slice from the data based on the start and size and pads +// up to size with zero's. This function is overflow safe. +func getDataBig(data []byte, start *big.Int, size *big.Int) []byte { dlen := big.NewInt(int64(len(data))) s := math.BigMin(start, dlen) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 90b2f913e..790d42bbe 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -22,15 +22,14 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/params" "golang.org/x/crypto/ripemd160" ) -var errBadPrecompileInput = errors.New("bad pre compile input") - -// Precompiled contract is the basic interface for native Go contracts. The implementation +// PrecompiledContract is the basic interface for native Go contracts. The implementation // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { @@ -38,52 +37,63 @@ type PrecompiledContract interface { Run(input []byte) ([]byte, error) // Run runs the precompiled contract } -// PrecompiledContracts contains the default set of ethereum contracts -var PrecompiledContracts = map[common.Address]PrecompiledContract{ +// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum +// contracts used in the Frontier and Homestead releases. +var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{4}): &dataCopy{}, } -// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go +// PrecompiledContractsMetropolis contains the default set of pre-compiled Ethereum +// contracts used in the Metropolis release. +var PrecompiledContractsMetropolis = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{1}): &ecrecover{}, + common.BytesToAddress([]byte{2}): &sha256hash{}, + common.BytesToAddress([]byte{3}): &ripemd160hash{}, + common.BytesToAddress([]byte{4}): &dataCopy{}, + common.BytesToAddress([]byte{5}): &bigModExp{}, + common.BytesToAddress([]byte{6}): &bn256Add{}, + common.BytesToAddress([]byte{7}): &bn256ScalarMul{}, + common.BytesToAddress([]byte{8}): &bn256Pairing{}, +} + +// RunPrecompiledContract runs and evaluates the output of a precompiled contract. func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { gas := p.RequiredGas(input) if contract.UseGas(gas) { return p.Run(input) - } else { - return nil, ErrOutOfGas } + return nil, ErrOutOfGas } -// ECRECOVER implemented as a native contract +// ECRECOVER implemented as a native contract. type ecrecover struct{} func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(in []byte) ([]byte, error) { +func (c *ecrecover) Run(input []byte) ([]byte, error) { const ecRecoverInputLength = 128 - in = common.RightPadBytes(in, ecRecoverInputLength) - // "in" is (hash, v, r, s), each 32 bytes + input = common.RightPadBytes(input, ecRecoverInputLength) + // "input" is (hash, v, r, s), each 32 bytes // but for ecrecover we want (r, s, v) - r := new(big.Int).SetBytes(in[64:96]) - s := new(big.Int).SetBytes(in[96:128]) - v := in[63] - 27 + r := new(big.Int).SetBytes(input[64:96]) + s := new(big.Int).SetBytes(input[96:128]) + v := input[63] - 27 - // tighter sig s values in homestead only apply to tx sigs - if !allZero(in[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { - log.Trace("ECRECOVER error: v, r or s value invalid") + // tighter sig s values input homestead only apply to tx sigs + if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { return nil, nil } // v needs to be at the end for libsecp256k1 - pubKey, err := crypto.Ecrecover(in[:32], append(in[64:128], v)) + pubKey, err := crypto.Ecrecover(input[:32], append(input[64:128], v)) // make sure the public key is a valid one if err != nil { - log.Trace("ECRECOVER failed", "err", err) return nil, nil } @@ -91,7 +101,7 @@ func (c *ecrecover) Run(in []byte) ([]byte, error) { return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil } -// SHA256 implemented as a native contract +// SHA256 implemented as a native contract. type sha256hash struct{} // RequiredGas returns the gas required to execute the pre-compiled contract. @@ -99,14 +109,14 @@ type sha256hash struct{} // This method does not require any overflow checking as the input size gas costs // required for anything significant is so high it's impossible to pay for. func (c *sha256hash) RequiredGas(input []byte) uint64 { - return uint64(len(input)+31)/32*params.Sha256WordGas + params.Sha256Gas + return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas } -func (c *sha256hash) Run(in []byte) ([]byte, error) { - h := sha256.Sum256(in) +func (c *sha256hash) Run(input []byte) ([]byte, error) { + h := sha256.Sum256(input) return h[:], nil } -// RIPMED160 implemented as a native contract +// RIPMED160 implemented as a native contract. type ripemd160hash struct{} // RequiredGas returns the gas required to execute the pre-compiled contract. @@ -114,15 +124,15 @@ type ripemd160hash struct{} // This method does not require any overflow checking as the input size gas costs // required for anything significant is so high it's impossible to pay for. func (c *ripemd160hash) RequiredGas(input []byte) uint64 { - return uint64(len(input)+31)/32*params.Ripemd160WordGas + params.Ripemd160Gas + return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas } -func (c *ripemd160hash) Run(in []byte) ([]byte, error) { +func (c *ripemd160hash) Run(input []byte) ([]byte, error) { ripemd := ripemd160.New() - ripemd.Write(in) + ripemd.Write(input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil } -// data copy implemented as a native contract +// data copy implemented as a native contract. type dataCopy struct{} // RequiredGas returns the gas required to execute the pre-compiled contract. @@ -130,8 +140,240 @@ type dataCopy struct{} // This method does not require any overflow checking as the input size gas costs // required for anything significant is so high it's impossible to pay for. func (c *dataCopy) RequiredGas(input []byte) uint64 { - return uint64(len(input)+31)/32*params.IdentityWordGas + params.IdentityGas + return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } func (c *dataCopy) Run(in []byte) ([]byte, error) { return in, nil } + +// bigModExp implements a native big integer exponential modular operation. +type bigModExp struct{} + +var ( + big1 = big.NewInt(1) + big4 = big.NewInt(4) + big8 = big.NewInt(8) + big16 = big.NewInt(16) + big32 = big.NewInt(32) + big64 = big.NewInt(64) + big96 = big.NewInt(96) + big480 = big.NewInt(480) + big1024 = big.NewInt(1024) + big3072 = big.NewInt(3072) + big199680 = big.NewInt(199680) +) + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bigModExp) RequiredGas(input []byte) uint64 { + var ( + baseLen = new(big.Int).SetBytes(getData(input, 0, 32)) + expLen = new(big.Int).SetBytes(getData(input, 32, 32)) + modLen = new(big.Int).SetBytes(getData(input, 64, 32)) + ) + if len(input) > 96 { + input = input[96:] + } else { + input = input[:0] + } + // Retrieve the head 32 bytes of exp for the adjusted exponent length + var expHead *big.Int + if big.NewInt(int64(len(input))).Cmp(baseLen) <= 0 { + expHead = new(big.Int) + } else { + if expLen.Cmp(big32) > 0 { + expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), 32)) + } else { + expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), expLen.Uint64())) + } + } + // Calculate the adjusted exponent length + var msb int + if bitlen := expHead.BitLen(); bitlen > 0 { + msb = bitlen - 1 + } + adjExpLen := new(big.Int) + if expLen.Cmp(big32) > 0 { + adjExpLen.Sub(expLen, big32) + adjExpLen.Mul(big8, adjExpLen) + } + adjExpLen.Add(adjExpLen, big.NewInt(int64(msb))) + + // Calculate the gas cost of the operation + gas := new(big.Int).Set(math.BigMax(modLen, baseLen)) + switch { + case gas.Cmp(big64) <= 0: + gas.Mul(gas, gas) + case gas.Cmp(big1024) <= 0: + gas = new(big.Int).Add( + new(big.Int).Div(new(big.Int).Mul(gas, gas), big4), + new(big.Int).Sub(new(big.Int).Mul(big96, gas), big3072), + ) + default: + gas = new(big.Int).Add( + new(big.Int).Div(new(big.Int).Mul(gas, gas), big16), + new(big.Int).Sub(new(big.Int).Mul(big480, gas), big199680), + ) + } + gas.Mul(gas, math.BigMax(adjExpLen, big1)) + gas.Div(gas, new(big.Int).SetUint64(params.ModExpQuadCoeffDiv)) + + if gas.BitLen() > 64 { + return math.MaxUint64 + } + return gas.Uint64() +} + +func (c *bigModExp) Run(input []byte) ([]byte, error) { + var ( + baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() + expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() + modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64() + ) + if len(input) > 96 { + input = input[96:] + } else { + input = input[:0] + } + // Handle a special case when both the base and mod length is zero + if baseLen == 0 && modLen == 0 { + return []byte{}, nil + } + // Retrieve the operands and execute the exponentiation + var ( + base = new(big.Int).SetBytes(getData(input, 0, baseLen)) + exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) + mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + ) + if mod.BitLen() == 0 { + // Modulo 0 is undefined, return zero + return common.LeftPadBytes([]byte{}, int(modLen)), nil + } + return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil +} + +var ( + // errNotOnCurve is returned if a point being unmarshalled as a bn256 elliptic + // curve point is not on the curve. + errNotOnCurve = errors.New("point not on elliptic curve") + + // errInvalidCurvePoint is returned if a point being unmarshalled as a bn256 + // elliptic curve point is invalid. + errInvalidCurvePoint = errors.New("invalid elliptic curve point") +) + +// newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point, +// returning it, or an error if the point is invalid. +func newCurvePoint(blob []byte) (*bn256.G1, error) { + p, onCurve := new(bn256.G1).Unmarshal(blob) + if !onCurve { + return nil, errNotOnCurve + } + gx, gy, _, _ := p.CurvePoints() + if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + return p, nil +} + +// newTwistPoint unmarshals a binary blob into a bn256 elliptic curve point, +// returning it, or an error if the point is invalid. +func newTwistPoint(blob []byte) (*bn256.G2, error) { + p, onCurve := new(bn256.G2).Unmarshal(blob) + if !onCurve { + return nil, errNotOnCurve + } + x2, y2, _, _ := p.CurvePoints() + if x2.Real().Cmp(bn256.P) >= 0 || x2.Imag().Cmp(bn256.P) >= 0 || + y2.Real().Cmp(bn256.P) >= 0 || y2.Imag().Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + return p, nil +} + +// bn256Add implements a native elliptic curve point addition. +type bn256Add struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256Add) RequiredGas(input []byte) uint64 { + return params.Bn256AddGas +} + +func (c *bn256Add) Run(input []byte) ([]byte, error) { + x, err := newCurvePoint(getData(input, 0, 64)) + if err != nil { + return nil, err + } + y, err := newCurvePoint(getData(input, 64, 64)) + if err != nil { + return nil, err + } + res := new(bn256.G1) + res.Add(x, y) + return res.Marshal(), nil +} + +// bn256ScalarMul implements a native elliptic curve scalar multiplication. +type bn256ScalarMul struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 { + return params.Bn256ScalarMulGas +} + +func (c *bn256ScalarMul) Run(input []byte) ([]byte, error) { + p, err := newCurvePoint(getData(input, 0, 64)) + if err != nil { + return nil, err + } + res := new(bn256.G1) + res.ScalarMult(p, new(big.Int).SetBytes(getData(input, 64, 32))) + return res.Marshal(), nil +} + +var ( + // true32Byte is returned if the bn256 pairing check succeeds. + true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + + // false32Byte is returned if the bn256 pairing check fails. + false32Byte = make([]byte, 32) + + // errBadPairingInput is returned if the bn256 pairing input is invalid. + errBadPairingInput = errors.New("bad elliptic curve pairing size") +) + +// bn256Pairing implements a pairing pre-compile for the bn256 curve +type bn256Pairing struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *bn256Pairing) RequiredGas(input []byte) uint64 { + return params.Bn256PairingBaseGas + uint64(len(input)/192)*params.Bn256PairingPerPointGas +} + +func (c *bn256Pairing) Run(input []byte) ([]byte, error) { + // Handle some corner cases cheaply + if len(input)%192 > 0 { + return nil, errBadPairingInput + } + // Convert the input into a set of coordinates + var ( + cs []*bn256.G1 + ts []*bn256.G2 + ) + for i := 0; i < len(input); i += 192 { + c, err := newCurvePoint(input[i : i+64]) + if err != nil { + return nil, err + } + t, err := newTwistPoint(input[i+64 : i+192]) + if err != nil { + return nil, err + } + cs = append(cs, c) + ts = append(ts, t) + } + // Execute the pairing checks and return the results + if bn256.PairingCheck(cs, ts) { + return true32Byte, nil + } + return false32Byte, nil +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 830a8f69d..022070ab8 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -1 +1,391 @@ package vm + +import ( + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +// precompiledTest defines the input/output pairs for precompiled contract tests. +type precompiledTest struct { + input, expected string + gas uint64 + name string +} + +// modexpTests are the test and benchmark data for the modexp precompiled contract. +var modexpTests = []precompiledTest{ + { + input: "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000020" + + "03" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "eip_example1", + }, { + input: "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000020" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + expected: "0000000000000000000000000000000000000000000000000000000000000000", + name: "eip_example2", + }, { + input: "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb502fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + expected: "60008f1614cc01dcfb6bfb09c625cf90b47d4468db81b5f8b7a39d42f332eab9b2da8f2d95311648a8f243f4bb13cfb3d8f7f2a3c014122ebb3ed41b02783adc", + name: "nagydani-1-square", + }, { + input: "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb503fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + expected: "4834a46ba565db27903b1c720c9d593e84e4cbd6ad2e64b31885d944f68cd801f92225a8961c952ddf2797fa4701b330c85c4b363798100b921a1a22a46a7fec", + name: "nagydani-1-qube", + }, { + input: "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5010001fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + expected: "c36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2", + name: "nagydani-1-pow0x10001", + }, { + input: "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5102e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + expected: "981dd99c3b113fae3e3eaa9435c0dc96779a23c12a53d1084b4f67b0b053a27560f627b873e3f16ad78f28c94f14b6392def26e4d8896c5e3c984e50fa0b3aa44f1da78b913187c6128baa9340b1e9c9a0fd02cb78885e72576da4a8f7e5a113e173a7a2889fde9d407bd9f06eb05bc8fc7b4229377a32941a02bf4edcc06d70", + name: "nagydani-2-square", + }, { + input: "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5103e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + expected: "d89ceb68c32da4f6364978d62aaa40d7b09b59ec61eb3c0159c87ec3a91037f7dc6967594e530a69d049b64adfa39c8fa208ea970cfe4b7bcd359d345744405afe1cbf761647e32b3184c7fbe87cee8c6c7ff3b378faba6c68b83b6889cb40f1603ee68c56b4c03d48c595c826c041112dc941878f8c5be828154afd4a16311f", + name: "nagydani-2-qube", + }, { + input: "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51010001e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + expected: "ad85e8ef13fd1dd46eae44af8b91ad1ccae5b7a1c92944f92a19f21b0b658139e0cabe9c1f679507c2de354bf2c91ebd965d1e633978a830d517d2f6f8dd5fd58065d58559de7e2334a878f8ec6992d9b9e77430d4764e863d77c0f87beede8f2f7f2ab2e7222f85cc9d98b8467f4bb72e87ef2882423ebdb6daf02dddac6db2", + name: "nagydani-2-pow0x10001", + }, { + input: "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb02d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + expected: "affc7507ea6d84751ec6b3f0d7b99dbcc263f33330e450d1b3ff0bc3d0874320bf4edd57debd587306988157958cb3cfd369cc0c9c198706f635c9e0f15d047df5cb44d03e2727f26b083c4ad8485080e1293f171c1ed52aef5993a5815c35108e848c951cf1e334490b4a539a139e57b68f44fee583306f5b85ffa57206b3ee5660458858534e5386b9584af3c7f67806e84c189d695e5eb96e1272d06ec2df5dc5fabc6e94b793718c60c36be0a4d031fc84cd658aa72294b2e16fc240aef70cb9e591248e38bd49c5a554d1afa01f38dab72733092f7555334bbef6c8c430119840492380aa95fa025dcf699f0a39669d812b0c6946b6091e6e235337b6f8", + name: "nagydani-3-square", + }, { + input: "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb03d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + expected: "1b280ecd6a6bf906b806d527c2a831e23b238f89da48449003a88ac3ac7150d6a5e9e6b3be4054c7da11dd1e470ec29a606f5115801b5bf53bc1900271d7c3ff3cd5ed790d1c219a9800437a689f2388ba1a11d68f6a8e5b74e9a3b1fac6ee85fc6afbac599f93c391f5dc82a759e3c6c0ab45ce3f5d25d9b0c1bf94cf701ea6466fc9a478dacc5754e593172b5111eeba88557048bceae401337cd4c1182ad9f700852bc8c99933a193f0b94cf1aedbefc48be3bc93ef5cb276d7c2d5462ac8bb0c8fe8923a1db2afe1c6b90d59c534994a6a633f0ead1d638fdc293486bb634ff2c8ec9e7297c04241a61c37e3ae95b11d53343d4ba2b4cc33d2cfa7eb705e", + name: "nagydani-3-qube", + }, { + input: "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb010001d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + expected: "37843d7c67920b5f177372fa56e2a09117df585f81df8b300fba245b1175f488c99476019857198ed459ed8d9799c377330e49f4180c4bf8e8f66240c64f65ede93d601f957b95b83efdee1e1bfde74169ff77002eaf078c71815a9220c80b2e3b3ff22c2f358111d816ebf83c2999026b6de50bfc711ff68705d2f40b753424aefc9f70f08d908b5a20276ad613b4ab4309a3ea72f0c17ea9df6b3367d44fb3acab11c333909e02e81ea2ed404a712d3ea96bba87461720e2d98723e7acd0520ac1a5212dbedcd8dc0c1abf61d4719e319ff4758a774790b8d463cdfe131d1b2dcfee52d002694e98e720cb6ae7ccea353bc503269ba35f0f63bf8d7b672a76", + name: "nagydani-3-pow0x10001", + }, { + input: "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8102df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + expected: "8a5aea5f50dcc03dc7a7a272b5aeebc040554dbc1ffe36753c4fc75f7ed5f6c2cc0de3a922bf96c78bf0643a73025ad21f45a4a5cadd717612c511ab2bff1190fe5f1ae05ba9f8fe3624de1de2a817da6072ddcdb933b50216811dbe6a9ca79d3a3c6b3a476b079fd0d05f04fb154e2dd3e5cb83b148a006f2bcbf0042efb2ae7b916ea81b27aac25c3bf9a8b6d35440062ad8eae34a83f3ffa2cc7b40346b62174a4422584f72f95316f6b2bee9ff232ba9739301c97c99a9ded26c45d72676eb856ad6ecc81d36a6de36d7f9dafafee11baa43a4b0d5e4ecffa7b9b7dcefd58c397dd373e6db4acd2b2c02717712e6289bed7c813b670c4a0c6735aa7f3b0f1ce556eae9fcc94b501b2c8781ba50a8c6220e8246371c3c7359fe4ef9da786ca7d98256754ca4e496be0a9174bedbecb384bdf470779186d6a833f068d2838a88d90ef3ad48ff963b67c39cc5a3ee123baf7bf3125f64e77af7f30e105d72c4b9b5b237ed251e4c122c6d8c1405e736299c3afd6db16a28c6a9cfa68241e53de4cd388271fe534a6a9b0dbea6171d170db1b89858468885d08fecbd54c8e471c3e25d48e97ba450b96d0d87e00ac732aaa0d3ce4309c1064bd8a4c0808a97e0143e43a24cfa847635125cd41c13e0574487963e9d725c01375db99c31da67b4cf65eff555f0c0ac416c727ff8d438ad7c42030551d68c2e7adda0abb1ca7c10", + name: "nagydani-4-square", + }, { + input: "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8103df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + expected: "5a2664252aba2d6e19d9600da582cdd1f09d7a890ac48e6b8da15ae7c6ff1856fc67a841ac2314d283ffa3ca81a0ecf7c27d89ef91a5a893297928f5da0245c99645676b481b7e20a566ee6a4f2481942bee191deec5544600bb2441fd0fb19e2ee7d801ad8911c6b7750affec367a4b29a22942c0f5f4744a4e77a8b654da2a82571037099e9c6d930794efe5cdca73c7b6c0844e386bdca8ea01b3d7807146bb81365e2cdc6475f8c23e0ff84463126189dc9789f72bbce2e3d2d114d728a272f1345122de23df54c922ec7a16e5c2a8f84da8871482bd258c20a7c09bbcd64c7a96a51029bbfe848736a6ba7bf9d931a9b7de0bcaf3635034d4958b20ae9ab3a95a147b0421dd5f7ebff46c971010ebfc4adbbe0ad94d5498c853e7142c450d8c71de4b2f84edbf8acd2e16d00c8115b150b1c30e553dbb82635e781379fe2a56360420ff7e9f70cc64c00aba7e26ed13c7c19622865ae07248daced36416080f35f8cc157a857ed70ea4f347f17d1bee80fa038abd6e39b1ba06b97264388b21364f7c56e192d4b62d9b161405f32ab1e2594e86243e56fcf2cb30d21adef15b9940f91af681da24328c883d892670c6aa47940867a81830a82b82716895db810df1b834640abefb7db2092dd92912cb9a735175bc447be40a503cf22dfe565b4ed7a3293ca0dfd63a507430b323ee248ec82e843b673c97ad730728cebc", + name: "nagydani-4-qube", + }, { + input: "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81010001df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + expected: "bed8b970c4a34849fc6926b08e40e20b21c15ed68d18f228904878d4370b56322d0da5789da0318768a374758e6375bfe4641fca5285ec7171828922160f48f5ca7efbfee4d5148612c38ad683ae4e3c3a053d2b7c098cf2b34f2cb19146eadd53c86b2d7ccf3d83b2c370bfb840913ee3879b1057a6b4e07e110b6bcd5e958bc71a14798c91d518cc70abee264b0d25a4110962a764b364ac0b0dd1ee8abc8426d775ec0f22b7e47b32576afaf1b5a48f64573ed1c5c29f50ab412188d9685307323d990802b81dacc06c6e05a1e901830ba9fcc67688dc29c5e27bde0a6e845ca925f5454b6fb3747edfaa2a5820838fb759eadf57f7cb5cec57fc213ddd8a4298fa079c3c0f472b07fb15aa6a7f0a3780bd296ff6a62e58ef443870b02260bd4fd2bbc98255674b8e1f1f9f8d33c7170b0ebbea4523b695911abbf26e41885344823bd0587115fdd83b721a4e8457a31c9a84b3d3520a07e0e35df7f48e5a9d534d0ec7feef1ff74de6a11e7f93eab95175b6ce22c68d78a642ad642837897ec11349205d8593ac19300207572c38d29ca5dfa03bc14cdbc32153c80e5cc3e739403d34c75915e49beb43094cc6dcafb3665b305ddec9286934ae66ec6b777ca528728c851318eb0f207b39f1caaf96db6eeead6b55ed08f451939314577d42bcc9f97c0b52d0234f88fd07e4c1d7780fdebc025cfffcb572cb27a8c33963", + name: "nagydani-4-pow0x10001", + }, { + input: "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf02e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + expected: "d61fe4e3f32ac260915b5b03b78a86d11bfc41d973fce5b0cc59035cf8289a8a2e3878ea15fa46565b0d806e2f85b53873ea20ed653869b688adf83f3ef444535bf91598ff7e80f334fb782539b92f39f55310cc4b35349ab7b278346eda9bc37c0d8acd3557fae38197f412f8d9e57ce6a76b7205c23564cab06e5615be7c6f05c3d05ec690cba91da5e89d55b152ff8dd2157dc5458190025cf94b1ad98f7cbe64e9482faba95e6b33844afc640892872b44a9932096508f4a782a4805323808f23e54b6ff9b841dbfa87db3505ae4f687972c18ea0f0d0af89d36c1c2a5b14560c153c3fee406f5cf15cfd1c0bb45d767426d465f2f14c158495069d0c5955a00150707862ecaae30624ebacdd8ac33e4e6aab3ff90b6ba445a84689386b9e945d01823a65874444316e83767290fcff630d2477f49d5d8ffdd200e08ee1274270f86ed14c687895f6caf5ce528bd970c20d2408a9ba66216324c6a011ac4999098362dbd98a038129a2d40c8da6ab88318aa3046cb660327cc44236d9e5d2163bd0959062195c51ed93d0088b6f92051fc99050ece2538749165976233697ab4b610385366e5ce0b02ad6b61c168ecfbedcdf74278a38de340fd7a5fead8e588e294795f9b011e2e60377a89e25c90e145397cdeabc60fd32444a6b7642a611a83c464d8b8976666351b4865c37b02e6dc21dbcdf5f930341707b618cc0f03c3122646b3385c9df9f2ec730eec9d49e7dfc9153b6e6289da8c4f0ebea9ccc1b751948e3bb7171c9e4d57423b0eeeb79095c030cb52677b3f7e0b45c30f645391f3f9c957afa549c4e0b2465b03c67993cd200b1af01035962edbc4c9e89b31c82ac121987d6529dafdeef67a132dc04b6dc68e77f22862040b75e2ceb9ff16da0fca534e6db7bd12fa7b7f51b6c08c1e23dfcdb7acbd2da0b51c87ffbced065a612e9b1c8bba9b7e2d8d7a2f04fcc4aaf355b60d764879a76b5e16762d5f2f55d585d0c8e82df6940960cddfb72c91dfa71f6b4e1c6ca25dfc39a878e998a663c04fe29d5e83b9586d047b4d7ff70a9f0d44f127e7d741685ca75f11629128d916a0ffef4be586a30c4b70389cc746e84ebf177c01ee8a4511cfbb9d1ecf7f7b33c7dd8177896e10bbc82f838dcd6db7ac67de62bf46b6a640fb580c5d1d2708f3862e3d2b645d0d18e49ef088053e3a220adc0e033c2afcfe61c90e32151152eb3caaf746c5e377d541cafc6cbb0cc0fa48b5caf1728f2e1957f5addfc234f1a9d89e40d49356c9172d0561a695fce6dab1d412321bbf407f63766ffd7b6b3d79bcfa07991c5a9709849c1008689e3b47c50d613980bec239fb64185249d055b30375ccb4354d71fe4d05648fbf6c80634dfc3575f2f24abb714c1e4c95e8896763bf4316e954c7ad19e5780ab7a040ca6fb9271f90a8b22ae738daf6cb", + name: "nagydani-5-square", + }, { + input: "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf03e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + expected: "5f9c70ec884926a89461056ad20ac4c30155e817f807e4d3f5bb743d789c83386762435c3627773fa77da5144451f2a8aad8adba88e0b669f5377c5e9bad70e45c86fe952b613f015a9953b8a5de5eaee4566acf98d41e327d93a35bd5cef4607d025e58951167957df4ff9b1627649d3943805472e5e293d3efb687cfd1e503faafeb2840a3e3b3f85d016051a58e1c9498aab72e63b748d834b31eb05d85dcde65e27834e266b85c75cc4ec0135135e0601cb93eeeb6e0010c8ceb65c4c319623c5e573a2c8c9fbbf7df68a930beb412d3f4dfd146175484f45d7afaa0d2e60684af9b34730f7c8438465ad3e1d0c3237336722f2aa51095bd5759f4b8ab4dda111b684aa3dac62a761722e7ae43495b7709933512c81c4e3c9133a51f7ce9f2b51fcec064f65779666960b4e45df3900f54311f5613e8012dd1b8efd359eda31a778264c72aa8bb419d862734d769076bce2810011989a45374e5c5d8729fec21427f0bf397eacbb4220f603cf463a4b0c94efd858ffd9768cd60d6ce68d755e0fbad007ce5c2223d70c7018345a102e4ab3c60a13a9e7794303156d4c2063e919f2153c13961fb324c80b240742f47773a7a8e25b3e3fb19b00ce839346c6eb3c732fbc6b888df0b1fe0a3d07b053a2e9402c267b2d62f794d8a2840526e3ade15ce2264496ccd7519571dfde47f7a4bb16292241c20b2be59f3f8fb4f6383f232d838c5a22d8c95b6834d9d2ca493f5a505ebe8899503b0e8f9b19e6e2dd81c1628b80016d02097e0134de51054c4e7674824d4d758760fc52377d2cad145e259aa2ffaf54139e1a66b1e0c1c191e32ac59474c6b526f5b3ba07d3e5ec286eddf531fcd5292869be58c9f22ef91026159f7cf9d05ef66b4299f4da48cc1635bf2243051d342d378a22c83390553e873713c0454ce5f3234397111ac3fe3207b86f0ed9fc025c81903e1748103692074f83824fda6341be4f95ff00b0a9a208c267e12fa01825054cc0513629bf3dbb56dc5b90d4316f87654a8be18227978ea0a8a522760cad620d0d14fd38920fb7321314062914275a5f99f677145a6979b156bd82ecd36f23f8e1273cc2759ecc0b2c69d94dad5211d1bed939dd87ed9e07b91d49713a6e16ade0a98aea789f04994e318e4ff2c8a188cd8d43aeb52c6daa3bc29b4af50ea82a247c5cd67b573b34cbadcc0a376d3bbd530d50367b42705d870f2e27a8197ef46070528bfe408360faa2ebb8bf76e9f388572842bcb119f4d84ee34ae31f5cc594f23705a49197b181fb78ed1ec99499c690f843a4d0cf2e226d118e9372271054fbabdcc5c92ae9fefaef0589cd0e722eaf30c1703ec4289c7fd81beaa8a455ccee5298e31e2080c10c366a6fcf56f7d13582ad0bcad037c612b710fc595b70fbefaaca23623b60c6c39b11beb8e5843b6b3dac60f", + name: "nagydani-5-qube", + }, { + input: "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + expected: "5a0eb2bdf0ac1cae8e586689fa16cd4b07dfdedaec8a110ea1fdb059dd5253231b6132987598dfc6e11f86780428982d50cf68f67ae452622c3b336b537ef3298ca645e8f89ee39a26758206a5a3f6409afc709582f95274b57b71fae5c6b74619ae6f089a5393c5b79235d9caf699d23d88fb873f78379690ad8405e34c19f5257d596580c7a6a7206a3712825afe630c76b31cdb4a23e7f0632e10f14f4e282c81a66451a26f8df2a352b5b9f607a7198449d1b926e27036810368e691a74b91c61afa73d9d3b99453e7c8b50fd4f09c039a2f2feb5c419206694c31b92df1d9586140cb3417b38d0c503c7b508cc2ed12e813a1c795e9829eb39ee78eeaf360a169b491a1d4e419574e712402de9d48d54c1ae5e03739b7156615e8267e1fb0a897f067afd11fb33f6e24182d7aaaaa18fe5bc1982f20d6b871e5a398f0f6f718181d31ec225cfa9a0a70124ed9a70031bdf0c1c7829f708b6e17d50419ef361cf77d99c85f44607186c8d683106b8bd38a49b5d0fb503b397a83388c5678dcfcc737499d84512690701ed621a6f0172aecf037184ddf0f2453e4053024018e5ab2e30d6d5363b56e8b41509317c99042f517247474ab3abc848e00a07f69c254f46f2a05cf6ed84e5cc906a518fdcfdf2c61ce731f24c5264f1a25fc04934dc28aec112134dd523f70115074ca34e3807aa4cb925147f3a0ce152d323bd8c675ace446d0fd1ae30c4b57f0eb2c23884bc18f0964c0114796c5b6d080c3d89175665fbf63a6381a6a9da39ad070b645c8bb1779506da14439a9f5b5d481954764ea114fac688930bc68534d403cff4210673b6a6ff7ae416b7cd41404c3d3f282fcd193b86d0f54d0006c2a503b40d5c3930da980565b8f9630e9493a79d1c03e74e5f93ac8e4dc1a901ec5e3b3e57049124c7b72ea345aa359e782285d9e6a5c144a378111dd02c40855ff9c2be9b48425cb0b2fd62dc8678fd151121cf26a65e917d65d8e0dacfae108eb5508b601fb8ffa370be1f9a8b749a2d12eeab81f41079de87e2d777994fa4d28188c579ad327f9957fb7bdecec5c680844dd43cb57cf87aeb763c003e65011f73f8c63442df39a92b946a6bd968a1c1e4d5fa7d88476a68bd8e20e5b70a99259c7d3f85fb1b65cd2e93972e6264e74ebf289b8b6979b9b68a85cd5b360c1987f87235c3c845d62489e33acf85d53fa3561fe3a3aee18924588d9c6eba4edb7a4d106b31173e42929f6f0c48c80ce6a72d54eca7c0fe870068b7a7c89c63cdda593f5b32d3cb4ea8a32c39f00ab449155757172d66763ed9527019d6de6c9f2416aa6203f4d11c9ebee1e1d3845099e55504446448027212616167eb36035726daa7698b075286f5379cd3e93cb3e0cf4f9cb8d017facbb5550ed32d5ec5400ae57e47e2bf78d1eaeff9480cc765ceff39db500", + name: "nagydani-5-pow0x10001", + }, +} + +// bn256AddTests are the test and benchmark data for the bn256 addition precompiled +// contract. +var bn256AddTests = []precompiledTest{ + { + input: "18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726607c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7", + expected: "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915", + name: "chfast1", + }, { + input: "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c91518b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266", + expected: "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204", + name: "chfast2", + }, { + input: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + name: "cdetrio1", + }, { + input: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + name: "cdetrio2", + }, { + input: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + name: "cdetrio3", + }, { + input: "", + expected: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + name: "cdetrio4", + }, { + input: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + name: "cdetrio5", + }, { + input: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + expected: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + name: "cdetrio6", + }, { + input: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + name: "cdetrio7", + }, { + input: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + expected: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + name: "cdetrio8", + }, { + input: "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + name: "cdetrio9", + }, { + input: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + name: "cdetrio10", + }, { + input: "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + expected: "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + name: "cdetrio11", + }, { + input: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + name: "cdetrio12", + }, { + input: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + expected: "15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f", + name: "cdetrio13", + }, { + input: "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + expected: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + name: "cdetrio14", + }, +} + +// bn256ScalarMulTests are the test and benchmark data for the bn256 scalar +// multipication precompiled contract. +var bn256ScalarMulTests = []precompiledTest{ + { + input: "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20400000000000000000000000000000000000000000000000011138ce750fa15c2", + expected: "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc", + name: "chfast1", + }, { + input: "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46", + expected: "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e", + name: "chfast2", + }, { + input: "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3", + expected: "14789d0d4a730b354403b5fac948113739e276c23e0258d8596ee72f9cd9d3230af18a63153e0ec25ff9f2951dd3fa90ed0197bfef6e2a1a62b5095b9d2b4a27", + name: "chfast3", + }, +} + +// bn256PairingTests are the test and benchmark data for the bn256 pairing check +// precompiled contract. +var bn256PairingTests = []precompiledTest{ + { + input: "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "jeff1", + }, { + input: "2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "jeff2", + }, { + input: "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "jeff3", + }, { + input: "2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "jeff4", + }, { + input: "20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "jeff5", + }, { + input: "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + expected: "0000000000000000000000000000000000000000000000000000000000000000", + name: "jeff6", + }, { // ecpairing_empty_data_insufficient_gas + input: "", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "empty_data", + }, { // ecpairing_one_point_insufficient_gas + input: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + expected: "0000000000000000000000000000000000000000000000000000000000000000", + name: "one_point", + }, { // ecpairing_two_point_match_2 + input: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "two_point_match_2", + }, { // ecpairing_two_point_match_3 + input: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "two_point_match_3", + }, { // ecpairing_two_point_match_4 + input: "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "two_point_match_4", + }, { + input: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "ten_point_match_1", + }, { + input: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "ten_point_match_2", + }, { // ecpairing_two_point_match_4 + input: "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "ten_point_match_3", + }, +} + +func testPrecompiled(addr string, test precompiledTest, t *testing.T) { + p := PrecompiledContractsMetropolis[common.HexToAddress(addr)] + in := common.Hex2Bytes(test.input) + contract := NewContract(AccountRef(common.HexToAddress("1337")), + nil, new(big.Int), p.RequiredGas(in)) + t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) { + if res, err := RunPrecompiledContract(p, in, contract); err != nil { + t.Error(err) + } else if common.Bytes2Hex(res) != test.expected { + t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res)) + } + }) +} + +func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { + p := PrecompiledContractsMetropolis[common.HexToAddress(addr)] + in := common.Hex2Bytes(test.input) + reqGas := p.RequiredGas(in) + contract := NewContract(AccountRef(common.HexToAddress("1337")), + nil, new(big.Int), reqGas) + + var ( + res []byte + err error + data = make([]byte, len(in)) + ) + + bench.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(bench *testing.B) { + bench.ResetTimer() + for i := 0; i < bench.N; i++ { + contract.Gas = reqGas + copy(data, in) + res, err = RunPrecompiledContract(p, data, contract) + } + bench.StopTimer() + //Check if it is correct + if err != nil { + bench.Error(err) + return + } + if common.Bytes2Hex(res) != test.expected { + bench.Error(fmt.Sprintf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))) + return + } + }) +} + +// Benchmarks the sample inputs from the ECRECOVER precompile. +func BenchmarkPrecompiledEcrecover(bench *testing.B) { + t := precompiledTest{ + input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + expected: "000000000000000000000000ceaccac640adf55b2028469bd36ba501f28b699d", + name: "", + } + benchmarkPrecompiled("01", t, bench) +} + +// Benchmarks the sample inputs from the SHA256 precompile. +func BenchmarkPrecompiledSha256(bench *testing.B) { + t := precompiledTest{ + input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + expected: "811c7003375852fabd0d362e40e68607a12bdabae61a7d068fe5fdd1dbbf2a5d", + name: "128", + } + benchmarkPrecompiled("02", t, bench) +} + +// Benchmarks the sample inputs from the RIPEMD precompile. +func BenchmarkPrecompiledRipeMD(bench *testing.B) { + t := precompiledTest{ + input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + expected: "0000000000000000000000009215b8d9882ff46f0dfde6684d78e831467f65e6", + name: "128", + } + benchmarkPrecompiled("03", t, bench) +} + +// Benchmarks the sample inputs from the identiy precompile. +func BenchmarkPrecompiledIdentity(bench *testing.B) { + t := precompiledTest{ + input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + expected: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02", + name: "128", + } + benchmarkPrecompiled("04", t, bench) +} + +// Tests the sample inputs from the ModExp EIP 198. +func TestPrecompiledModExp(t *testing.T) { + for _, test := range modexpTests { + testPrecompiled("05", test, t) + } +} + +// Benchmarks the sample inputs from the ModExp EIP 198. +func BenchmarkPrecompiledModExp(bench *testing.B) { + for _, test := range modexpTests { + benchmarkPrecompiled("05", test, bench) + } +} + +// Tests the sample inputs from the elliptic curve addition EIP 213. +func TestPrecompiledBn256Add(t *testing.T) { + for _, test := range bn256AddTests { + testPrecompiled("06", test, t) + } +} + +// Benchmarks the sample inputs from the elliptic curve addition EIP 213. +func BenchmarkPrecompiledBn256Add(bench *testing.B) { + for _, test := range bn256AddTests { + benchmarkPrecompiled("06", test, bench) + } +} + +// Tests the sample inputs from the elliptic curve scalar multiplication EIP 213. +func TestPrecompiledBn256ScalarMul(t *testing.T) { + for _, test := range bn256ScalarMulTests { + testPrecompiled("07", test, t) + } +} + +// Benchmarks the sample inputs from the elliptic curve scalar multiplication EIP 213. +func BenchmarkPrecompiledBn256ScalarMul(bench *testing.B) { + for _, test := range bn256ScalarMulTests { + benchmarkPrecompiled("07", test, bench) + } +} + +// Tests the sample inputs from the elliptic curve pairing check EIP 197. +func TestPrecompiledBn256Pairing(t *testing.T) { + for _, test := range bn256PairingTests { + testPrecompiled("08", test, t) + } +} + +// Behcnmarks the sample inputs from the elliptic curve pairing check EIP 197. +func BenchmarkPrecompiledBn256Pairing(bench *testing.B) { + for _, test := range bn256PairingTests { + benchmarkPrecompiled("08", test, bench) + } +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 9296cc7ca..448acd469 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -36,12 +36,14 @@ type ( // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, error) { if contract.CodeAddr != nil { - precompiledContracts := PrecompiledContracts - if p := precompiledContracts[*contract.CodeAddr]; p != nil { + precompiles := PrecompiledContractsHomestead + if evm.ChainConfig().IsMetropolis(evm.BlockNumber) { + precompiles = PrecompiledContractsMetropolis + } + if p := precompiles[*contract.CodeAddr]; p != nil { return RunPrecompiledContract(p, input, contract) } } - return evm.interpreter.Run(snapshot, contract, input) } @@ -100,8 +102,8 @@ type EVM struct { abort int32 } -// NewEVM retutrns a new EVM evmironment. The returned EVM is not thread safe -// and should only ever be used *once*. +// NewEVM retutrns a new EVM . The returned EVM is not thread safe and should +// only ever be used *once*. func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { evm := &EVM{ Context: ctx, @@ -121,19 +123,20 @@ func (evm *EVM) Cancel() { atomic.StoreInt32(&evm.abort, 1) } -// Call executes the contract associated with the addr with the given input as parameters. It also handles any -// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in -// case of an execution error or failed value transfer. +// Call executes the contract associated with the addr with the given input as +// parameters. It also handles any necessary value transfer required and takes +// the necessary steps to create accounts and reverses the state in case of an +// execution error or failed value transfer. func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } - // Depth check execution. Fail if we're trying to execute above the - // limit. + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth } + // Fail if we're trying to transfer more than the available balance if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, ErrInsufficientBalance } @@ -143,10 +146,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas snapshot = evm.StateDB.Snapshot() ) if !evm.StateDB.Exist(addr) { - if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { + precompiles := PrecompiledContractsHomestead + if evm.ChainConfig().IsMetropolis(evm.BlockNumber) { + precompiles = PrecompiledContractsMetropolis + } + if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { return nil, gas, nil } - evm.StateDB.CreateAccount(addr) } evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) @@ -168,21 +174,23 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return ret, contract.Gas, err } -// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any -// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in -// case of an execution error or failed value transfer. +// CallCode executes the contract associated with the addr with the given input +// as parameters. It also handles any necessary value transfer required and takes +// the necessary steps to create accounts and reverses the state in case of an +// execution error or failed value transfer. // -// CallCode differs from Call in the sense that it executes the given address' code with the caller as context. +// CallCode differs from Call in the sense that it executes the given address' +// code with the caller as context. func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } - // Depth check execution. Fail if we're trying to execute above the - // limit. + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth } + // Fail if we're trying to transfer more than the available balance if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, ErrInsufficientBalance } @@ -206,18 +214,16 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, return ret, contract.Gas, err } -// DelegateCall executes the contract associated with the addr with the given input as parameters. -// It reverses the state in case of an execution error. +// DelegateCall executes the contract associated with the addr with the given input +// as parameters. It reverses the state in case of an execution error. // -// DelegateCall differs from CallCode in the sense that it executes the given address' code with the caller as context -// and the caller is set to the caller of the caller. +// DelegateCall differs from CallCode in the sense that it executes the given address' +// code with the caller as context and the caller is set to the caller of the caller. func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } - - // Depth check execution. Fail if we're trying to execute above the - // limit. + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth } @@ -227,7 +233,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by to = AccountRef(caller.Address()) ) - // Iinitialise a new contract and make initialise the delegate values + // Initialise a new contract and make initialise the delegate values contract := NewContract(caller, to, nil, gas).AsDelegate() contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) @@ -240,6 +246,47 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by return ret, contract.Gas, err } +// StaticCall executes the contract associated with the addr with the given input +// as parameters while disallowing any modifications to the state during the call. +// Opcodes that attempt to perform such modifications will result in exceptions +// instead of performing the modifications. +func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + // Make sure the readonly is only set if we aren't in readonly yet + // this makes also sure that the readonly flag isn't removed for + // child calls. + if !evm.interpreter.readOnly { + evm.interpreter.readOnly = true + defer func() { evm.interpreter.readOnly = false }() + } + + var ( + to = AccountRef(addr) + snapshot = evm.StateDB.Snapshot() + ) + // Initialise a new contract and set the code that is to be used by the + // EVM. The contract is a scoped environment for this execution context + // only. + contract := NewContract(caller, to, new(big.Int), gas) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + // When an error was returned by the EVM or when setting the creation code + // above we revert to the snapshot and consume any gas remaining. Additionally + // when we're in Homestead this also counts for code storage gas errors. + ret, err = run(evm, snapshot, contract, input) + if err != nil { + contract.UseGas(contract.Gas) + evm.StateDB.RevertToSnapshot(snapshot) + } + return ret, contract.Gas, err +} + // Create creates a new contract using code as deployment code. func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 761ca4450..a6346bd80 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -65,7 +65,33 @@ func constGasFunc(gas uint64) gasFunc { } } -func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + + var overflow bool + if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { + return 0, errGasUintOverflow + } + + words, overflow := bigUint64(stack.Back(2)) + if overflow { + return 0, errGasUintOverflow + } + + if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + return 0, errGasUintOverflow + } + + if gas, overflow = math.SafeAdd(gas, words); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + +func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -423,6 +449,33 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St return gas, nil } +func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { + return 0, errGasUintOverflow + } + + cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + // Replace the stack item with the new gas calculation. This means that + // either the original item is left on the stack or the item is replaced by: + // (availableGas - gas) * 63 / 64 + // We replace the stack item so that it's available when the opCall instruction is + // called. + stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) + + if gas, overflow = math.SafeAdd(gas, cg); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index f5164fcdd..4d6197912 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,6 +17,7 @@ package vm import ( + "errors" "fmt" "math/big" @@ -28,7 +29,9 @@ import ( ) var ( - bigZero = new(big.Int) + bigZero = new(big.Int) + errWriteProtection = errors.New("evm: write protection") + errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -240,6 +243,7 @@ func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac evm.interpreter.intPool.put(y) return nil, nil } + func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.Or(x, y)) @@ -247,6 +251,7 @@ func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack evm.interpreter.intPool.put(y) return nil, nil } + func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.Xor(x, y)) @@ -266,6 +271,7 @@ func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta evm.interpreter.intPool.put(th) return nil, nil } + func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(bigZero) > 0 { @@ -279,6 +285,7 @@ func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S evm.interpreter.intPool.put(y, z) return nil, nil } + func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(bigZero) > 0 { @@ -336,25 +343,47 @@ func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack return nil, nil } -func opCalldataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(big.Int).SetBytes(getData(contract.Input, stack.pop(), common.Big32))) +func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(new(big.Int).SetBytes(getDataBig(contract.Input, stack.pop(), big32))) return nil, nil } -func opCalldataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) return nil, nil } -func opCalldataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + var ( + memOffset = stack.pop() + dataOffset = stack.pop() + length = stack.pop() + ) + memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length)) + + evm.interpreter.intPool.put(memOffset, dataOffset, length) + return nil, nil +} + +func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(evm.interpreter.returnData)))) + return nil, nil +} + +func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( - mOff = stack.pop() - cOff = stack.pop() - l = stack.pop() + memOffset = stack.pop() + dataOffset = stack.pop() + length = stack.pop() ) - memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l)) + defer evm.interpreter.intPool.put(memOffset, dataOffset, length) + + end := new(big.Int).Add(dataOffset, length) + if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() { + return nil, errReturnDataOutOfBounds + } + memory.Set(memOffset.Uint64(), length.Uint64(), evm.interpreter.returnData[dataOffset.Uint64():end.Uint64()]) - evm.interpreter.intPool.put(mOff, cOff, l) return nil, nil } @@ -376,31 +405,28 @@ func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( - mOff = stack.pop() - cOff = stack.pop() - l = stack.pop() + memOffset = stack.pop() + codeOffset = stack.pop() + length = stack.pop() ) - codeCopy := getData(contract.Code, cOff, l) - - memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) + codeCopy := getDataBig(contract.Code, codeOffset, length) + memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - evm.interpreter.intPool.put(mOff, cOff, l) + evm.interpreter.intPool.put(memOffset, codeOffset, length) return nil, nil } func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( - addr = common.BigToAddress(stack.pop()) - mOff = stack.pop() - cOff = stack.pop() - l = stack.pop() + addr = common.BigToAddress(stack.pop()) + memOffset = stack.pop() + codeOffset = stack.pop() + length = stack.pop() ) - codeCopy := getData(evm.StateDB.GetCode(addr), cOff, l) - - memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) - - evm.interpreter.intPool.put(mOff, cOff, l) + codeCopy := getDataBig(evm.StateDB.GetCode(addr), codeOffset, length) + memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) + evm.interpreter.intPool.put(memOffset, codeOffset, length) return nil, nil } @@ -505,6 +531,7 @@ func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta evm.interpreter.intPool.put(pos) return nil, nil } + func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { pos, cond := stack.pop(), stack.pop() if cond.Sign() != 0 { @@ -520,6 +547,7 @@ func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St evm.interpreter.intPool.put(pos, cond) return nil, nil } + func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } @@ -656,6 +684,35 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st return ret, nil } +func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // pop gas + gas := stack.pop().Uint64() + // pop address + addr := stack.pop() + // pop input size and offset + inOffset, inSize := stack.pop(), stack.pop() + // pop return size and offset + retOffset, retSize := stack.pop(), stack.pop() + + address := common.BigToAddress(addr) + + // Get the arguments from the memory + args := memory.Get(inOffset.Int64(), inSize.Int64()) + + ret, returnGas, err := evm.StaticCall(contract, address, args, gas) + if err != nil { + stack.push(new(big.Int)) + } else { + stack.push(big.NewInt(1)) + + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + } + contract.Gas += returnGas + + evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + return ret, nil +} + func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 03c42c561..18644989c 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -1,7 +1,6 @@ package vm import ( - "fmt" "math/big" "testing" @@ -64,197 +63,169 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contr } } -func precompiledBenchmark(addr, input, expected string, gas uint64, bench *testing.B) { +func BenchmarkOpAdd64(b *testing.B) { + x := "ffffffff" + y := "fd37f3e2bba2c4f" - contract := NewContract(AccountRef(common.HexToAddress("1337")), - nil, new(big.Int), gas) - - p := PrecompiledContracts[common.HexToAddress(addr)] - in := common.Hex2Bytes(input) - var ( - res []byte - err error - ) - data := make([]byte, len(in)) - bench.ResetTimer() - for i := 0; i < bench.N; i++ { - contract.Gas = gas - copy(data, in) - res, err = RunPrecompiledContract(p, data, contract) - } - bench.StopTimer() - //Check if it is correct - if err != nil { - bench.Error(err) - return - } - if common.Bytes2Hex(res) != expected { - bench.Error(fmt.Sprintf("Expected %v, got %v", expected, common.Bytes2Hex(res))) - return - } + opBenchmark(b, opAdd, x, y) } -func BenchmarkPrecompiledEcdsa(bench *testing.B) { - var ( - addr = "01" - inp = "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02" - exp = "000000000000000000000000ceaccac640adf55b2028469bd36ba501f28b699d" - gas = uint64(4000000) - ) - precompiledBenchmark(addr, inp, exp, gas, bench) -} -func BenchmarkPrecompiledSha256(bench *testing.B) { - var ( - addr = "02" - inp = "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02" - exp = "811c7003375852fabd0d362e40e68607a12bdabae61a7d068fe5fdd1dbbf2a5d" - gas = uint64(4000000) - ) - precompiledBenchmark(addr, inp, exp, gas, bench) -} -func BenchmarkPrecompiledRipeMD(bench *testing.B) { - var ( - addr = "03" - inp = "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02" - exp = "0000000000000000000000009215b8d9882ff46f0dfde6684d78e831467f65e6" - gas = uint64(4000000) - ) - precompiledBenchmark(addr, inp, exp, gas, bench) -} -func BenchmarkPrecompiledIdentity(bench *testing.B) { - var ( - addr = "04" - inp = "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02" - exp = "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02" - gas = uint64(4000000) - ) - precompiledBenchmark(addr, inp, exp, gas, bench) +func BenchmarkOpAdd128(b *testing.B) { + x := "ffffffffffffffff" + y := "f5470b43c6549b016288e9a65629687" + + opBenchmark(b, opAdd, x, y) } -func BenchmarkOpAdd(b *testing.B) { - x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" - y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" + +func BenchmarkOpAdd256(b *testing.B) { + x := "0802431afcbce1fc194c9eaa417b2fb67dc75a95db0bc7ec6b1c8af11df6a1da9" + y := "a1f5aac137876480252e5dcac62c354ec0d42b76b0642b6181ed099849ea1d57" opBenchmark(b, opAdd, x, y) +} + +func BenchmarkOpSub64(b *testing.B) { + x := "51022b6317003a9d" + y := "a20456c62e00753a" + opBenchmark(b, opSub, x, y) } -func BenchmarkOpSub(b *testing.B) { - x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" - y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" + +func BenchmarkOpSub128(b *testing.B) { + x := "4dde30faaacdc14d00327aac314e915d" + y := "9bbc61f5559b829a0064f558629d22ba" opBenchmark(b, opSub, x, y) +} +func BenchmarkOpSub256(b *testing.B) { + x := "4bfcd8bb2ac462735b48a17580690283980aa2d679f091c64364594df113ea37" + y := "97f9b1765588c4e6b69142eb00d20507301545acf3e1238c86c8b29be227d46e" + + opBenchmark(b, opSub, x, y) } + func BenchmarkOpMul(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opMul, x, y) +} +func BenchmarkOpDiv256(b *testing.B) { + x := "ff3f9014f20db29ae04af2c2d265de17" + y := "fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611" + opBenchmark(b, opDiv, x, y) } -func BenchmarkOpDiv(b *testing.B) { - x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" - y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" +func BenchmarkOpDiv128(b *testing.B) { + x := "fdedc7f10142ff97" + y := "fbdfda0e2ce356173d1993d5f70a2b11" opBenchmark(b, opDiv, x, y) +} +func BenchmarkOpDiv64(b *testing.B) { + x := "fcb34eb3" + y := "f97180878e839129" + opBenchmark(b, opDiv, x, y) } + func BenchmarkOpSdiv(b *testing.B) { - x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" - y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" + x := "ff3f9014f20db29ae04af2c2d265de17" + y := "fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611" opBenchmark(b, opSdiv, x, y) - } + func BenchmarkOpMod(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opMod, x, y) - } + func BenchmarkOpSmod(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opSmod, x, y) - } + func BenchmarkOpExp(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opExp, x, y) - } + func BenchmarkOpSignExtend(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opSignExtend, x, y) - } + func BenchmarkOpLt(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opLt, x, y) - } + func BenchmarkOpGt(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opGt, x, y) - } + func BenchmarkOpSlt(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opSlt, x, y) - } + func BenchmarkOpSgt(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opSgt, x, y) - } + func BenchmarkOpEq(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opEq, x, y) - } + func BenchmarkOpAnd(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opAnd, x, y) - } + func BenchmarkOpOr(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opOr, x, y) - } + func BenchmarkOpXor(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opXor, x, y) - } + func BenchmarkOpByte(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opByte, x, y) - } func BenchmarkOpAddmod(b *testing.B) { @@ -263,22 +234,12 @@ func BenchmarkOpAddmod(b *testing.B) { z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opAddmod, x, y, z) - } + func BenchmarkOpMulmod(b *testing.B) { x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff" opBenchmark(b, opMulmod, x, y, z) - } - -//func BenchmarkOpSha3(b *testing.B) { -// x := "0" -// y := "32" -// -// opBenchmark(b,opSha3, x, y) -// -// -//} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 545f7d650..954839f2e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -19,12 +19,10 @@ package vm import ( "fmt" "sync/atomic" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -46,7 +44,7 @@ type Config struct { // Enable recording of SHA3/keccak preimages EnablePreimageRecording bool // JumpTable contains the EVM instruction table. This - // may me left uninitialised and will be set the default + // may be left uninitialised and will be set to the default // table. JumpTable [256]operation } @@ -61,7 +59,8 @@ type Interpreter struct { gasTable params.GasTable intPool *intPool - readonly bool + readOnly bool // Whether to throw on stateful modifications + returnData []byte // Last CALL's return data for subsequent reuse } // NewInterpreter returns a new instance of the Interpreter. @@ -71,6 +70,8 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter { // we'll set the default jump table. if !cfg.JumpTable[STOP].valid { switch { + case evm.ChainConfig().IsMetropolis(evm.BlockNumber): + cfg.JumpTable = metropolisInstructionSet case evm.ChainConfig().IsHomestead(evm.BlockNumber): cfg.JumpTable = homesteadInstructionSet default: @@ -87,6 +88,18 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter { } func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { + if in.evm.chainRules.IsMetropolis { + if in.readOnly { + // If the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. The 3rd stack item + // for a call operation is the value. Transfering value from one + // account to the others means the state is modified and should also + // return with an error. + if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) { + return errWriteProtection + } + } + } return nil } @@ -97,9 +110,14 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack // considered a revert-and-consume-all-gas operation. No error specific checks // should be handled to reduce complexity and errors further down the in. func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) { + // Increment the call depth which is restricted to 1024 in.evm.depth++ defer func() { in.evm.depth-- }() + // Reset the previous call's return data. It's unimportant to preserve the old buffer + // as every returning call will return new data anyway. + in.returnData = nil + // Don't bother with the execution if there's no code. if len(contract.Code) == 0 { return nil, nil @@ -122,19 +140,12 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret ) contract.Input = input - // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return. defer func() { if err != nil && in.cfg.Debug { - // XXX For debugging - //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d ERR = %v\n", pc, op, cost, stack.len(), err) in.cfg.Tracer.CaptureState(in.evm, pc, op, contract.Gas, cost, mem, stack, contract, in.evm.depth, err) } }() - log.Debug("interpreter running contract", "hash", codehash[:]) - tstart := time.Now() - defer log.Debug("interpreter finished running contract", "hash", codehash[:], "elapsed", time.Since(tstart)) - // The Interpreter main run loop (contextual). This loop runs until either an // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during // the execution of one of the operations or until the done flag is set by the @@ -190,8 +201,6 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret if in.cfg.Debug { in.cfg.Tracer.CaptureState(in.evm, pc, op, contract.Gas, cost, mem, stack, contract, in.evm.depth, err) } - // XXX For debugging - //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d\n", pc, op, cost, stack.len()) // execute the operation res, err := operation.execute(&pc, in.evm, contract, mem, stack) @@ -209,10 +218,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret case !operation.jumps: pc++ } - // if the operation returned a value make sure that is also set - // the last return data. - if res != nil { - mem.lastReturn = ret + // if the operation clears the return data (e.g. it has returning data) + // set the last return to the result of the operation. + if operation.returns { + in.returnData = res } } return nil, nil diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 0034eacb7..2d238f7a1 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -53,13 +53,45 @@ type operation struct { valid bool // reverts determined whether the operation reverts state reverts bool + // returns determines whether the opertions sets the return data + returns bool } var ( - frontierInstructionSet = NewFrontierInstructionSet() - homesteadInstructionSet = NewHomesteadInstructionSet() + frontierInstructionSet = NewFrontierInstructionSet() + homesteadInstructionSet = NewHomesteadInstructionSet() + metropolisInstructionSet = NewMetropolisInstructionSet() ) +// NewMetropolisInstructionSet returns the frontier, homestead and +// metropolis instructions. +func NewMetropolisInstructionSet() [256]operation { + // instructions that can be executed during the homestead phase. + instructionSet := NewHomesteadInstructionSet() + instructionSet[STATICCALL] = operation{ + execute: opStaticCall, + gasCost: gasStaticCall, + validateStack: makeStackFunc(6, 1), + memorySize: memoryStaticCall, + valid: true, + returns: true, + } + instructionSet[RETURNDATASIZE] = operation{ + execute: opReturnDataSize, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + } + instructionSet[RETURNDATACOPY] = operation{ + execute: opReturnDataCopy, + gasCost: gasReturnDataCopy, + validateStack: makeStackFunc(3, 0), + memorySize: memoryReturnDataCopy, + valid: true, + } + return instructionSet +} + // NewHomesteadInstructionSet returns the frontier and homestead // instructions that can be executed during the homestead phase. func NewHomesteadInstructionSet() [256]operation { @@ -70,6 +102,7 @@ func NewHomesteadInstructionSet() [256]operation { validateStack: makeStackFunc(6, 1), memorySize: memoryDelegateCall, valid: true, + returns: true, } return instructionSet } @@ -255,22 +288,22 @@ func NewFrontierInstructionSet() [256]operation { valid: true, }, CALLDATALOAD: { - execute: opCalldataLoad, + execute: opCallDataLoad, gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(1, 1), valid: true, }, CALLDATASIZE: { - execute: opCalldataSize, + execute: opCallDataSize, gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }, CALLDATACOPY: { - execute: opCalldataCopy, - gasCost: gasCalldataCopy, + execute: opCallDataCopy, + gasCost: gasCallDataCopy, validateStack: makeStackFunc(3, 0), - memorySize: memoryCalldataCopy, + memorySize: memoryCallDataCopy, valid: true, }, CODESIZE: { @@ -810,6 +843,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(2, 0), memorySize: memoryLog, valid: true, + writes: true, }, LOG1: { execute: makeLog(1), @@ -817,6 +851,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(3, 0), memorySize: memoryLog, valid: true, + writes: true, }, LOG2: { execute: makeLog(2), @@ -824,6 +859,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(4, 0), memorySize: memoryLog, valid: true, + writes: true, }, LOG3: { execute: makeLog(3), @@ -831,6 +867,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(5, 0), memorySize: memoryLog, valid: true, + writes: true, }, LOG4: { execute: makeLog(4), @@ -838,6 +875,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(6, 0), memorySize: memoryLog, valid: true, + writes: true, }, CREATE: { execute: opCreate, @@ -846,6 +884,7 @@ func NewFrontierInstructionSet() [256]operation { memorySize: memoryCreate, valid: true, writes: true, + returns: true, }, CALL: { execute: opCall, @@ -853,6 +892,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(7, 1), memorySize: memoryCall, valid: true, + returns: true, }, CALLCODE: { execute: opCallCode, @@ -860,6 +900,7 @@ func NewFrontierInstructionSet() [256]operation { validateStack: makeStackFunc(7, 1), memorySize: memoryCall, valid: true, + returns: true, }, RETURN: { execute: opReturn, diff --git a/core/vm/logger.go b/core/vm/logger.go index 17a9c9ec3..b73b13bd9 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -196,20 +196,27 @@ func (l *StructLogger) StructLogs() []StructLog { // WriteTrace writes a formatted trace to the given writer func WriteTrace(writer io.Writer, logs []StructLog) { for _, log := range logs { - fmt.Fprintf(writer, "%-10spc=%08d gas=%v cost=%v", log.Op, log.Pc, log.Gas, log.GasCost) + fmt.Fprintf(writer, "%-16spc=%08d gas=%v cost=%v", log.Op, log.Pc, log.Gas, log.GasCost) if log.Err != nil { fmt.Fprintf(writer, " ERROR: %v", log.Err) } - fmt.Fprintf(writer, "\n") + fmt.Fprintln(writer) - for i := len(log.Stack) - 1; i >= 0; i-- { - fmt.Fprintf(writer, "%08d %x\n", len(log.Stack)-i-1, math.PaddedBigBytes(log.Stack[i], 32)) + if len(log.Stack) > 0 { + fmt.Fprintln(writer, "Stack:") + for i := len(log.Stack) - 1; i >= 0; i-- { + fmt.Fprintf(writer, "%08d %x\n", len(log.Stack)-i-1, math.PaddedBigBytes(log.Stack[i], 32)) + } } - - fmt.Fprint(writer, hex.Dump(log.Memory)) - - for h, item := range log.Storage { - fmt.Fprintf(writer, "%x: %x\n", h, item) + if len(log.Memory) > 0 { + fmt.Fprintln(writer, "Memory:") + fmt.Fprint(writer, hex.Dump(log.Memory)) + } + if len(log.Storage) > 0 { + fmt.Fprintln(writer, "Storage:") + for h, item := range log.Storage { + fmt.Fprintf(writer, "%x: %x\n", h, item) + } } fmt.Fprintln(writer) } diff --git a/core/vm/memory.go b/core/vm/memory.go index 6dbee94ef..99a84d227 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -22,7 +22,6 @@ import "fmt" type Memory struct { store []byte lastGasCost uint64 - lastReturn []byte } func NewMemory() *Memory { diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 654137c70..f1b671adc 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -26,7 +26,11 @@ func memorySha3(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(1)) } -func memoryCalldataCopy(stack *Stack) *big.Int { +func memoryCallDataCopy(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), stack.Back(2)) +} + +func memoryReturnDataCopy(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(2)) } @@ -74,6 +78,13 @@ func memoryDelegateCall(stack *Stack) *big.Int { return math.BigMax(x, y) } +func memoryStaticCall(stack *Stack) *big.Int { + x := calcMemSize(stack.Back(4), stack.Back(5)) + y := calcMemSize(stack.Back(2), stack.Back(3)) + + return math.BigMax(x, y) +} + func memoryReturn(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(1)) } diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index d4ba7f156..be87cae18 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -82,10 +82,11 @@ const ( GASPRICE EXTCODESIZE EXTCODECOPY + RETURNDATASIZE + RETURNDATACOPY ) const ( - // 0x40 range - block operations BLOCKHASH OpCode = 0x40 + iota COINBASE @@ -201,6 +202,7 @@ const ( CALLCODE RETURN DELEGATECALL + STATICCALL = 0xfa SELFDESTRUCT = 0xff ) @@ -238,27 +240,29 @@ var opCodeToString = map[OpCode]string{ SHA3: "SHA3", // 0x30 range - closure state - ADDRESS: "ADDRESS", - BALANCE: "BALANCE", - ORIGIN: "ORIGIN", - CALLER: "CALLER", - CALLVALUE: "CALLVALUE", - CALLDATALOAD: "CALLDATALOAD", - CALLDATASIZE: "CALLDATASIZE", - CALLDATACOPY: "CALLDATACOPY", - CODESIZE: "CODESIZE", - CODECOPY: "CODECOPY", - GASPRICE: "GASPRICE", + ADDRESS: "ADDRESS", + BALANCE: "BALANCE", + ORIGIN: "ORIGIN", + CALLER: "CALLER", + CALLVALUE: "CALLVALUE", + CALLDATALOAD: "CALLDATALOAD", + CALLDATASIZE: "CALLDATASIZE", + CALLDATACOPY: "CALLDATACOPY", + CODESIZE: "CODESIZE", + CODECOPY: "CODECOPY", + GASPRICE: "GASPRICE", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", + RETURNDATASIZE: "RETURNDATASIZE", + RETURNDATACOPY: "RETURNDATACOPY", // 0x40 range - block operations - BLOCKHASH: "BLOCKHASH", - COINBASE: "COINBASE", - TIMESTAMP: "TIMESTAMP", - NUMBER: "NUMBER", - DIFFICULTY: "DIFFICULTY", - GASLIMIT: "GASLIMIT", - EXTCODESIZE: "EXTCODESIZE", - EXTCODECOPY: "EXTCODECOPY", + BLOCKHASH: "BLOCKHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution POP: "POP", @@ -355,6 +359,7 @@ var opCodeToString = map[OpCode]string{ RETURN: "RETURN", CALLCODE: "CALLCODE", DELEGATECALL: "DELEGATECALL", + STATICCALL: "STATICCALL", SELFDESTRUCT: "SELFDESTRUCT", PUSH: "PUSH", @@ -372,136 +377,139 @@ func (o OpCode) String() string { } var stringToOp = map[string]OpCode{ - "STOP": STOP, - "ADD": ADD, - "MUL": MUL, - "SUB": SUB, - "DIV": DIV, - "SDIV": SDIV, - "MOD": MOD, - "SMOD": SMOD, - "EXP": EXP, - "NOT": NOT, - "LT": LT, - "GT": GT, - "SLT": SLT, - "SGT": SGT, - "EQ": EQ, - "ISZERO": ISZERO, - "SIGNEXTEND": SIGNEXTEND, - "AND": AND, - "OR": OR, - "XOR": XOR, - "BYTE": BYTE, - "ADDMOD": ADDMOD, - "MULMOD": MULMOD, - "SHA3": SHA3, - "ADDRESS": ADDRESS, - "BALANCE": BALANCE, - "ORIGIN": ORIGIN, - "CALLER": CALLER, - "CALLVALUE": CALLVALUE, - "CALLDATALOAD": CALLDATALOAD, - "CALLDATASIZE": CALLDATASIZE, - "CALLDATACOPY": CALLDATACOPY, - "DELEGATECALL": DELEGATECALL, - "CODESIZE": CODESIZE, - "CODECOPY": CODECOPY, - "GASPRICE": GASPRICE, - "BLOCKHASH": BLOCKHASH, - "COINBASE": COINBASE, - "TIMESTAMP": TIMESTAMP, - "NUMBER": NUMBER, - "DIFFICULTY": DIFFICULTY, - "GASLIMIT": GASLIMIT, - "EXTCODESIZE": EXTCODESIZE, - "EXTCODECOPY": EXTCODECOPY, - "POP": POP, - "MLOAD": MLOAD, - "MSTORE": MSTORE, - "MSTORE8": MSTORE8, - "SLOAD": SLOAD, - "SSTORE": SSTORE, - "JUMP": JUMP, - "JUMPI": JUMPI, - "PC": PC, - "MSIZE": MSIZE, - "GAS": GAS, - "JUMPDEST": JUMPDEST, - "PUSH1": PUSH1, - "PUSH2": PUSH2, - "PUSH3": PUSH3, - "PUSH4": PUSH4, - "PUSH5": PUSH5, - "PUSH6": PUSH6, - "PUSH7": PUSH7, - "PUSH8": PUSH8, - "PUSH9": PUSH9, - "PUSH10": PUSH10, - "PUSH11": PUSH11, - "PUSH12": PUSH12, - "PUSH13": PUSH13, - "PUSH14": PUSH14, - "PUSH15": PUSH15, - "PUSH16": PUSH16, - "PUSH17": PUSH17, - "PUSH18": PUSH18, - "PUSH19": PUSH19, - "PUSH20": PUSH20, - "PUSH21": PUSH21, - "PUSH22": PUSH22, - "PUSH23": PUSH23, - "PUSH24": PUSH24, - "PUSH25": PUSH25, - "PUSH26": PUSH26, - "PUSH27": PUSH27, - "PUSH28": PUSH28, - "PUSH29": PUSH29, - "PUSH30": PUSH30, - "PUSH31": PUSH31, - "PUSH32": PUSH32, - "DUP1": DUP1, - "DUP2": DUP2, - "DUP3": DUP3, - "DUP4": DUP4, - "DUP5": DUP5, - "DUP6": DUP6, - "DUP7": DUP7, - "DUP8": DUP8, - "DUP9": DUP9, - "DUP10": DUP10, - "DUP11": DUP11, - "DUP12": DUP12, - "DUP13": DUP13, - "DUP14": DUP14, - "DUP15": DUP15, - "DUP16": DUP16, - "SWAP1": SWAP1, - "SWAP2": SWAP2, - "SWAP3": SWAP3, - "SWAP4": SWAP4, - "SWAP5": SWAP5, - "SWAP6": SWAP6, - "SWAP7": SWAP7, - "SWAP8": SWAP8, - "SWAP9": SWAP9, - "SWAP10": SWAP10, - "SWAP11": SWAP11, - "SWAP12": SWAP12, - "SWAP13": SWAP13, - "SWAP14": SWAP14, - "SWAP15": SWAP15, - "SWAP16": SWAP16, - "LOG0": LOG0, - "LOG1": LOG1, - "LOG2": LOG2, - "LOG3": LOG3, - "LOG4": LOG4, - "CREATE": CREATE, - "CALL": CALL, - "RETURN": RETURN, - "CALLCODE": CALLCODE, - "SELFDESTRUCT": SELFDESTRUCT, + "STOP": STOP, + "ADD": ADD, + "MUL": MUL, + "SUB": SUB, + "DIV": DIV, + "SDIV": SDIV, + "MOD": MOD, + "SMOD": SMOD, + "EXP": EXP, + "NOT": NOT, + "LT": LT, + "GT": GT, + "SLT": SLT, + "SGT": SGT, + "EQ": EQ, + "ISZERO": ISZERO, + "SIGNEXTEND": SIGNEXTEND, + "AND": AND, + "OR": OR, + "XOR": XOR, + "BYTE": BYTE, + "ADDMOD": ADDMOD, + "MULMOD": MULMOD, + "SHA3": SHA3, + "ADDRESS": ADDRESS, + "BALANCE": BALANCE, + "ORIGIN": ORIGIN, + "CALLER": CALLER, + "CALLVALUE": CALLVALUE, + "CALLDATALOAD": CALLDATALOAD, + "CALLDATASIZE": CALLDATASIZE, + "CALLDATACOPY": CALLDATACOPY, + "DELEGATECALL": DELEGATECALL, + "STATICCALL": STATICCALL, + "CODESIZE": CODESIZE, + "CODECOPY": CODECOPY, + "GASPRICE": GASPRICE, + "EXTCODESIZE": EXTCODESIZE, + "EXTCODECOPY": EXTCODECOPY, + "RETURNDATASIZE": RETURNDATASIZE, + "RETURNDATACOPY": RETURNDATACOPY, + "BLOCKHASH": BLOCKHASH, + "COINBASE": COINBASE, + "TIMESTAMP": TIMESTAMP, + "NUMBER": NUMBER, + "DIFFICULTY": DIFFICULTY, + "GASLIMIT": GASLIMIT, + "POP": POP, + "MLOAD": MLOAD, + "MSTORE": MSTORE, + "MSTORE8": MSTORE8, + "SLOAD": SLOAD, + "SSTORE": SSTORE, + "JUMP": JUMP, + "JUMPI": JUMPI, + "PC": PC, + "MSIZE": MSIZE, + "GAS": GAS, + "JUMPDEST": JUMPDEST, + "PUSH1": PUSH1, + "PUSH2": PUSH2, + "PUSH3": PUSH3, + "PUSH4": PUSH4, + "PUSH5": PUSH5, + "PUSH6": PUSH6, + "PUSH7": PUSH7, + "PUSH8": PUSH8, + "PUSH9": PUSH9, + "PUSH10": PUSH10, + "PUSH11": PUSH11, + "PUSH12": PUSH12, + "PUSH13": PUSH13, + "PUSH14": PUSH14, + "PUSH15": PUSH15, + "PUSH16": PUSH16, + "PUSH17": PUSH17, + "PUSH18": PUSH18, + "PUSH19": PUSH19, + "PUSH20": PUSH20, + "PUSH21": PUSH21, + "PUSH22": PUSH22, + "PUSH23": PUSH23, + "PUSH24": PUSH24, + "PUSH25": PUSH25, + "PUSH26": PUSH26, + "PUSH27": PUSH27, + "PUSH28": PUSH28, + "PUSH29": PUSH29, + "PUSH30": PUSH30, + "PUSH31": PUSH31, + "PUSH32": PUSH32, + "DUP1": DUP1, + "DUP2": DUP2, + "DUP3": DUP3, + "DUP4": DUP4, + "DUP5": DUP5, + "DUP6": DUP6, + "DUP7": DUP7, + "DUP8": DUP8, + "DUP9": DUP9, + "DUP10": DUP10, + "DUP11": DUP11, + "DUP12": DUP12, + "DUP13": DUP13, + "DUP14": DUP14, + "DUP15": DUP15, + "DUP16": DUP16, + "SWAP1": SWAP1, + "SWAP2": SWAP2, + "SWAP3": SWAP3, + "SWAP4": SWAP4, + "SWAP5": SWAP5, + "SWAP6": SWAP6, + "SWAP7": SWAP7, + "SWAP8": SWAP8, + "SWAP9": SWAP9, + "SWAP10": SWAP10, + "SWAP11": SWAP11, + "SWAP12": SWAP12, + "SWAP13": SWAP13, + "SWAP14": SWAP14, + "SWAP15": SWAP15, + "SWAP16": SWAP16, + "LOG0": LOG0, + "LOG1": LOG1, + "LOG2": LOG2, + "LOG3": LOG3, + "LOG4": LOG4, + "CREATE": CREATE, + "CALL": CALL, + "RETURN": RETURN, + "CALLCODE": CALLCODE, + "SELFDESTRUCT": SELFDESTRUCT, } func StringToOp(str string) OpCode { diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 9aa88e669..818da1be2 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -21,11 +21,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" ) -func NewEnv(cfg *Config, state *state.StateDB) *vm.EVM { +func NewEnv(cfg *Config) *vm.EVM { context := vm.Context{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -37,7 +36,7 @@ func NewEnv(cfg *Config, state *state.StateDB) *vm.EVM { Time: cfg.Time, Difficulty: cfg.Difficulty, GasLimit: new(big.Int).SetUint64(cfg.GasLimit), - GasPrice: new(big.Int), + GasPrice: cfg.GasPrice, } return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 44cde4f70..edbf54176 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -106,7 +106,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { } var ( address = common.StringToAddress("contract") - vmenv = NewEnv(cfg, cfg.State) + vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) ) cfg.State.CreateAccount(address) @@ -136,7 +136,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) } var ( - vmenv = NewEnv(cfg, cfg.State) + vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) ) @@ -158,7 +158,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { setDefaults(cfg) - vmenv := NewEnv(cfg, cfg.State) + vmenv := NewEnv(cfg) sender := cfg.State.GetOrNewStateObject(cfg.Origin) // Call the code with the given configuration. diff --git a/crypto/bn256/bn256.go b/crypto/bn256/bn256.go index 92418369b..7144c31a8 100644 --- a/crypto/bn256/bn256.go +++ b/crypto/bn256/bn256.go @@ -379,16 +379,22 @@ func Pair(g1 *G1, g2 *G2) *GT { return >{optimalAte(g2.p, g1.p, new(bnPool))} } +// PairingCheck calculates the Optimal Ate pairing for a set of points. func PairingCheck(a []*G1, b []*G2) bool { pool := new(bnPool) - e := newGFp12(pool) - e.SetOne() + + acc := newGFp12(pool) + acc.SetOne() + for i := 0; i < len(a); i++ { - new_e := miller(b[i].p, a[i].p, pool) - e.Mul(e, new_e, pool) + if a[i].p.IsInfinity() || b[i].p.IsInfinity() { + continue + } + acc.Mul(acc, miller(b[i].p, a[i].p, pool), pool) } - ret := finalExponentiation(e, pool) - e.Put(pool) + ret := finalExponentiation(acc, pool) + acc.Put(pool) + return ret.IsOne() } diff --git a/crypto/bn256/optate.go b/crypto/bn256/optate.go index 68716b62b..9d6957062 100644 --- a/crypto/bn256/optate.go +++ b/crypto/bn256/optate.go @@ -393,6 +393,5 @@ func optimalAte(a *twistPoint, b *curvePoint, pool *bnPool) *gfP12 { if a.IsInfinity() || b.IsInfinity() { ret.SetOne() } - return ret } diff --git a/crypto/ecies/asn1.go b/crypto/ecies/asn1.go deleted file mode 100644 index d3e77d849..000000000 --- a/crypto/ecies/asn1.go +++ /dev/null @@ -1,584 +0,0 @@ -// Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is> -// Copyright (c) 2012 The Go Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package ecies - -import ( - "bytes" - "crypto" - "crypto/elliptic" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "encoding/asn1" - "encoding/pem" - "fmt" - "hash" - "math/big" - - ethcrypto "github.com/ethereum/go-ethereum/crypto" -) - -var ( - secgScheme = []int{1, 3, 132, 1} - shaScheme = []int{2, 16, 840, 1, 101, 3, 4, 2} - ansiX962Scheme = []int{1, 2, 840, 10045} - x963Scheme = []int{1, 2, 840, 63, 0} -) - -var ErrInvalidPrivateKey = fmt.Errorf("ecies: invalid private key") - -func doScheme(base, v []int) asn1.ObjectIdentifier { - var oidInts asn1.ObjectIdentifier - oidInts = append(oidInts, base...) - return append(oidInts, v...) -} - -// curve OID code taken from crypto/x509, including -// - oidNameCurve* -// - namedCurveFromOID -// - oidFromNamedCurve -// RFC 5480, 2.1.1.1. Named Curve -// -// secp224r1 OBJECT IDENTIFIER ::= { -// iso(1) identified-organization(3) certicom(132) curve(0) 33 } -// -// secp256r1 OBJECT IDENTIFIER ::= { -// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) -// prime(1) 7 } -// -// secp384r1 OBJECT IDENTIFIER ::= { -// iso(1) identified-organization(3) certicom(132) curve(0) 34 } -// -// secp521r1 OBJECT IDENTIFIER ::= { -// iso(1) identified-organization(3) certicom(132) curve(0) 35 } -// -// NB: secp256r1 is equivalent to prime256v1 -type secgNamedCurve asn1.ObjectIdentifier - -var ( - secgNamedCurveS256 = secgNamedCurve{1, 3, 132, 0, 10} - secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7} - secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34} - secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35} - rawCurveP256 = []byte{6, 8, 4, 2, 1, 3, 4, 7, 2, 2, 0, 6, 6, 1, 3, 1, 7} - rawCurveP384 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 4} - rawCurveP521 = []byte{6, 5, 4, 3, 1, 2, 9, 4, 0, 3, 5} -) - -func rawCurve(curve elliptic.Curve) []byte { - switch curve { - case elliptic.P256(): - return rawCurveP256 - case elliptic.P384(): - return rawCurveP384 - case elliptic.P521(): - return rawCurveP521 - default: - return nil - } -} - -func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool { - if len(curve) != len(curve2) { - return false - } - for i := range curve { - if curve[i] != curve2[i] { - return false - } - } - return true -} - -func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve { - switch { - case curve.Equal(secgNamedCurveS256): - return ethcrypto.S256() - case curve.Equal(secgNamedCurveP256): - return elliptic.P256() - case curve.Equal(secgNamedCurveP384): - return elliptic.P384() - case curve.Equal(secgNamedCurveP521): - return elliptic.P521() - } - return nil -} - -func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) { - switch curve { - case elliptic.P256(): - return secgNamedCurveP256, true - case elliptic.P384(): - return secgNamedCurveP384, true - case elliptic.P521(): - return secgNamedCurveP521, true - case ethcrypto.S256(): - return secgNamedCurveS256, true - } - - return nil, false -} - -// asnAlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC -// 5280, section 4.1.1.2. -type asnAlgorithmIdentifier struct { - Algorithm asn1.ObjectIdentifier - Parameters asn1.RawValue `asn1:"optional"` -} - -func (a asnAlgorithmIdentifier) Cmp(b asnAlgorithmIdentifier) bool { - if len(a.Algorithm) != len(b.Algorithm) { - return false - } - for i := range a.Algorithm { - if a.Algorithm[i] != b.Algorithm[i] { - return false - } - } - return true -} - -type asnHashFunction asnAlgorithmIdentifier - -var ( - oidSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26} - oidSHA224 = doScheme(shaScheme, []int{4}) - oidSHA256 = doScheme(shaScheme, []int{1}) - oidSHA384 = doScheme(shaScheme, []int{2}) - oidSHA512 = doScheme(shaScheme, []int{3}) -) - -func hashFromOID(oid asn1.ObjectIdentifier) func() hash.Hash { - switch { - case oid.Equal(oidSHA1): - return sha1.New - case oid.Equal(oidSHA224): - return sha256.New224 - case oid.Equal(oidSHA256): - return sha256.New - case oid.Equal(oidSHA384): - return sha512.New384 - case oid.Equal(oidSHA512): - return sha512.New - } - return nil -} - -func oidFromHash(hash crypto.Hash) (asn1.ObjectIdentifier, bool) { - switch hash { - case crypto.SHA1: - return oidSHA1, true - case crypto.SHA224: - return oidSHA224, true - case crypto.SHA256: - return oidSHA256, true - case crypto.SHA384: - return oidSHA384, true - case crypto.SHA512: - return oidSHA512, true - default: - return nil, false - } -} - -var ( - asnAlgoSHA1 = asnHashFunction{ - Algorithm: oidSHA1, - } - asnAlgoSHA224 = asnHashFunction{ - Algorithm: oidSHA224, - } - asnAlgoSHA256 = asnHashFunction{ - Algorithm: oidSHA256, - } - asnAlgoSHA384 = asnHashFunction{ - Algorithm: oidSHA384, - } - asnAlgoSHA512 = asnHashFunction{ - Algorithm: oidSHA512, - } -) - -// type ASNasnSubjectPublicKeyInfo struct { -// -// } -// - -type asnSubjectPublicKeyInfo struct { - Algorithm asn1.ObjectIdentifier - PublicKey asn1.BitString - Supplements ecpksSupplements `asn1:"optional"` -} - -type asnECPKAlgorithms struct { - Type asn1.ObjectIdentifier -} - -var idPublicKeyType = doScheme(ansiX962Scheme, []int{2}) -var idEcPublicKey = doScheme(idPublicKeyType, []int{1}) -var idEcPublicKeySupplemented = doScheme(idPublicKeyType, []int{0}) - -func curveToRaw(curve elliptic.Curve) (rv asn1.RawValue, ok bool) { - switch curve { - case elliptic.P256(), elliptic.P384(), elliptic.P521(): - raw := rawCurve(curve) - return asn1.RawValue{ - Tag: 30, - Bytes: raw[2:], - FullBytes: raw, - }, true - default: - return rv, false - } -} - -func asnECPublicKeyType(curve elliptic.Curve) (algo asnAlgorithmIdentifier, ok bool) { - raw, ok := curveToRaw(curve) - if !ok { - return - } else { - return asnAlgorithmIdentifier{Algorithm: idEcPublicKey, - Parameters: raw}, true - } -} - -type asnECPrivKeyVer int - -var asnECPrivKeyVer1 asnECPrivKeyVer = 1 - -type asnPrivateKey struct { - Version asnECPrivKeyVer - Private []byte - Curve secgNamedCurve `asn1:"optional"` - Public asn1.BitString -} - -var asnECDH = doScheme(secgScheme, []int{12}) - -type asnECDHAlgorithm asnAlgorithmIdentifier - -var ( - dhSinglePass_stdDH_sha1kdf = asnECDHAlgorithm{ - Algorithm: doScheme(x963Scheme, []int{2}), - } - dhSinglePass_stdDH_sha256kdf = asnECDHAlgorithm{ - Algorithm: doScheme(secgScheme, []int{11, 1}), - } - dhSinglePass_stdDH_sha384kdf = asnECDHAlgorithm{ - Algorithm: doScheme(secgScheme, []int{11, 2}), - } - dhSinglePass_stdDH_sha224kdf = asnECDHAlgorithm{ - Algorithm: doScheme(secgScheme, []int{11, 0}), - } - dhSinglePass_stdDH_sha512kdf = asnECDHAlgorithm{ - Algorithm: doScheme(secgScheme, []int{11, 3}), - } -) - -func (a asnECDHAlgorithm) Cmp(b asnECDHAlgorithm) bool { - if len(a.Algorithm) != len(b.Algorithm) { - return false - } - for i := range a.Algorithm { - if a.Algorithm[i] != b.Algorithm[i] { - return false - } - } - return true -} - -// asnNISTConcatenation is the only supported KDF at this time. -type asnKeyDerivationFunction asnAlgorithmIdentifier - -var asnNISTConcatenationKDF = asnKeyDerivationFunction{ - Algorithm: doScheme(secgScheme, []int{17, 1}), -} - -func (a asnKeyDerivationFunction) Cmp(b asnKeyDerivationFunction) bool { - if len(a.Algorithm) != len(b.Algorithm) { - return false - } - for i := range a.Algorithm { - if a.Algorithm[i] != b.Algorithm[i] { - return false - } - } - return true -} - -var eciesRecommendedParameters = doScheme(secgScheme, []int{7}) -var eciesSpecifiedParameters = doScheme(secgScheme, []int{8}) - -type asnECIESParameters struct { - KDF asnKeyDerivationFunction `asn1:"optional"` - Sym asnSymmetricEncryption `asn1:"optional"` - MAC asnMessageAuthenticationCode `asn1:"optional"` -} - -type asnSymmetricEncryption asnAlgorithmIdentifier - -var ( - aes128CTRinECIES = asnSymmetricEncryption{ - Algorithm: doScheme(secgScheme, []int{21, 0}), - } - aes192CTRinECIES = asnSymmetricEncryption{ - Algorithm: doScheme(secgScheme, []int{21, 1}), - } - aes256CTRinECIES = asnSymmetricEncryption{ - Algorithm: doScheme(secgScheme, []int{21, 2}), - } -) - -func (a asnSymmetricEncryption) Cmp(b asnSymmetricEncryption) bool { - if len(a.Algorithm) != len(b.Algorithm) { - return false - } - for i := range a.Algorithm { - if a.Algorithm[i] != b.Algorithm[i] { - return false - } - } - return true -} - -type asnMessageAuthenticationCode asnAlgorithmIdentifier - -var ( - hmacFull = asnMessageAuthenticationCode{ - Algorithm: doScheme(secgScheme, []int{22}), - } -) - -func (a asnMessageAuthenticationCode) Cmp(b asnMessageAuthenticationCode) bool { - if len(a.Algorithm) != len(b.Algorithm) { - return false - } - for i := range a.Algorithm { - if a.Algorithm[i] != b.Algorithm[i] { - return false - } - } - return true -} - -type ecpksSupplements struct { - ECDomain secgNamedCurve - ECCAlgorithms eccAlgorithmSet -} - -type eccAlgorithmSet struct { - ECDH asnECDHAlgorithm `asn1:"optional"` - ECIES asnECIESParameters `asn1:"optional"` -} - -func marshalSubjectPublicKeyInfo(pub *PublicKey) (subj asnSubjectPublicKeyInfo, err error) { - subj.Algorithm = idEcPublicKeySupplemented - curve, ok := oidFromNamedCurve(pub.Curve) - if !ok { - err = ErrInvalidPublicKey - return - } - subj.Supplements.ECDomain = curve - if pub.Params != nil { - subj.Supplements.ECCAlgorithms.ECDH = paramsToASNECDH(pub.Params) - subj.Supplements.ECCAlgorithms.ECIES = paramsToASNECIES(pub.Params) - } - pubkey := elliptic.Marshal(pub.Curve, pub.X, pub.Y) - subj.PublicKey = asn1.BitString{ - BitLength: len(pubkey) * 8, - Bytes: pubkey, - } - return -} - -// Encode a public key to DER format. -func MarshalPublic(pub *PublicKey) ([]byte, error) { - subj, err := marshalSubjectPublicKeyInfo(pub) - if err != nil { - return nil, err - } - return asn1.Marshal(subj) -} - -// Decode a DER-encoded public key. -func UnmarshalPublic(in []byte) (pub *PublicKey, err error) { - var subj asnSubjectPublicKeyInfo - - if _, err = asn1.Unmarshal(in, &subj); err != nil { - return - } - if !subj.Algorithm.Equal(idEcPublicKeySupplemented) { - err = ErrInvalidPublicKey - return - } - pub = new(PublicKey) - pub.Curve = namedCurveFromOID(subj.Supplements.ECDomain) - x, y := elliptic.Unmarshal(pub.Curve, subj.PublicKey.Bytes) - if x == nil { - err = ErrInvalidPublicKey - return - } - pub.X = x - pub.Y = y - pub.Params = new(ECIESParams) - asnECIEStoParams(subj.Supplements.ECCAlgorithms.ECIES, pub.Params) - asnECDHtoParams(subj.Supplements.ECCAlgorithms.ECDH, pub.Params) - if pub.Params == nil { - if pub.Params = ParamsFromCurve(pub.Curve); pub.Params == nil { - err = ErrInvalidPublicKey - } - } - return -} - -func marshalPrivateKey(prv *PrivateKey) (ecprv asnPrivateKey, err error) { - ecprv.Version = asnECPrivKeyVer1 - ecprv.Private = prv.D.Bytes() - - var ok bool - ecprv.Curve, ok = oidFromNamedCurve(prv.PublicKey.Curve) - if !ok { - err = ErrInvalidPrivateKey - return - } - - var pub []byte - if pub, err = MarshalPublic(&prv.PublicKey); err != nil { - return - } else { - ecprv.Public = asn1.BitString{ - BitLength: len(pub) * 8, - Bytes: pub, - } - } - return -} - -// Encode a private key to DER format. -func MarshalPrivate(prv *PrivateKey) ([]byte, error) { - ecprv, err := marshalPrivateKey(prv) - if err != nil { - return nil, err - } - return asn1.Marshal(ecprv) -} - -// Decode a private key from a DER-encoded format. -func UnmarshalPrivate(in []byte) (prv *PrivateKey, err error) { - var ecprv asnPrivateKey - - if _, err = asn1.Unmarshal(in, &ecprv); err != nil { - return - } else if ecprv.Version != asnECPrivKeyVer1 { - err = ErrInvalidPrivateKey - return - } - - privateCurve := namedCurveFromOID(ecprv.Curve) - if privateCurve == nil { - err = ErrInvalidPrivateKey - return - } - - prv = new(PrivateKey) - prv.D = new(big.Int).SetBytes(ecprv.Private) - - if pub, err := UnmarshalPublic(ecprv.Public.Bytes); err != nil { - return nil, err - } else { - prv.PublicKey = *pub - } - - return -} - -// Export a public key to PEM format. -func ExportPublicPEM(pub *PublicKey) (out []byte, err error) { - der, err := MarshalPublic(pub) - if err != nil { - return - } - - var block pem.Block - block.Type = "ELLIPTIC CURVE PUBLIC KEY" - block.Bytes = der - - buf := new(bytes.Buffer) - err = pem.Encode(buf, &block) - if err != nil { - return - } else { - out = buf.Bytes() - } - return -} - -// Export a private key to PEM format. -func ExportPrivatePEM(prv *PrivateKey) (out []byte, err error) { - der, err := MarshalPrivate(prv) - if err != nil { - return - } - - var block pem.Block - block.Type = "ELLIPTIC CURVE PRIVATE KEY" - block.Bytes = der - - buf := new(bytes.Buffer) - err = pem.Encode(buf, &block) - if err != nil { - return - } else { - out = buf.Bytes() - } - return -} - -// Import a PEM-encoded public key. -func ImportPublicPEM(in []byte) (pub *PublicKey, err error) { - p, _ := pem.Decode(in) - if p == nil || p.Type != "ELLIPTIC CURVE PUBLIC KEY" { - return nil, ErrInvalidPublicKey - } - - pub, err = UnmarshalPublic(p.Bytes) - return -} - -// Import a PEM-encoded private key. -func ImportPrivatePEM(in []byte) (prv *PrivateKey, err error) { - p, _ := pem.Decode(in) - if p == nil || p.Type != "ELLIPTIC CURVE PRIVATE KEY" { - return nil, ErrInvalidPrivateKey - } - - prv, err = UnmarshalPrivate(p.Bytes) - return -} diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 2a16f20a2..1d5f96ed2 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -151,14 +151,16 @@ var ( func incCounter(ctr []byte) { if ctr[3]++; ctr[3] != 0 { return - } else if ctr[2]++; ctr[2] != 0 { + } + if ctr[2]++; ctr[2] != 0 { return - } else if ctr[1]++; ctr[1] != 0 { + } + if ctr[1]++; ctr[1] != 0 { return - } else if ctr[0]++; ctr[0] != 0 { + } + if ctr[0]++; ctr[0] != 0 { return } - return } // NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1). diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 7c454aa73..9cd5c79f7 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -37,7 +37,6 @@ import ( "encoding/hex" "flag" "fmt" - "io/ioutil" "math/big" "testing" @@ -63,8 +62,7 @@ func TestKDF(t *testing.T) { t.FailNow() } if len(k) != 64 { - fmt.Printf("KDF: generated key is the wrong size (%d instead of 64\n", - len(k)) + fmt.Printf("KDF: generated key is the wrong size (%d instead of 64\n", len(k)) t.FailNow() } } @@ -74,14 +72,9 @@ var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match") // cmpParams compares a set of ECIES parameters. We assume, as per the // docs, that AES is the only supported symmetric encryption algorithm. func cmpParams(p1, p2 *ECIESParams) bool { - if p1.hashAlgo != p2.hashAlgo { - return false - } else if p1.KeyLen != p2.KeyLen { - return false - } else if p1.BlockSize != p2.BlockSize { - return false - } - return true + return p1.hashAlgo == p2.hashAlgo && + p1.KeyLen == p2.KeyLen && + p1.BlockSize == p2.BlockSize } // cmpPublic returns true if the two public keys represent the same pojnt. @@ -212,118 +205,6 @@ func TestTooBigSharedKey(t *testing.T) { } } -// Ensure a public key can be successfully marshalled and unmarshalled, and -// that the decoded key is the same as the original. -func TestMarshalPublic(t *testing.T) { - prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) - if err != nil { - t.Fatalf("GenerateKey error: %s", err) - } - - out, err := MarshalPublic(&prv.PublicKey) - if err != nil { - t.Fatalf("MarshalPublic error: %s", err) - } - - pub, err := UnmarshalPublic(out) - if err != nil { - t.Fatalf("UnmarshalPublic error: %s", err) - } - - if !cmpPublic(prv.PublicKey, *pub) { - t.Fatal("ecies: failed to unmarshal public key") - } -} - -// Ensure that a private key can be encoded into DER format, and that -// the resulting key is properly parsed back into a public key. -func TestMarshalPrivate(t *testing.T) { - prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - out, err := MarshalPrivate(prv) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - if dumpEnc { - ioutil.WriteFile("test.out", out, 0644) - } - - prv2, err := UnmarshalPrivate(out) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - if !cmpPrivate(prv, prv2) { - fmt.Println("ecdh: private key import failed") - t.FailNow() - } -} - -// Ensure that a private key can be successfully encoded to PEM format, and -// the resulting key is properly parsed back in. -func TestPrivatePEM(t *testing.T) { - prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - out, err := ExportPrivatePEM(prv) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - if dumpEnc { - ioutil.WriteFile("test.key", out, 0644) - } - - prv2, err := ImportPrivatePEM(out) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } else if !cmpPrivate(prv, prv2) { - fmt.Println("ecdh: import from PEM failed") - t.FailNow() - } -} - -// Ensure that a public key can be successfully encoded to PEM format, and -// the resulting key is properly parsed back in. -func TestPublicPEM(t *testing.T) { - prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - out, err := ExportPublicPEM(&prv.PublicKey) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - if dumpEnc { - ioutil.WriteFile("test.pem", out, 0644) - } - - pub2, err := ImportPublicPEM(out) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } else if !cmpPublic(prv.PublicKey, *pub2) { - fmt.Println("ecdh: import from PEM failed") - t.FailNow() - } -} - // Benchmark the generation of P256 keys. func BenchmarkGenerateKeyP256(b *testing.B) { for i := 0; i < b.N; i++ { @@ -437,74 +318,27 @@ func TestDecryptShared2(t *testing.T) { } } -// TestMarshalEncryption validates the encode/decode produces a valid -// ECIES encryption key. -func TestMarshalEncryption(t *testing.T) { - prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - out, err := MarshalPrivate(prv1) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - prv2, err := UnmarshalPrivate(out) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - message := []byte("Hello, world.") - ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - - if !bytes.Equal(pt, message) { - fmt.Println("ecies: plaintext doesn't match message") - t.FailNow() - } - - _, err = prv1.Decrypt(rand.Reader, ct, nil, nil) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - -} - type testCase struct { Curve elliptic.Curve Name string - Expected bool + Expected *ECIESParams } var testCases = []testCase{ { Curve: elliptic.P256(), Name: "P256", - Expected: true, + Expected: ECIES_AES128_SHA256, }, { Curve: elliptic.P384(), Name: "P384", - Expected: true, + Expected: ECIES_AES256_SHA384, }, { Curve: elliptic.P521(), Name: "P521", - Expected: true, + Expected: ECIES_AES256_SHA512, }, } @@ -519,10 +353,10 @@ func TestParamSelection(t *testing.T) { func testParamSelection(t *testing.T, c testCase) { params := ParamsFromCurve(c.Curve) - if params == nil && c.Expected { + if params == nil && c.Expected != nil { fmt.Printf("%s (%s)\n", ErrInvalidParams.Error(), c.Name) t.FailNow() - } else if params != nil && !c.Expected { + } else if params != nil && !cmpParams(params, c.Expected) { fmt.Printf("ecies: parameters should be invalid (%s)\n", c.Name) t.FailNow() diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go index 826d90c84..6312daf5a 100644 --- a/crypto/ecies/params.go +++ b/crypto/ecies/params.go @@ -114,97 +114,4 @@ func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) { // Only the curves P256, P384, and P512 are supported. func ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) { return paramsFromCurve[curve] - - /* - switch curve { - case elliptic.P256(): - return ECIES_AES128_SHA256 - case elliptic.P384(): - return ECIES_AES256_SHA384 - case elliptic.P521(): - return ECIES_AES256_SHA512 - default: - return nil - } - */ -} - -// ASN.1 encode the ECIES parameters relevant to the encryption operations. -func paramsToASNECIES(params *ECIESParams) (asnParams asnECIESParameters) { - if nil == params { - return - } - asnParams.KDF = asnNISTConcatenationKDF - asnParams.MAC = hmacFull - switch params.KeyLen { - case 16: - asnParams.Sym = aes128CTRinECIES - case 24: - asnParams.Sym = aes192CTRinECIES - case 32: - asnParams.Sym = aes256CTRinECIES - } - return -} - -// ASN.1 encode the ECIES parameters relevant to ECDH. -func paramsToASNECDH(params *ECIESParams) (algo asnECDHAlgorithm) { - switch params.hashAlgo { - case crypto.SHA224: - algo = dhSinglePass_stdDH_sha224kdf - case crypto.SHA256: - algo = dhSinglePass_stdDH_sha256kdf - case crypto.SHA384: - algo = dhSinglePass_stdDH_sha384kdf - case crypto.SHA512: - algo = dhSinglePass_stdDH_sha512kdf - } - return -} - -// ASN.1 decode the ECIES parameters relevant to the encryption stage. -func asnECIEStoParams(asnParams asnECIESParameters, params *ECIESParams) { - if !asnParams.KDF.Cmp(asnNISTConcatenationKDF) { - params = nil - return - } else if !asnParams.MAC.Cmp(hmacFull) { - params = nil - return - } - - switch { - case asnParams.Sym.Cmp(aes128CTRinECIES): - params.KeyLen = 16 - params.BlockSize = 16 - params.Cipher = aes.NewCipher - case asnParams.Sym.Cmp(aes192CTRinECIES): - params.KeyLen = 24 - params.BlockSize = 16 - params.Cipher = aes.NewCipher - case asnParams.Sym.Cmp(aes256CTRinECIES): - params.KeyLen = 32 - params.BlockSize = 16 - params.Cipher = aes.NewCipher - default: - params = nil - } -} - -// ASN.1 decode the ECIES parameters relevant to ECDH. -func asnECDHtoParams(asnParams asnECDHAlgorithm, params *ECIESParams) { - if asnParams.Cmp(dhSinglePass_stdDH_sha224kdf) { - params.hashAlgo = crypto.SHA224 - params.Hash = sha256.New224 - } else if asnParams.Cmp(dhSinglePass_stdDH_sha256kdf) { - params.hashAlgo = crypto.SHA256 - params.Hash = sha256.New - } else if asnParams.Cmp(dhSinglePass_stdDH_sha384kdf) { - params.hashAlgo = crypto.SHA384 - params.Hash = sha512.New384 - } else if asnParams.Cmp(dhSinglePass_stdDH_sha512kdf) { - params.hashAlgo = crypto.SHA512 - params.Hash = sha512.New - } else { - params = nil - } } diff --git a/crypto/sha3/sha3.go b/crypto/sha3/sha3.go index c86167c0b..b12a35c87 100644 --- a/crypto/sha3/sha3.go +++ b/crypto/sha3/sha3.go @@ -42,9 +42,8 @@ type state struct { storage [maxRate]byte // Specific to SHA-3 and SHAKE. - fixedOutput bool // whether this is a fixed-output-length instance - outputLen int // the default output size in bytes - state spongeDirection // whether the sponge is absorbing or squeezing + outputLen int // the default output size in bytes + state spongeDirection // whether the sponge is absorbing or squeezing } // BlockSize returns the rate of sponge underlying this hash function. diff --git a/crypto/sha3/sha3_test.go b/crypto/sha3/sha3_test.go index c433761a8..0e33676ce 100644 --- a/crypto/sha3/sha3_test.go +++ b/crypto/sha3/sha3_test.go @@ -53,15 +53,6 @@ var testShakes = map[string]func() ShakeHash{ "SHAKE256": NewShake256, } -// decodeHex converts a hex-encoded string into a raw byte string. -func decodeHex(s string) []byte { - b, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return b -} - // structs used to marshal JSON test-cases. type KeccakKats struct { Kats map[string][]struct { @@ -125,7 +116,7 @@ func TestKeccakKats(t *testing.T) { // TestUnalignedWrite tests that writing data in an arbitrary pattern with // small input buffers. -func testUnalignedWrite(t *testing.T) { +func TestUnalignedWrite(t *testing.T) { testUnalignedAndGeneric(t, func(impl string) { buf := sequentialBytes(0x10000) for alg, df := range testDigests { diff --git a/eth/api.go b/eth/api.go index 0d90759b6..f5214fc37 100644 --- a/eth/api.go +++ b/eth/api.go @@ -465,26 +465,6 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, logConfig *vm.LogConf return true, structLogger.StructLogs(), nil } -// callmsg is the message type used for call transitions. -type callmsg struct { - addr common.Address - to *common.Address - gas, gasPrice *big.Int - value *big.Int - data []byte -} - -// accessor boilerplate to implement core.Message -func (m callmsg) From() (common.Address, error) { return m.addr, nil } -func (m callmsg) FromFrontier() (common.Address, error) { return m.addr, nil } -func (m callmsg) Nonce() uint64 { return 0 } -func (m callmsg) CheckNonce() bool { return false } -func (m callmsg) To() *common.Address { return m.to } -func (m callmsg) GasPrice() *big.Int { return m.gasPrice } -func (m callmsg) Gas() *big.Int { return m.gas } -func (m callmsg) Value() *big.Int { return m.value } -func (m callmsg) Data() []byte { return m.data } - // formatError formats a Go error into either an empty string or the data content // of the error itself. func formatError(err error) string { diff --git a/eth/backend.go b/eth/backend.go index c7df517c0..8a837f7b8 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -148,8 +148,10 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { core.WriteChainConfig(chainDb, genesisHash, chainConfig) } - newPool := core.NewTxPool(config.TxPool, eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) - eth.txPool = newPool + if config.TxPool.Journal != "" { + config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) + } + eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) maxPeers := config.MaxPeers if config.LightServ > 0 { diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index b354682a1..d66aafe94 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -403,8 +403,7 @@ func (dl *downloadTester) newSlowPeer(id string, version int, hashes []common.Ha dl.lock.Lock() defer dl.lock.Unlock() - var err error - err = dl.downloader.RegisterPeer(id, version, &downloadTesterPeer{dl, id, delay}) + var err = dl.downloader.RegisterPeer(id, version, &downloadTesterPeer{dl: dl, id: id, delay: delay}) if err == nil { // Assign the owned hashes, headers and blocks to the peer (deep copy) dl.peerHashes[id] = make([]common.Hash, len(hashes)) @@ -466,6 +465,24 @@ type downloadTesterPeer struct { dl *downloadTester id string delay time.Duration + lock sync.RWMutex +} + +// setDelay is a thread safe setter for the network delay value. +func (dlp *downloadTesterPeer) setDelay(delay time.Duration) { + dlp.lock.Lock() + defer dlp.lock.Unlock() + + dlp.delay = delay +} + +// waitDelay is a thread safe way to sleep for the configured time. +func (dlp *downloadTesterPeer) waitDelay() { + dlp.lock.RLock() + delay := dlp.delay + dlp.lock.RUnlock() + + time.Sleep(delay) } // Head constructs a function to retrieve a peer's current head hash @@ -500,7 +517,7 @@ func (dlp *downloadTesterPeer) RequestHeadersByHash(origin common.Hash, amount i // origin; associated with a particular peer in the download tester. The returned // function can be used to retrieve batches of headers from the particular peer. func (dlp *downloadTesterPeer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { - time.Sleep(dlp.delay) + dlp.waitDelay() dlp.dl.lock.RLock() defer dlp.dl.lock.RUnlock() @@ -526,7 +543,7 @@ func (dlp *downloadTesterPeer) RequestHeadersByNumber(origin uint64, amount int, // peer in the download tester. The returned function can be used to retrieve // batches of block bodies from the particularly requested peer. func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash) error { - time.Sleep(dlp.delay) + dlp.waitDelay() dlp.dl.lock.RLock() defer dlp.dl.lock.RUnlock() @@ -551,7 +568,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash) error { // peer in the download tester. The returned function can be used to retrieve // batches of block receipts from the particularly requested peer. func (dlp *downloadTesterPeer) RequestReceipts(hashes []common.Hash) error { - time.Sleep(dlp.delay) + dlp.waitDelay() dlp.dl.lock.RLock() defer dlp.dl.lock.RUnlock() @@ -573,7 +590,7 @@ func (dlp *downloadTesterPeer) RequestReceipts(hashes []common.Hash) error { // peer in the download tester. The returned function can be used to retrieve // batches of node state data from the particularly requested peer. func (dlp *downloadTesterPeer) RequestNodeData(hashes []common.Hash) error { - time.Sleep(dlp.delay) + dlp.waitDelay() dlp.dl.lock.RLock() defer dlp.dl.lock.RUnlock() @@ -1381,7 +1398,7 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) { go func() { defer pending.Done() if err := tester.sync("peer-half", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) + panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) } }() <-starting @@ -1398,7 +1415,7 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) { go func() { defer pending.Done() if err := tester.sync("peer-full", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) + panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) } }() <-starting @@ -1454,7 +1471,7 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) { go func() { defer pending.Done() if err := tester.sync("fork A", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) + panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) } }() <-starting @@ -1474,7 +1491,7 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) { go func() { defer pending.Done() if err := tester.sync("fork B", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) + panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) } }() <-starting @@ -1535,7 +1552,7 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) { go func() { defer pending.Done() if err := tester.sync("faulty", nil, mode); err == nil { - t.Fatalf("succeeded faulty synchronisation") + panic("succeeded faulty synchronisation") } }() <-starting @@ -1552,7 +1569,7 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) { go func() { defer pending.Done() if err := tester.sync("valid", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) + panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) } }() <-starting @@ -1613,7 +1630,7 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) { go func() { defer pending.Done() if err := tester.sync("attack", nil, mode); err == nil { - t.Fatalf("succeeded attacker synchronisation") + panic("succeeded attacker synchronisation") } }() <-starting @@ -1630,7 +1647,7 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) { go func() { defer pending.Done() if err := tester.sync("valid", nil, mode); err != nil { - t.Fatalf("failed to synchronise blocks: %v", err) + panic(fmt.Sprintf("failed to synchronise blocks: %v", err)) } }() <-starting @@ -1747,7 +1764,7 @@ func testFastCriticalRestarts(t *testing.T, protocol int, progress bool) { for i := 0; i < fsPivotInterval; i++ { tester.peerMissingStates["peer"][headers[hashes[fsMinFullBlocks+i]].Root] = true } - (tester.downloader.peers.peers["peer"].peer).(*downloadTesterPeer).delay = 500 * time.Millisecond // Enough to reach the critical section + (tester.downloader.peers.peers["peer"].peer).(*downloadTesterPeer).setDelay(500 * time.Millisecond) // Enough to reach the critical section // Synchronise with the peer a few times and make sure they fail until the retry limit for i := 0; i < int(fsCriticalTrials)-1; i++ { @@ -1766,7 +1783,7 @@ func testFastCriticalRestarts(t *testing.T, protocol int, progress bool) { tester.lock.Lock() tester.peerHeaders["peer"][hashes[fsMinFullBlocks-1]] = headers[hashes[fsMinFullBlocks-1]] tester.peerMissingStates["peer"] = map[common.Hash]bool{tester.downloader.fsPivotLock.Root: true} - (tester.downloader.peers.peers["peer"].peer).(*downloadTesterPeer).delay = 0 + (tester.downloader.peers.peers["peer"].peer).(*downloadTesterPeer).setDelay(0) tester.lock.Unlock() } } diff --git a/eth/filters/api.go b/eth/filters/api.go index 61647a5d0..fff58a268 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -54,7 +54,6 @@ type PublicFilterAPI struct { backend Backend useMipMap bool mux *event.TypeMux - quit chan struct{} chainDb ethdb.Database events *EventSystem filtersMu sync.Mutex diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 0a0b81224..f27b76929 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -20,7 +20,6 @@ import ( "context" "math" "math/big" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -42,8 +41,6 @@ type Filter struct { backend Backend useMipMap bool - created time.Time - db ethdb.Database begin, end int64 addresses []common.Address diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 7abace1e6..ab0b7473e 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -74,7 +74,6 @@ type subscription struct { // subscription which match the subscription criteria. type EventSystem struct { mux *event.TypeMux - sub *event.TypeMuxSubscription backend Backend lightMode bool lastHead *types.Header diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 822580b56..23e6d66e1 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -18,6 +18,7 @@ package filters import ( "context" + "fmt" "math/big" "reflect" "testing" @@ -439,15 +440,15 @@ func TestPendingLogsSubscription(t *testing.T) { } if len(fetched) != len(tt.expected) { - t.Fatalf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) + panic(fmt.Sprintf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched))) } for l := range fetched { if fetched[l].Removed { - t.Errorf("expected log not to be removed for log %d in case %d", l, i) + panic(fmt.Sprintf("expected log not to be removed for log %d in case %d", l, i)) } if !reflect.DeepEqual(fetched[l], tt.expected[l]) { - t.Errorf("invalid log on index %d for case %d", l, i) + panic(fmt.Sprintf("invalid log on index %d for case %d", l, i)) } } }() diff --git a/eth/sync.go b/eth/sync.go index 8784b225d..7442f912c 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -138,7 +138,9 @@ func (pm *ProtocolManager) syncer() { defer pm.downloader.Terminate() // Wait for different events to fire synchronisation operations - forceSync := time.Tick(forceSyncCycle) + forceSync := time.NewTicker(forceSyncCycle) + defer forceSync.Stop() + for { select { case <-pm.newPeerCh: @@ -148,7 +150,7 @@ func (pm *ProtocolManager) syncer() { } go pm.synchronise(pm.peers.BestPeer()) - case <-forceSync: + case <-forceSync.C: // Force a sync even if not enough peers are present go pm.synchronise(pm.peers.BestPeer()) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 45bb87322..48639d949 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -203,8 +203,6 @@ func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (* if err == nil { if r == nil { return nil, ethereum.NotFound - } else if len(r.PostState) == 0 { - return nil, fmt.Errorf("server returned receipt without post state") } } return r, err @@ -258,6 +256,19 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) // State Access +// NetworkID returns the network ID (also known as the chain ID) for this chain. +func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) { + version := new(big.Int) + var ver string + if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil { + return nil, err + } + if _, ok := version.SetString(ver, 10); !ok { + return nil, fmt.Errorf("invalid net_version result %q", ver) + } + return version, nil +} + // BalanceAt returns the wei balance of the given account. // The block number can be nil, in which case the balance is taken from the latest known block. func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { diff --git a/ethdb/database_test.go b/ethdb/database_test.go index 0e69a1218..5e4a3ca34 100644 --- a/ethdb/database_test.go +++ b/ethdb/database_test.go @@ -14,21 +14,179 @@ // 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 ethdb +package ethdb_test import ( + "bytes" + "fmt" + "io/ioutil" "os" - "path/filepath" + "strconv" + "sync" + "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" ) -func newDb() *LDBDatabase { - file := filepath.Join("/", "tmp", "ldbtesttmpfile") - if common.FileExist(file) { - os.RemoveAll(file) +func newTestLDB() (*ethdb.LDBDatabase, func()) { + dirname, err := ioutil.TempDir(os.TempDir(), "ethdb_test_") + if err != nil { + panic("failed to create test file: " + err.Error()) } - db, _ := NewLDBDatabase(file, 0, 0) + db, err := ethdb.NewLDBDatabase(dirname, 0, 0) + if err != nil { + panic("failed to create test database: " + err.Error()) + } + + return db, func() { + db.Close() + os.RemoveAll(dirname) + } +} + +var test_values = []string{"", "a", "1251", "\x00123\x00"} + +func TestLDB_PutGet(t *testing.T) { + db, remove := newTestLDB() + defer remove() + testPutGet(db, t) +} + +func TestMemoryDB_PutGet(t *testing.T) { + db, _ := ethdb.NewMemDatabase() + testPutGet(db, t) +} + +func testPutGet(db ethdb.Database, t *testing.T) { + t.Parallel() - return db + for _, v := range test_values { + err := db.Put([]byte(v), []byte(v)) + if err != nil { + t.Fatalf("put failed: %v", err) + } + } + + for _, v := range test_values { + data, err := db.Get([]byte(v)) + if err != nil { + t.Fatalf("get failed: %v", err) + } + if !bytes.Equal(data, []byte(v)) { + t.Fatalf("get returned wrong result, got %q expected %q", string(data), v) + } + } + + for _, v := range test_values { + err := db.Put([]byte(v), []byte("?")) + if err != nil { + t.Fatalf("put override failed: %v", err) + } + } + + for _, v := range test_values { + data, err := db.Get([]byte(v)) + if err != nil { + t.Fatalf("get failed: %v", err) + } + if !bytes.Equal(data, []byte("?")) { + t.Fatalf("get returned wrong result, got %q expected ?", string(data)) + } + } + + for _, v := range test_values { + orig, err := db.Get([]byte(v)) + if err != nil { + t.Fatalf("get failed: %v", err) + } + orig[0] = byte(0xff) + data, err := db.Get([]byte(v)) + if err != nil { + t.Fatalf("get failed: %v", err) + } + if !bytes.Equal(data, []byte("?")) { + t.Fatalf("get returned wrong result, got %q expected ?", string(data)) + } + } + + for _, v := range test_values { + err := db.Delete([]byte(v)) + if err != nil { + t.Fatalf("delete %q failed: %v", v, err) + } + } + + for _, v := range test_values { + _, err := db.Get([]byte(v)) + if err == nil { + t.Fatalf("got deleted value %q", v) + } + } +} + +func TestLDB_ParallelPutGet(t *testing.T) { + db, remove := newTestLDB() + defer remove() + testParallelPutGet(db, t) +} + +func TestMemoryDB_ParallelPutGet(t *testing.T) { + db, _ := ethdb.NewMemDatabase() + testParallelPutGet(db, t) +} + +func testParallelPutGet(db ethdb.Database, t *testing.T) { + const n = 8 + var pending sync.WaitGroup + + pending.Add(n) + for i := 0; i < n; i++ { + go func(key string) { + defer pending.Done() + err := db.Put([]byte(key), []byte("v"+key)) + if err != nil { + panic("put failed: " + err.Error()) + } + }(strconv.Itoa(i)) + } + pending.Wait() + + pending.Add(n) + for i := 0; i < n; i++ { + go func(key string) { + defer pending.Done() + data, err := db.Get([]byte(key)) + if err != nil { + panic("get failed: " + err.Error()) + } + if !bytes.Equal(data, []byte("v"+key)) { + panic(fmt.Sprintf("get failed, got %q expected %q", []byte(data), []byte("v"+key))) + } + }(strconv.Itoa(i)) + } + pending.Wait() + + pending.Add(n) + for i := 0; i < n; i++ { + go func(key string) { + defer pending.Done() + err := db.Delete([]byte(key)) + if err != nil { + panic("delete failed: " + err.Error()) + } + }(strconv.Itoa(i)) + } + pending.Wait() + + pending.Add(n) + for i := 0; i < n; i++ { + go func(key string) { + defer pending.Done() + _, err := db.Get([]byte(key)) + if err == nil { + panic("get succeeded") + } + }(strconv.Itoa(i)) + } + pending.Wait() } diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index a2ee2f2cc..11b093724 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -50,7 +50,7 @@ func (db *MemDatabase) Get(key []byte) ([]byte, error) { defer db.lock.RUnlock() if entry, ok := db.db[string(key)]; ok { - return entry, nil + return common.CopyBytes(entry), nil } return nil, errors.New("not found") } diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index 333c975c9..b75c5e6da 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" "golang.org/x/net/websocket" @@ -52,8 +51,6 @@ const historyUpdateRange = 50 // Service implements an Ethereum netstats reporting daemon that pushes local // chain statistics up to a monitoring server. type Service struct { - stack *node.Node // Temporary workaround, remove when API finalized - server *p2p.Server // Peer-to-peer server to retrieve networking infos eth *eth.Ethereum // Full Ethereum service if monitoring a full node les *les.LightEthereum // Light Ethereum service if monitoring a light node diff --git a/internal/build/util.go b/internal/build/util.go index 44f6760b9..ade9cbe93 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -138,6 +138,19 @@ func CopyFile(dst, src string, mode os.FileMode) { } } +// GoTool returns the command that runs a go tool. This uses go from GOROOT instead of PATH +// so that go commands executed by build use the same version of Go as the 'host' that runs +// build code. e.g. +// +// /usr/lib/go-1.8/bin/go run build/ci.go ... +// +// runs using go 1.8 and invokes go 1.8 tools from the same GOROOT. This is also important +// because runtime.Version checks on the host should match the tools that are run. +func GoTool(tool string, args ...string) *exec.Cmd { + args = append([]string{tool}, args...) + return exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...) +} + // ExpandPackagesNoVendor expands a cmd/go import path pattern, skipping // vendored packages. func ExpandPackagesNoVendor(patterns []string) []string { @@ -148,8 +161,7 @@ func ExpandPackagesNoVendor(patterns []string) []string { } } if expand { - args := append([]string{"list"}, patterns...) - cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...) + cmd := GoTool("list", patterns...) out, err := cmd.CombinedOutput() if err != nil { log.Fatalf("package listing failed: %v\n%s", err, string(out)) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1b23ac559..c3924b93a 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -46,7 +46,6 @@ import ( const ( defaultGas = 90000 defaultGasPrice = 50 * params.Shannon - emptyHex = "0x" ) // PublicEthereumAPI provides an API to access Ethereum related information. @@ -231,22 +230,45 @@ func (s *PrivateAccountAPI) ListAccounts() []common.Address { type rawWallet struct { URL string `json:"url"` Status string `json:"status"` - Accounts []accounts.Account `json:"accounts"` + Failure string `json:"failure,omitempty"` + Accounts []accounts.Account `json:"accounts,omitempty"` } // ListWallets will return a list of wallets this node manages. func (s *PrivateAccountAPI) ListWallets() []rawWallet { wallets := make([]rawWallet, 0) // return [] instead of nil if empty for _, wallet := range s.am.Wallets() { - wallets = append(wallets, rawWallet{ + status, failure := wallet.Status() + + raw := rawWallet{ URL: wallet.URL().String(), - Status: wallet.Status(), + Status: status, Accounts: wallet.Accounts(), - }) + } + if failure != nil { + raw.Failure = failure.Error() + } + wallets = append(wallets, raw) } return wallets } +// OpenWallet initiates a hardware wallet opening procedure, establishing a USB +// connection and attempting to authenticate via the provided passphrase. Note, +// the method may return an extra challenge requiring a second open (e.g. the +// Trezor PIN matrix challenge). +func (s *PrivateAccountAPI) OpenWallet(url string, passphrase *string) error { + wallet, err := s.am.Wallet(url) + if err != nil { + return err + } + pass := "" + if passphrase != nil { + pass = *passphrase + } + return wallet.Open(pass) +} + // DeriveAccount requests a HD wallet to derive a new account, optionally pinning // it for later reuse. func (s *PrivateAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { @@ -548,26 +570,6 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A return res[:], state.Error() } -// callmsg is the message type used for call transitions. -type callmsg struct { - addr common.Address - to *common.Address - gas, gasPrice *big.Int - value *big.Int - data []byte -} - -// accessor boilerplate to implement core.Message -func (m callmsg) From() (common.Address, error) { return m.addr, nil } -func (m callmsg) FromFrontier() (common.Address, error) { return m.addr, nil } -func (m callmsg) Nonce() uint64 { return 0 } -func (m callmsg) CheckNonce() bool { return false } -func (m callmsg) To() *common.Address { return m.to } -func (m callmsg) GasPrice() *big.Int { return m.gasPrice } -func (m callmsg) Gas() *big.Int { return m.gas } -func (m callmsg) Value() *big.Int { return m.value } -func (m callmsg) Data() []byte { return m.data } - // CallArgs represents the arguments for a call. type CallArgs struct { From common.Address `json:"from"` @@ -626,10 +628,8 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Wait for the context to be done and cancel the evm. Even if the // EVM has finished, cancelling may be done (repeatedly) go func() { - select { - case <-ctx.Done(): - evm.Cancel() - } + <-ctx.Done() + evm.Cancel() }() // Setup the gas pool (also for unmetered requests) @@ -1306,7 +1306,7 @@ func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (strin if block == nil { return "", fmt.Errorf("block #%d not found", number) } - return fmt.Sprintf("%s", block), nil + return block.String(), nil } // SeedHash retrieves the seed hash of a block. diff --git a/internal/jsre/pretty.go b/internal/jsre/pretty.go index e096eec23..16fa91b67 100644 --- a/internal/jsre/pretty.go +++ b/internal/jsre/pretty.go @@ -65,14 +65,6 @@ func prettyError(vm *otto.Otto, err error, w io.Writer) { fmt.Fprint(w, ErrorColor("%s", failure)) } -// jsErrorString adds a backtrace to errors generated by otto. -func jsErrorString(err error) string { - if ottoErr, ok := err.(*otto.Error); ok { - return ottoErr.String() - } - return err.Error() -} - func (re *JSRE) prettyPrintJS(call otto.FunctionCall) otto.Value { for _, v := range call.ArgumentList { prettyPrint(call.Otto, v, re.output) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 44fabd6ab..bf1db8819 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -493,6 +493,11 @@ web3._extend({ params: 2 }), new web3._extend.Method({ + name: 'openWallet', + call: 'personal_openWallet', + params: 2 + }), + new web3._extend.Method({ name: 'deriveAccount', call: 'personal_deriveAccount', params: 3 diff --git a/les/backend.go b/les/backend.go index 658c73c6e..a4e772671 100644 --- a/les/backend.go +++ b/les/backend.go @@ -70,8 +70,7 @@ type LightEthereum struct { networkId uint64 netRPCService *ethapi.PublicNetAPI - quitSync chan struct{} - wg sync.WaitGroup + wg sync.WaitGroup } func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { diff --git a/les/flowcontrol/control.go b/les/flowcontrol/control.go index e40e69346..d50eb809c 100644 --- a/les/flowcontrol/control.go +++ b/les/flowcontrol/control.go @@ -157,9 +157,7 @@ func (peer *ServerNode) QueueRequest(reqID, maxCost uint64) { peer.bufEstimate -= maxCost peer.sumCost += maxCost - if reqID >= 0 { - peer.pending[reqID] = peer.sumCost - } + peer.pending[reqID] = peer.sumCost } // GotReply adjusts estimated buffer value according to the value included in diff --git a/les/handler.go b/les/handler.go index f50abaaa3..234b6e998 100644 --- a/les/handler.go +++ b/les/handler.go @@ -69,8 +69,6 @@ func errResp(code errCode, format string, v ...interface{}) error { return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...)) } -type hashFetcherFn func(common.Hash) error - type BlockChain interface { HasHeader(hash common.Hash) bool GetHeader(hash common.Hash, number uint64) *types.Header @@ -119,10 +117,6 @@ type ProtocolManager struct { quitSync chan struct{} noMorePeers chan struct{} - syncMu sync.Mutex - syncing bool - syncDone chan struct{} - // wait group is used for graceful shutdowns during downloading // and processing wg *sync.WaitGroup diff --git a/les/handler_test.go b/les/handler_test.go index 5df1d3463..b1f1aa095 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -305,7 +305,7 @@ func testGetReceipt(t *testing.T, protocol int) { } // Tests that trie merkle proofs can be retrieved -func TestGetProofsLes1(t *testing.T) { testGetReceipt(t, 1) } +func TestGetProofsLes1(t *testing.T) { testGetProofs(t, 1) } func testGetProofs(t *testing.T, protocol int) { // Assemble the test environment @@ -327,7 +327,7 @@ func testGetProofs(t *testing.T, protocol int) { for _, acc := range accounts { req := ProofReq{ BHash: header.Hash(), - Key: acc[:], + Key: crypto.Keccak256(acc[:]), } proofreqs = append(proofreqs, req) diff --git a/les/helper_test.go b/les/helper_test.go index 52fddd117..7dccfc458 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -20,7 +20,6 @@ package les import ( - "crypto/ecdsa" "crypto/rand" "math/big" "sync" @@ -140,7 +139,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, } genesis = gspec.MustCommit(db) - chain BlockChain + chain BlockChain ) if peers == nil { peers = newPeerSet() @@ -189,45 +188,6 @@ func newTestProtocolManagerMust(t *testing.T, lightSync bool, blocks int, genera return pm } -// testTxPool is a fake, helper transaction pool for testing purposes -type testTxPool struct { - pool []*types.Transaction // Collection of all transactions - added chan<- []*types.Transaction // Notification channel for new transactions - - lock sync.RWMutex // Protects the transaction pool -} - -// AddTransactions appends a batch of transactions to the pool, and notifies any -// listeners if the addition channel is non nil -func (p *testTxPool) AddBatch(txs []*types.Transaction) { - p.lock.Lock() - defer p.lock.Unlock() - - p.pool = append(p.pool, txs...) - if p.added != nil { - p.added <- txs - } -} - -// GetTransactions returns all the transactions known to the pool -func (p *testTxPool) GetTransactions() types.Transactions { - p.lock.RLock() - defer p.lock.RUnlock() - - txs := make([]*types.Transaction, len(p.pool)) - copy(txs, p.pool) - - return txs -} - -// newTestTransaction create a new dummy transaction. -func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { - tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) - tx, _ = types.SignTx(tx, types.HomesteadSigner{}, from) - - return tx -} - // testPeer is a simulated peer to allow testing direct network calls. type testPeer struct { net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging diff --git a/les/peer.go b/les/peer.go index 791d0da24..3ba2df3fe 100644 --- a/les/peer.go +++ b/les/peer.go @@ -38,10 +38,7 @@ var ( errNotRegistered = errors.New("peer is not registered") ) -const ( - maxHeadInfoLen = 20 - maxResponseErrors = 50 // number of invalid responses tolerated (makes the protocol less brittle but still avoids spam) -) +const maxResponseErrors = 50 // number of invalid responses tolerated (makes the protocol less brittle but still avoids spam) type peer struct { *p2p.Peer diff --git a/les/protocol.go b/les/protocol.go index 46da2b8c8..33d930ee0 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -23,7 +23,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) @@ -105,12 +104,6 @@ var errorToString = map[int]string{ ErrHandshakeMissingKey: "Key missing from handshake message", } -type chainManager interface { - GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash) - GetBlock(hash common.Hash) (block *types.Block) - Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) -} - // announceData is the network packet for the block announcements. type announceData struct { Hash common.Hash // Hash of one particular block being announced @@ -118,11 +111,6 @@ type announceData struct { Td *big.Int // Total difficulty of one particular block being announced ReorgDepth uint64 Update keyValueList - - haveHeaders uint64 // we have the headers of the remote peer's chain up to this number - headKnown bool - requested bool - next *announceData } type blockInfo struct { @@ -131,12 +119,6 @@ type blockInfo struct { Td *big.Int // Total difficulty of one particular block being announced } -// getBlockHashesData is the network packet for the hash based hash retrieval. -type getBlockHashesData struct { - Hash common.Hash - Amount uint64 -} - // getBlockHeadersData represents a block header query. type getBlockHeadersData struct { Origin hashOrNumber // Block from which to retrieve headers @@ -181,15 +163,6 @@ func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error { return err } -// newBlockData is the network packet for the block propagation message. -type newBlockData struct { - Block *types.Block - TD *big.Int -} - -// blockBodiesData is the network packet for block content distribution. -type blockBodiesData []*types.Body - // CodeData is the network response packet for a node data retrieval. type CodeData []struct { Value []byte diff --git a/les/server.go b/les/server.go index 2ff715ea8..39ef0efff 100644 --- a/les/server.go +++ b/les/server.go @@ -44,7 +44,6 @@ type LesServer struct { defParams *flowcontrol.ServerParams lesTopic discv5.Topic quitSync chan struct{} - stopped bool } func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { @@ -118,16 +117,6 @@ func (list RequestCostList) decode() requestCostTable { return table } -func (table requestCostTable) encode() RequestCostList { - list := make(RequestCostList, len(table)) - for idx, code := range reqList { - list[idx].MsgCode = code - list[idx].BaseCost = table[code].baseCost - list[idx].ReqCost = table[code].reqCost - } - return list -} - type linReg struct { sumX, sumY, sumXX, sumXY float64 cnt uint64 diff --git a/light/lightchain.go b/light/lightchain.go index 8bbf529cc..a51043975 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -52,7 +52,6 @@ type LightChain struct { mu sync.RWMutex chainmu sync.RWMutex - procmu sync.RWMutex bodyCache *lru.Cache // Cache for the most recent block bodies bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format diff --git a/light/lightchain_test.go b/light/lightchain_test.go index 21b621046..0ad640525 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -18,7 +18,6 @@ package light import ( "context" - "fmt" "math/big" "testing" @@ -98,10 +97,7 @@ func testFork(t *testing.T, LightChain *LightChain, i, n int, comparator func(td t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", i, hash2, hash1) } // Extend the newly created chain - var ( - headerChainB []*types.Header - ) - headerChainB = makeHeaderChain(LightChain2.CurrentHeader(), n, db, forkSeed) + headerChainB := makeHeaderChain(LightChain2.CurrentHeader(), n, db, forkSeed) if _, err := LightChain2.InsertHeaderChain(headerChainB, 1); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } @@ -117,13 +113,6 @@ func testFork(t *testing.T, LightChain *LightChain, i, n int, comparator func(td comparator(tdPre, tdPost) } -func printChain(bc *LightChain) { - for i := bc.CurrentHeader().Number.Uint64(); i > 0; i-- { - b := bc.GetHeaderByNumber(uint64(i)) - fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty) - } -} - // testHeaderChainImport tries to process a chain of header, writing them into // the database if successful. func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error { diff --git a/light/txpool.go b/light/txpool.go index 416148b7e..7cbb991e8 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -81,7 +81,7 @@ type TxRelayBackend interface { func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool { pool := &TxPool{ config: config, - signer: types.HomesteadSigner{}, + signer: types.NewEIP155Signer(config.ChainId), nonce: make(map[common.Address]uint64), pending: make(map[common.Hash]*types.Transaction), mined: make(map[common.Hash][]*types.Transaction), @@ -124,12 +124,6 @@ func (pool *TxPool) GetNonce(ctx context.Context, addr common.Address) (uint64, return nonce, nil } -type txBlockData struct { - BlockHash common.Hash - BlockIndex uint64 - Index uint64 -} - // txStateChanges stores the recent changes between pending/mined states of // transactions. True means mined, false means rolled back, no entry means no change type txStateChanges map[common.Hash]bool diff --git a/log/format.go b/log/format.go index 6c19c7a55..0b07abb2a 100644 --- a/log/format.go +++ b/log/format.go @@ -330,7 +330,7 @@ func escapeString(s string) string { needsEscape = true } } - if needsEscape == false && needsQuotes == false { + if !needsEscape && !needsQuotes { return s } e := stringBufPool.Get().(*bytes.Buffer) diff --git a/miner/remote_agent.go b/miner/remote_agent.go index bb223ba1b..aac7ce865 100644 --- a/miner/remote_agent.go +++ b/miner/remote_agent.go @@ -169,7 +169,8 @@ func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common. // RemoteAgent.Start() constantly recreates these channels, so the loop code cannot // assume data stability in these member fields. func (a *RemoteAgent) loop(workCh chan *Work, quitCh chan struct{}) { - ticker := time.Tick(5 * time.Second) + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() for { select { @@ -179,7 +180,7 @@ func (a *RemoteAgent) loop(workCh chan *Work, quitCh chan struct{}) { a.mu.Lock() a.currentWork = work a.mu.Unlock() - case <-ticker: + case <-ticker.C: // cleanup a.mu.Lock() for hash, work := range a.work { diff --git a/miner/worker.go b/miner/worker.go index 411bc4e1b..dab192c24 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -24,7 +24,6 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" @@ -109,9 +108,6 @@ type worker struct { uncleMu sync.Mutex possibleUncles map[common.Hash]*types.Block - txQueueMu sync.Mutex - txQueue map[common.Hash]*types.Transaction - unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations // atomic status counters @@ -133,9 +129,8 @@ func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase com proc: eth.BlockChain().Validator(), possibleUncles: make(map[common.Hash]*types.Block), coinbase: coinbase, - txQueue: make(map[common.Hash]*types.Transaction), agents: make(map[Agent]struct{}), - unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), 5), + unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), fullValidation: false, } worker.events = worker.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}, core.TxPreEvent{}) @@ -362,11 +357,7 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error work.family.Add(ancestor.Hash()) work.ancestors.Add(ancestor.Hash()) } - wallets := self.eth.AccountManager().Wallets() - accounts := make([]accounts.Account, 0, len(wallets)) - for _, wallet := range wallets { - accounts = append(accounts, wallet.Accounts()...) - } + // Keep track of transactions which return errors so they can be removed work.tcount = 0 self.current = work diff --git a/mobile/accounts.go b/mobile/accounts.go index 977999c3a..4d979bfff 100644 --- a/mobile/accounts.go +++ b/mobile/accounts.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -111,7 +112,7 @@ func (ks *KeyStore) DeleteAccount(account *Account, passphrase string) error { // SignHash calculates a ECDSA signature for the given hash. The produced signature // is in the [R || S || V] format where V is 0 or 1. func (ks *KeyStore) SignHash(address *Address, hash []byte) (signature []byte, _ error) { - return ks.keystore.SignHash(accounts.Account{Address: address.address}, hash) + return ks.keystore.SignHash(accounts.Account{Address: address.address}, common.CopyBytes(hash)) } // SignTx signs the given transaction with the requested account. @@ -130,7 +131,7 @@ func (ks *KeyStore) SignTx(account *Account, tx *Transaction, chainID *BigInt) ( // be decrypted with the given passphrase. The produced signature is in the // [R || S || V] format where V is 0 or 1. func (ks *KeyStore) SignHashPassphrase(account *Account, passphrase string, hash []byte) (signature []byte, _ error) { - return ks.keystore.SignHashWithPassphrase(account.account, passphrase, hash) + return ks.keystore.SignHashWithPassphrase(account.account, passphrase, common.CopyBytes(hash)) } // SignTxPassphrase signs the transaction if the private key matching the @@ -189,7 +190,7 @@ func (ks *KeyStore) ExportKey(account *Account, passphrase, newPassphrase string // ImportKey stores the given encrypted JSON key into the key directory. func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (account *Account, _ error) { - acc, err := ks.keystore.Import(keyJSON, passphrase, newPassphrase) + acc, err := ks.keystore.Import(common.CopyBytes(keyJSON), passphrase, newPassphrase) if err != nil { return nil, err } @@ -198,7 +199,7 @@ func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string) // ImportECDSAKey stores the given encrypted JSON key into the key directory. func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Account, _ error) { - privkey, err := crypto.ToECDSA(key) + privkey, err := crypto.ToECDSA(common.CopyBytes(key)) if err != nil { return nil, err } @@ -212,7 +213,7 @@ func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Acco // ImportPreSaleKey decrypts the given Ethereum presale wallet and stores // a key file in the key directory. The key file is encrypted with the same passphrase. func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (ccount *Account, _ error) { - account, err := ks.keystore.ImportPreSaleKey(keyJSON, passphrase) + account, err := ks.keystore.ImportPreSaleKey(common.CopyBytes(keyJSON), passphrase) if err != nil { return nil, err } diff --git a/mobile/big.go b/mobile/big.go index 525717caa..564fbad47 100644 --- a/mobile/big.go +++ b/mobile/big.go @@ -21,6 +21,8 @@ package geth import ( "errors" "math/big" + + "github.com/ethereum/go-ethereum/common" ) // A BigInt represents a signed multi-precision integer. @@ -52,7 +54,7 @@ func (bi *BigInt) GetInt64() int64 { // SetBytes interprets buf as the bytes of a big-endian unsigned integer and sets // the big int to that value. func (bi *BigInt) SetBytes(buf []byte) { - bi.bigint.SetBytes(buf) + bi.bigint.SetBytes(common.CopyBytes(buf)) } // SetInt64 sets the big int to x. diff --git a/mobile/bind.go b/mobile/bind.go index bc4eb25ba..084d6ef4c 100644 --- a/mobile/bind.go +++ b/mobile/bind.go @@ -119,7 +119,7 @@ func DeployContract(opts *TransactOpts, abiJSON string, bytecode []byte, client if err != nil { return nil, err } - addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, bytecode, client.client, args.objects...) + addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, common.CopyBytes(bytecode), client.client, args.objects...) if err != nil { return nil, err } diff --git a/mobile/common.go b/mobile/common.go index 3090014c5..047d8e1f6 100644 --- a/mobile/common.go +++ b/mobile/common.go @@ -35,7 +35,7 @@ type Hash struct { // NewHashFromBytes converts a slice of bytes to a hash value. func NewHashFromBytes(binary []byte) (hash *Hash, _ error) { h := new(Hash) - if err := h.SetBytes(binary); err != nil { + if err := h.SetBytes(common.CopyBytes(binary)); err != nil { return nil, err } return h, nil @@ -136,7 +136,7 @@ type Address struct { // NewAddressFromBytes converts a slice of bytes to a hash value. func NewAddressFromBytes(binary []byte) (address *Address, _ error) { a := new(Address) - if err := a.SetBytes(binary); err != nil { + if err := a.SetBytes(common.CopyBytes(binary)); err != nil { return nil, err } return a, nil diff --git a/mobile/ethereum.go b/mobile/ethereum.go index 30a94dc89..c9bb3013c 100644 --- a/mobile/ethereum.go +++ b/mobile/ethereum.go @@ -64,7 +64,7 @@ func (msg *CallMsg) SetFrom(address *Address) { msg.msg.From = address.address func (msg *CallMsg) SetGas(gas int64) { msg.msg.Gas = big.NewInt(gas) } func (msg *CallMsg) SetGasPrice(price *BigInt) { msg.msg.GasPrice = price.bigint } func (msg *CallMsg) SetValue(value *BigInt) { msg.msg.Value = value.bigint } -func (msg *CallMsg) SetData(data []byte) { msg.msg.Data = data } +func (msg *CallMsg) SetData(data []byte) { msg.msg.Data = common.CopyBytes(data) } func (msg *CallMsg) SetTo(address *Address) { if address == nil { msg.msg.To = nil diff --git a/mobile/interface.go b/mobile/interface.go index 10eac5f72..72958e66a 100644 --- a/mobile/interface.go +++ b/mobile/interface.go @@ -46,7 +46,7 @@ func (i *Interface) SetBool(b bool) { i.object = &b } func (i *Interface) SetBools(bs []bool) { i.object = &bs } func (i *Interface) SetString(str string) { i.object = &str } func (i *Interface) SetStrings(strs *Strings) { i.object = &strs.strs } -func (i *Interface) SetBinary(binary []byte) { i.object = &binary } +func (i *Interface) SetBinary(binary []byte) { b := common.CopyBytes(binary); i.object = &b } func (i *Interface) SetBinaries(binaries [][]byte) { i.object = &binaries } func (i *Interface) SetAddress(address *Address) { i.object = &address.address } func (i *Interface) SetAddresses(addrs *Addresses) { i.object = &addrs.addresses } diff --git a/mobile/params.go b/mobile/params.go index 9c58a90ab..45fe870ee 100644 --- a/mobile/params.go +++ b/mobile/params.go @@ -41,6 +41,15 @@ func TestnetGenesis() string { return string(enc) } +// RinkebyGenesis returns the JSON spec to use for the Rinkeby test network +func RinkebyGenesis() string { + enc, err := json.Marshal(core.DefaultRinkebyGenesisBlock()) + if err != nil { + panic(err) + } + return string(enc) +} + // FoundationBootnodes returns the enode URLs of the P2P bootstrap nodes operated // by the foundation running the V5 discovery protocol. func FoundationBootnodes() *Enodes { diff --git a/mobile/types.go b/mobile/types.go index 02282f7a3..088c7c6b3 100644 --- a/mobile/types.go +++ b/mobile/types.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) @@ -68,7 +69,7 @@ func NewHeaderFromRLP(data []byte) (*Header, error) { h := &Header{ header: new(types.Header), } - if err := rlp.DecodeBytes(data, h.header); err != nil { + if err := rlp.DecodeBytes(common.CopyBytes(data), h.header); err != nil { return nil, err } return h, nil @@ -145,7 +146,7 @@ func NewBlockFromRLP(data []byte) (*Block, error) { b := &Block{ block: new(types.Block), } - if err := rlp.DecodeBytes(data, b.block); err != nil { + if err := rlp.DecodeBytes(common.CopyBytes(data), b.block); err != nil { return nil, err } return b, nil @@ -212,7 +213,7 @@ type Transaction struct { // NewTransaction creates a new transaction with the given properties. func NewTransaction(nonce int64, to *Address, amount, gasLimit, gasPrice *BigInt, data []byte) *Transaction { - return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, gasLimit.bigint, gasPrice.bigint, data)} + return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, gasLimit.bigint, gasPrice.bigint, common.CopyBytes(data))} } // NewTransactionFromRLP parses a transaction from an RLP data dump. @@ -220,7 +221,7 @@ func NewTransactionFromRLP(data []byte) (*Transaction, error) { tx := &Transaction{ tx: new(types.Transaction), } - if err := rlp.DecodeBytes(data, tx.tx); err != nil { + if err := rlp.DecodeBytes(common.CopyBytes(data), tx.tx); err != nil { return nil, err } return tx, nil @@ -265,10 +266,11 @@ func (tx *Transaction) GetSigHash() *Hash { return &Hash{tx.tx.SigHash(types.Hom func (tx *Transaction) GetCost() *BigInt { return &BigInt{tx.tx.Cost()} } func (tx *Transaction) GetFrom(chainID *BigInt) (address *Address, _ error) { - if chainID == nil { // Null passed from mobile app - chainID = new(BigInt) + var signer types.Signer = types.HomesteadSigner{} + if chainID != nil { + signer = types.NewEIP155Signer(chainID.bigint) } - from, err := types.Sender(types.NewEIP155Signer(chainID.bigint), tx.tx) + from, err := types.Sender(signer, tx.tx) return &Address{from}, err } @@ -279,8 +281,12 @@ func (tx *Transaction) GetTo() *Address { return nil } -func (tx *Transaction) WithSignature(sig []byte) (signedTx *Transaction, _ error) { - rawTx, err := tx.tx.WithSignature(types.HomesteadSigner{}, sig) +func (tx *Transaction) WithSignature(sig []byte, chainID *BigInt) (signedTx *Transaction, _ error) { + var signer types.Signer = types.HomesteadSigner{} + if chainID != nil { + signer = types.NewEIP155Signer(chainID.bigint) + } + rawTx, err := tx.tx.WithSignature(signer, common.CopyBytes(sig)) return &Transaction{rawTx}, err } @@ -310,7 +316,7 @@ func NewReceiptFromRLP(data []byte) (*Receipt, error) { r := &Receipt{ receipt: new(types.Receipt), } - if err := rlp.DecodeBytes(data, r.receipt); err != nil { + if err := rlp.DecodeBytes(common.CopyBytes(data), r.receipt); err != nil { return nil, err } return r, nil diff --git a/node/config.go b/node/config.go index 61e0008ef..b9b5e5b92 100644 --- a/node/config.go +++ b/node/config.go @@ -35,7 +35,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/discover" ) -var ( +const ( datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key datadirDefaultKeyStore = "keystore" // Path within the datadir to the keystore datadirStaticNodes = "static-nodes.json" // Path within the datadir to the static node list @@ -160,7 +160,7 @@ func (c *Config) NodeDB() string { if c.DataDir == "" { return "" // ephemeral } - return c.resolvePath("nodes") + return c.resolvePath(datadirNodeDatabase) } // DefaultIPCEndpoint returns the IPC path used by default. @@ -316,8 +316,8 @@ func (c *Config) StaticNodes() []*discover.Node { return c.parsePersistentNodes(c.resolvePath(datadirStaticNodes)) } -// TrusterNodes returns a list of node enode URLs configured as trusted nodes. -func (c *Config) TrusterNodes() []*discover.Node { +// TrustedNodes returns a list of node enode URLs configured as trusted nodes. +func (c *Config) TrustedNodes() []*discover.Node { return c.parsePersistentNodes(c.resolvePath(datadirTrustedNodes)) } @@ -393,11 +393,18 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { keystore.NewKeyStore(keydir, scryptN, scryptP), } if !conf.NoUSB { + // Start a USB hub for Ledger hardware wallets if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) } else { backends = append(backends, ledgerhub) } + // Start a USB hub for Trezor hardware wallets + if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { + log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) + } else { + backends = append(backends, trezorhub) + } } return accounts.NewManager(backends...), ephemeral, nil } diff --git a/node/doc.go b/node/doc.go index f009e6f85..d9688e0a1 100644 --- a/node/doc.go +++ b/node/doc.go @@ -68,7 +68,7 @@ unless its location is changed through the KeyStoreDir configuration option. Data Directory Sharing Example -In this exanple, two node instances named A and B are started with the same data +In this example, two node instances named A and B are started with the same data directory. Mode instance A opens the database "db", node instance B opens the databases "db" and "db-2". The following files will be created in the data directory: diff --git a/node/node.go b/node/node.go index a372b1c25..e3f0232b4 100644 --- a/node/node.go +++ b/node/node.go @@ -160,7 +160,7 @@ func (n *Node) Start() error { n.serverConfig.StaticNodes = n.config.StaticNodes() } if n.serverConfig.TrustedNodes == nil { - n.serverConfig.TrustedNodes = n.config.TrusterNodes() + n.serverConfig.TrustedNodes = n.config.TrustedNodes() } if n.serverConfig.NodeDatabase == "" { n.serverConfig.NodeDatabase = n.config.NodeDB() diff --git a/node/utils_test.go b/node/utils_test.go index 7cdfc2b3a..8eddce3ed 100644 --- a/node/utils_test.go +++ b/node/utils_test.go @@ -41,12 +41,10 @@ func NewNoopService(*ServiceContext) (Service, error) { return new(NoopService), type NoopServiceA struct{ NoopService } type NoopServiceB struct{ NoopService } type NoopServiceC struct{ NoopService } -type NoopServiceD struct{ NoopService } func NewNoopServiceA(*ServiceContext) (Service, error) { return new(NoopServiceA), nil } func NewNoopServiceB(*ServiceContext) (Service, error) { return new(NoopServiceB), nil } func NewNoopServiceC(*ServiceContext) (Service, error) { return new(NoopServiceC), nil } -func NewNoopServiceD(*ServiceContext) (Service, error) { return new(NoopServiceD), nil } // InstrumentedService is an implementation of Service for which all interface // methods can be instrumented both return value as well as event hook wise. diff --git a/params/protocol_params.go b/params/protocol_params.go index f48bf4992..9c84c7d34 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -31,23 +31,16 @@ const ( SstoreSetGas uint64 = 20000 // Once per SLOAD operation. LogDataGas uint64 = 8 // Per byte in a LOG* operation's data. CallStipend uint64 = 2300 // Free gas given at beginning of call. - EcrecoverGas uint64 = 3000 // - Sha256WordGas uint64 = 12 // Sha3Gas uint64 = 30 // Once per SHA3 operation. - Sha256Gas uint64 = 60 // - IdentityWordGas uint64 = 3 // Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data. SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero. SstoreClearGas uint64 = 5000 // Once per SSTORE operation if the zeroness doesn't change. SstoreRefundGas uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero. JumpdestGas uint64 = 1 // Refunded gas, once per SSTORE operation if the zeroness changes to zero. - IdentityGas uint64 = 15 // EpochDuration uint64 = 30000 // Duration between proof-of-work epochs. CallGas uint64 = 40 // Once per CALL operation & message call transaction. CreateDataGas uint64 = 200 // - Ripemd160Gas uint64 = 600 // - Ripemd160WordGas uint64 = 120 // CallCreateDepth uint64 = 1024 // Maximum depth of call/create stack. ExpGas uint64 = 10 // Once per EXP instruction LogGas uint64 = 375 // Per LOG* operation. @@ -60,7 +53,22 @@ const ( MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. - MaxCodeSize = 24576 + MaxCodeSize = 24576 // Maximum bytecode to permit for a contract + + // Precompiled contract gas prices + + EcrecoverGas uint64 = 3000 // Elliptic curve sender recovery gas price + Sha256BaseGas uint64 = 60 // Base price for a SHA256 operation + Sha256PerWordGas uint64 = 12 // Per-word price for a SHA256 operation + Ripemd160BaseGas uint64 = 600 // Base price for a RIPEMD160 operation + Ripemd160PerWordGas uint64 = 120 // Per-word price for a RIPEMD160 operation + IdentityBaseGas uint64 = 15 // Base price for a data copy operation + IdentityPerWordGas uint64 = 3 // Per-work price for a data copy operation + ModExpQuadCoeffDiv uint64 = 100 // Divisor for the quadratic particle of the big int modular exponentiation + Bn256AddGas uint64 = 500 // Gas needed for an elliptic curve addition + Bn256ScalarMulGas uint64 = 2000 // Gas needed for an elliptic curve scalar multiplication + Bn256PairingBaseGas uint64 = 100000 // Base price for an elliptic curve pairing check + Bn256PairingPerPointGas uint64 = 80000 // Per-point price for an elliptic curve pairing check ) var ( diff --git a/rpc/server.go b/rpc/server.go index 62b84af34..30c288349 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -29,11 +29,7 @@ import ( "gopkg.in/fatih/set.v0" ) -const ( - notificationBufferSize = 10000 // max buffered notifications before codec is closed - - MetadataApi = "rpc" -) +const MetadataApi = "rpc" // CodecOption specifies which type of messages this codec supports type CodecOption int @@ -49,10 +45,9 @@ const ( // NewServer will create a new server instance with no registered handlers. func NewServer() *Server { server := &Server{ - services: make(serviceRegistry), - subscriptions: make(subscriptionRegistry), - codecs: set.New(), - run: 1, + services: make(serviceRegistry), + codecs: set.New(), + run: 1, } // register a default service which will provide meta information about the RPC service such as the services and @@ -124,16 +119,6 @@ func (s *Server) RegisterName(name string, rcvr interface{}) error { return nil } -// hasOption returns true if option is included in options, otherwise false -func hasOption(option CodecOption, options []CodecOption) bool { - for _, o := range options { - if option == o { - return true - } - } - return false -} - // serveRequest will reads requests from the codec, calls the RPC callback and // writes the response to the given codec. // @@ -148,13 +133,11 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] - log.Error(fmt.Sprint(string(buf))) + log.Error(string(buf)) } s.codecsMu.Lock() s.codecs.Remove(codec) s.codecsMu.Unlock() - - return }() ctx, cancel := context.WithCancel(context.Background()) @@ -246,7 +229,7 @@ func (s *Server) ServeSingleRequest(codec ServerCodec, options CodecOption) { // close all codecs which will cancel pending requests/subscriptions. func (s *Server) Stop() { if atomic.CompareAndSwapInt32(&s.run, 1, 0) { - log.Debug(fmt.Sprint("RPC Server shutdown initiatied")) + log.Debug("RPC Server shutdown initiatied") s.codecsMu.Lock() defer s.codecsMu.Unlock() s.codecs.Each(func(c interface{}) bool { diff --git a/rpc/subscription.go b/rpc/subscription.go index 720e4dd06..6ce7befa1 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -53,7 +53,6 @@ type notifierKey struct{} type Notifier struct { codec ServerCodec subMu sync.RWMutex // guards active and inactive maps - stopped bool active map[ID]*Subscription inactive map[ID]*Subscription } diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 0ed15ddfe..39f759692 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -165,7 +165,7 @@ func TestNotifications(t *testing.T) { } func waitForMessages(t *testing.T, in *json.Decoder, successes chan<- jsonSuccessResponse, - failures chan<- jsonErrResponse, notifications chan<- jsonNotification) { + failures chan<- jsonErrResponse, notifications chan<- jsonNotification, errors chan<- error) { // read and parse server messages for { @@ -177,12 +177,14 @@ func waitForMessages(t *testing.T, in *json.Decoder, successes chan<- jsonSucces var responses []map[string]interface{} if rmsg[0] == '[' { if err := json.Unmarshal(rmsg, &responses); err != nil { - t.Fatalf("Received invalid message: %s", rmsg) + errors <- fmt.Errorf("Received invalid message: %s", rmsg) + return } } else { var msg map[string]interface{} if err := json.Unmarshal(rmsg, &msg); err != nil { - t.Fatalf("Received invalid message: %s", rmsg) + errors <- fmt.Errorf("Received invalid message: %s", rmsg) + return } responses = append(responses, msg) } @@ -216,7 +218,7 @@ func waitForMessages(t *testing.T, in *json.Decoder, successes chan<- jsonSucces } continue } - t.Fatalf("Received invalid message: %s", msg) + errors <- fmt.Errorf("Received invalid message: %s", msg) } } } @@ -235,6 +237,8 @@ func TestSubscriptionMultipleNamespaces(t *testing.T) { successes = make(chan jsonSuccessResponse) failures = make(chan jsonErrResponse) notifications = make(chan jsonNotification) + + errors = make(chan error, 10) ) // setup and start server @@ -248,7 +252,7 @@ func TestSubscriptionMultipleNamespaces(t *testing.T) { defer server.Stop() // wait for message and write them to the given channels - go waitForMessages(t, in, successes, failures, notifications) + go waitForMessages(t, in, successes, failures, notifications, errors) // create subscriptions one by one n := 3 @@ -297,6 +301,8 @@ func TestSubscriptionMultipleNamespaces(t *testing.T) { } select { + case err := <-errors: + t.Fatal(err) case suc := <-successes: // subscription created subids[namespaces[int(suc.Id.(float64))]] = suc.Result.(string) case failure := <-failures: diff --git a/rpc/types.go b/rpc/types.go index a7b8c9788..f2375604e 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -48,7 +48,6 @@ type callback struct { // service represents a registered object type service struct { name string // name for service - rcvr reflect.Value // receiver of methods for the service typ reflect.Type // receiver type callbacks callbacks // registered handlers subscriptions subscriptions // available subscriptions/notifications @@ -58,23 +57,19 @@ type service struct { type serverRequest struct { id interface{} svcname string - rcvr reflect.Value callb *callback args []reflect.Value isUnsubscribe bool err Error } -type serviceRegistry map[string]*service // collection of services -type callbacks map[string]*callback // collection of RPC callbacks -type subscriptions map[string]*callback // collection of subscription callbacks -type subscriptionRegistry map[string]*callback // collection of subscription callbacks +type serviceRegistry map[string]*service // collection of services +type callbacks map[string]*callback // collection of RPC callbacks +type subscriptions map[string]*callback // collection of subscription callbacks // Server represents a RPC server type Server struct { - services serviceRegistry - muSubcriptions sync.Mutex // protects subscriptions - subscriptions subscriptionRegistry + services serviceRegistry run int32 codecsMu sync.Mutex diff --git a/rpc/utils.go b/rpc/utils.go index 2506c4833..9315cab59 100644 --- a/rpc/utils.go +++ b/rpc/utils.go @@ -119,21 +119,6 @@ func isHexNum(t reflect.Type) bool { return t == bigIntType } -var blockNumberType = reflect.TypeOf((*BlockNumber)(nil)).Elem() - -// Indication if the given block is a BlockNumber -func isBlockNumber(t reflect.Type) bool { - if t == nil { - return false - } - - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - - return t == blockNumberType -} - // suitableCallbacks iterates over the methods of the given type. It will determine if a method satisfies the criteria // for a RPC callback or a subscription callback and adds it to the collection of callbacks or subscriptions. See server // documentation for a summary of these criteria. @@ -210,18 +195,12 @@ METHODS: } switch mtype.NumOut() { - case 0, 1: - break - case 2: - if h.errPos == -1 { // method must one return value and 1 error + case 0, 1, 2: + if mtype.NumOut() == 2 && h.errPos == -1 { // method must one return value and 1 error continue METHODS } - break - default: - continue METHODS + callbacks[mname] = &h } - - callbacks[mname] = &h } return callbacks, subscriptions diff --git a/swarm/api/api.go b/swarm/api/api.go index 803265a3e..7d185ab3c 100644 --- a/swarm/api/api.go +++ b/swarm/api/api.go @@ -34,11 +34,7 @@ import ( "github.com/ethereum/go-ethereum/swarm/storage" ) -var ( - hashMatcher = regexp.MustCompile("^[0-9A-Fa-f]{64}") - slashes = regexp.MustCompile("/+") - domainAndVersion = regexp.MustCompile("[@:;,]+") -) +var hashMatcher = regexp.MustCompile("^[0-9A-Fa-f]{64}") type Resolver interface { Resolve(string) (common.Hash, error) @@ -335,7 +331,6 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte } func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storage.Key, manifestEntryMap map[string]*manifestTrieEntry, err error) { - uri, err := Parse("bzz:/" + mhash) if err != nil { return nil, nil, err @@ -356,5 +351,8 @@ func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storag manifestEntryMap[suffix] = entry }) + if err != nil { + return nil, nil, fmt.Errorf("list with prefix failed %v: %v", key.String(), err) + } return key, manifestEntryMap, nil } diff --git a/swarm/api/client/client_test.go b/swarm/api/client/client_test.go index 03d25049d..edf385dd0 100644 --- a/swarm/api/client/client_test.go +++ b/swarm/api/client/client_test.go @@ -89,8 +89,8 @@ func TestClientUploadDownloadFiles(t *testing.T) { if file.Size != int64(len(expected)) { t.Fatalf("expected downloaded file to be %d bytes, got %d", len(expected), file.Size) } - if file.ContentType != file.ContentType { - t.Fatalf("expected downloaded file to have type %q, got %q", file.ContentType, file.ContentType) + if file.ContentType != "text/plain" { + t.Fatalf("expected downloaded file to have type %q, got %q", "text/plain", file.ContentType) } data, err := ioutil.ReadAll(file) if err != nil { @@ -235,9 +235,7 @@ func TestClientFileList(t *testing.T) { t.Fatal(err) } paths := make([]string, 0, len(list.CommonPrefixes)+len(list.Entries)) - for _, prefix := range list.CommonPrefixes { - paths = append(paths, prefix) - } + paths = append(paths, list.CommonPrefixes...) for _, entry := range list.Entries { paths = append(paths, entry.Path) } diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index 5f64f971b..0b4ec7e18 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -224,7 +224,7 @@ func (s *Server) handleMultipartUpload(req *Request, boundary string, mw *api.Ma if err != nil { return fmt.Errorf("error copying multipart content: %s", err) } - if _, err := tmp.Seek(0, os.SEEK_SET); err != nil { + if _, err := tmp.Seek(0, io.SeekStart); err != nil { return fmt.Errorf("error copying multipart content: %s", err) } reader = tmp @@ -522,6 +522,12 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) { // HandleGetFile handles a GET request to bzz://<manifest>/<path> and responds // with the content of the file at <path> from the given <manifest> func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) { + // ensure the root path has a trailing slash so that relative URLs work + if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { + http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently) + return + } + key, err := s.api.Resolve(r.uri) if err != nil { s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go index 0b124a19a..d3374594b 100644 --- a/swarm/api/http/server_test.go +++ b/swarm/api/http/server_test.go @@ -18,12 +18,16 @@ package http_test import ( "bytes" + "errors" + "fmt" "io/ioutil" "net/http" "sync" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/swarm/api" + swarm "github.com/ethereum/go-ethereum/swarm/api/client" "github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/testutil" ) @@ -93,7 +97,7 @@ func TestBzzrGetPath(t *testing.T) { isexpectedfailrequest = true } } - if isexpectedfailrequest == false { + if !isexpectedfailrequest { t.Fatalf("Response body does not match, expected: %v, got %v", testmanifest[v], string(respbody)) } } @@ -122,9 +126,70 @@ func TestBzzrGetPath(t *testing.T) { } defer resp.Body.Close() respbody, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatalf("ReadAll failed: %v", err) + } if string(respbody) != nonhashresponses[i] { t.Fatalf("Non-Hash response body does not match, expected: %v, got: %v", nonhashresponses[i], string(respbody)) } } } + +// TestBzzRootRedirect tests that getting the root path of a manifest without +// a trailing slash gets redirected to include the trailing slash so that +// relative URLs work as expected. +func TestBzzRootRedirect(t *testing.T) { + srv := testutil.NewTestSwarmServer(t) + defer srv.Close() + + // create a manifest with some data at the root path + client := swarm.NewClient(srv.URL) + data := []byte("data") + file := &swarm.File{ + ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), + ManifestEntry: api.ManifestEntry{ + Path: "", + ContentType: "text/plain", + Size: int64(len(data)), + }, + } + hash, err := client.Upload(file, "") + if err != nil { + t.Fatal(err) + } + + // define a CheckRedirect hook which ensures there is only a single + // redirect to the correct URL + redirected := false + httpClient := http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + if redirected { + return errors.New("too many redirects") + } + redirected = true + expectedPath := "/bzz:/" + hash + "/" + if req.URL.Path != expectedPath { + return fmt.Errorf("expected redirect to %q, got %q", expectedPath, req.URL.Path) + } + return nil + }, + } + + // perform the GET request and assert the response + res, err := httpClient.Get(srv.URL + "/bzz:/" + hash) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + if !redirected { + t.Fatal("expected GET /bzz:/<hash> to redirect to /bzz:/<hash>/ but it didn't") + } + gotData, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(gotData, data) { + t.Fatalf("expected response to equal %q, got %q", data, gotData) + } +} diff --git a/swarm/api/manifest.go b/swarm/api/manifest.go index e251620a7..90f287677 100644 --- a/swarm/api/manifest.go +++ b/swarm/api/manifest.go @@ -63,7 +63,7 @@ func (a *Api) NewManifest() (storage.Key, error) { if err != nil { return nil, err } - return a.Store(bytes.NewReader(data), int64(len(data)), nil) + return a.Store(bytes.NewReader(data), int64(len(data)), &sync.WaitGroup{}) } // ManifestWriter is used to add and remove entries from an underlying manifest diff --git a/swarm/fuse/swarmfs_unix.go b/swarm/fuse/swarmfs_unix.go index 1a8390a4b..75742845a 100644 --- a/swarm/fuse/swarmfs_unix.go +++ b/swarm/fuse/swarmfs_unix.go @@ -59,14 +59,6 @@ type MountInfo struct { lock *sync.RWMutex } -// Inode numbers need to be unique, they are used for caching inside fuse -func newInode() uint64 { - inodeLock.Lock() - defer inodeLock.Unlock() - inode += 1 - return inode -} - func NewMountInfo(mhash, mpoint string, sapi *api.Api) *MountInfo { newMountInfo := &MountInfo{ MountPoint: mpoint, @@ -103,7 +95,7 @@ func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) { } log.Info(fmt.Sprintf("Attempting to mount %s ", cleanedMountPoint)) - key, manifestEntryMap, err := self.swarmApi.BuildDirectoryTree(mhash, true) + _, manifestEntryMap, err := self.swarmApi.BuildDirectoryTree(mhash, true) if err != nil { return nil, err } @@ -116,8 +108,7 @@ func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) { mi.rootDir = rootDir for suffix, entry := range manifestEntryMap { - - key = common.Hex2Bytes(entry.Hash) + key := common.Hex2Bytes(entry.Hash) fullpath := "/" + suffix basepath := filepath.Dir(fullpath) diff --git a/swarm/network/hive.go b/swarm/network/hive.go index 70652c450..d37b7e400 100644 --- a/swarm/network/hive.go +++ b/swarm/network/hive.go @@ -355,7 +355,7 @@ func saveSync(record *kademlia.NodeRecord, node kademlia.Node) { // sends relevant peer data given by the kademlia hive to the requester // TODO: remember peers sent for duration of the session, only new peers sent func (self *Hive) peers(req *retrieveRequestMsgData) { - if req != nil && req.MaxPeers >= 0 { + if req != nil { var addrs []*peerAddr if req.timeout == nil || time.Now().Before(*(req.timeout)) { key := req.Key diff --git a/swarm/network/messages.go b/swarm/network/messages.go index d3858c424..d920def95 100644 --- a/swarm/network/messages.go +++ b/swarm/network/messages.go @@ -133,7 +133,7 @@ type retrieveRequestMsgData struct { from *peer // } -func (self retrieveRequestMsgData) String() string { +func (self *retrieveRequestMsgData) String() string { var from string if self.from == nil { from = "ourselves" @@ -148,12 +148,12 @@ func (self retrieveRequestMsgData) String() string { } // lookups are encoded by missing request ID -func (self retrieveRequestMsgData) isLookup() bool { +func (self *retrieveRequestMsgData) isLookup() bool { return self.Id == 0 } // sets timeout fields -func (self retrieveRequestMsgData) setTimeout(t *time.Time) { +func (self *retrieveRequestMsgData) setTimeout(t *time.Time) { self.timeout = t if t != nil { self.Timeout = uint64(t.UnixNano()) @@ -162,7 +162,7 @@ func (self retrieveRequestMsgData) setTimeout(t *time.Time) { } } -func (self retrieveRequestMsgData) getTimeout() (t *time.Time) { +func (self *retrieveRequestMsgData) getTimeout() (t *time.Time) { if self.Timeout > 0 && self.timeout == nil { timeout := time.Unix(int64(self.Timeout), 0) t = &timeout @@ -180,7 +180,7 @@ type peerAddr struct { } // peerAddr pretty prints as enode -func (self peerAddr) String() string { +func (self *peerAddr) String() string { var nodeid discover.NodeID copy(nodeid[:], self.ID) return discover.NewNode(nodeid, self.IP, 0, self.Port).String() @@ -213,7 +213,7 @@ type peersMsgData struct { } // peers msg pretty printer -func (self peersMsgData) String() string { +func (self *peersMsgData) String() string { var from string if self.from == nil { from = "ourselves" @@ -227,7 +227,7 @@ func (self peersMsgData) String() string { return fmt.Sprintf("from: %v, Key: %x; ID: %v, Peers: %v", from, target, self.Id, self.Peers) } -func (self peersMsgData) setTimeout(t *time.Time) { +func (self *peersMsgData) setTimeout(t *time.Time) { self.timeout = t if t != nil { self.Timeout = uint64(t.UnixNano()) @@ -236,15 +236,6 @@ func (self peersMsgData) setTimeout(t *time.Time) { } } -func (self peersMsgData) getTimeout() (t *time.Time) { - if self.Timeout > 0 && self.timeout == nil { - timeout := time.Unix(int64(self.Timeout), 0) - t = &timeout - self.timeout = t - } - return -} - /* syncRequest diff --git a/swarm/network/protocol.go b/swarm/network/protocol.go index d013b3109..2f880df57 100644 --- a/swarm/network/protocol.go +++ b/swarm/network/protocol.go @@ -40,7 +40,6 @@ import ( "github.com/ethereum/go-ethereum/contracts/chequebook" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" bzzswap "github.com/ethereum/go-ethereum/swarm/services/swap" "github.com/ethereum/go-ethereum/swarm/services/swap/swap" "github.com/ethereum/go-ethereum/swarm/storage" @@ -56,8 +55,6 @@ const ( // bzz represents the swarm wire protocol // an instance is running on each peer type bzz struct { - selfID discover.NodeID // peer's node id used in peer advertising in handshake - key storage.Key // baseaddress as storage.Key storage StorageHandler // handler storage/retrieval related requests coming via the bzz wire protocol hive *Hive // the logistic manager, peerPool, routing service and peer handler dbAccess *DbAccess // access to db storage counter and iterator for syncing diff --git a/swarm/network/syncer.go b/swarm/network/syncer.go index 20129c2a8..a3814e423 100644 --- a/swarm/network/syncer.go +++ b/swarm/network/syncer.go @@ -156,8 +156,7 @@ type syncer struct { quit chan bool // signal to quit loops // DB related fields - dbAccess *DbAccess // access to dbStore - db *storage.LDBDatabase // delivery msg db + dbAccess *DbAccess // access to dbStore // native fields queues [priorities]*syncDb // in-memory cache / queues for sync reqs diff --git a/swarm/storage/chunker.go b/swarm/storage/chunker.go index d55875369..563793e98 100644 --- a/swarm/storage/chunker.go +++ b/swarm/storage/chunker.go @@ -156,14 +156,12 @@ func (self *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, s close(errC) }() - select { - case err := <-errC: - if err != nil { - close(quitC) - return nil, err - } - //TODO: add a timeout + //TODO: add a timeout + if err := <-errC; err != nil { + close(quitC) + return nil, err } + return key, nil } diff --git a/swarm/storage/chunker_test.go b/swarm/storage/chunker_test.go index 40f870246..426074e59 100644 --- a/swarm/storage/chunker_test.go +++ b/swarm/storage/chunker_test.go @@ -43,13 +43,6 @@ type chunkerTester struct { t test } -func (self *chunkerTester) checkChunks(t *testing.T, want int) { - l := len(self.chunks) - if l != want { - t.Errorf("expected %v chunks, got %v", want, l) - } -} - func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key) { // reset self.chunks = make(map[string]*Chunk) @@ -209,20 +202,6 @@ func TestRandomBrokenData(t *testing.T) { } } -func readAll(reader LazySectionReader, result []byte) { - size := int64(len(result)) - - var end int64 - for pos := int64(0); pos < size; pos += 1000 { - if pos+1000 > size { - end = size - } else { - end = pos + 1000 - } - reader.ReadAt(result[pos:end], pos) - } -} - func benchReadAll(reader LazySectionReader) { size, _ := reader.Size(nil) output := make([]byte, 1000) diff --git a/swarm/storage/dbstore.go b/swarm/storage/dbstore.go index 31ff5b64e..cbeddb8cb 100644 --- a/swarm/storage/dbstore.go +++ b/swarm/storage/dbstore.go @@ -23,9 +23,13 @@ package storage import ( + "archive/tar" "bytes" "encoding/binary" + "encoding/hex" "fmt" + "io" + "io/ioutil" "sync" "github.com/ethereum/go-ethereum/log" @@ -260,6 +264,84 @@ func (s *DbStore) collectGarbage(ratio float32) { s.db.Put(keyGCPos, s.gcPos) } +// Export writes all chunks from the store to a tar archive, returning the +// number of chunks written. +func (s *DbStore) Export(out io.Writer) (int64, error) { + tw := tar.NewWriter(out) + defer tw.Close() + + it := s.db.NewIterator() + defer it.Release() + var count int64 + for ok := it.Seek([]byte{kpIndex}); ok; ok = it.Next() { + key := it.Key() + if (key == nil) || (key[0] != kpIndex) { + break + } + + var index dpaDBIndex + decodeIndex(it.Value(), &index) + + data, err := s.db.Get(getDataKey(index.Idx)) + if err != nil { + log.Warn(fmt.Sprintf("Chunk %x found but could not be accessed: %v", key[:], err)) + continue + } + + hdr := &tar.Header{ + Name: hex.EncodeToString(key[1:]), + Mode: 0644, + Size: int64(len(data)), + } + if err := tw.WriteHeader(hdr); err != nil { + return count, err + } + if _, err := tw.Write(data); err != nil { + return count, err + } + count++ + } + + return count, nil +} + +// Import reads chunks into the store from a tar archive, returning the number +// of chunks read. +func (s *DbStore) Import(in io.Reader) (int64, error) { + tr := tar.NewReader(in) + + var count int64 + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } else if err != nil { + return count, err + } + + if len(hdr.Name) != 64 { + log.Warn("ignoring non-chunk file", "name", hdr.Name) + continue + } + + key, err := hex.DecodeString(hdr.Name) + if err != nil { + log.Warn("ignoring invalid chunk file", "name", hdr.Name, "err", err) + continue + } + + data, err := ioutil.ReadAll(tr) + if err != nil { + return count, err + } + + s.Put(&Chunk{Key: key, SData: data}) + count++ + } + + return count, nil +} + func (s *DbStore) Cleanup() { //Iterates over the database and checks that there are no faulty chunks it := s.db.NewIterator() @@ -432,8 +514,7 @@ func (s *DbStore) setCapacity(c uint64) { s.capacity = c if s.entryCnt > c { - var ratio float32 - ratio = float32(1.01) - float32(c)/float32(s.entryCnt) + ratio := float32(1.01) - float32(c)/float32(s.entryCnt) if ratio < gcArrayFreeRatio { ratio = gcArrayFreeRatio } @@ -446,10 +527,6 @@ func (s *DbStore) setCapacity(c uint64) { } } -func (s *DbStore) getEntryCnt() uint64 { - return s.entryCnt -} - func (s *DbStore) Close() { s.db.Close() } diff --git a/swarm/storage/dpa.go b/swarm/storage/dpa.go index e16e4aacb..44a2669f1 100644 --- a/swarm/storage/dpa.go +++ b/swarm/storage/dpa.go @@ -59,7 +59,6 @@ type DPA struct { lock sync.Mutex running bool - wg *sync.WaitGroup quitC chan bool } @@ -239,6 +238,4 @@ func (self *dpaChunkStore) Put(entry *Chunk) { } // Close chunk store -func (self *dpaChunkStore) Close() { - return -} +func (self *dpaChunkStore) Close() {} diff --git a/swarm/storage/localstore.go b/swarm/storage/localstore.go index 14827e361..58f59d0a2 100644 --- a/swarm/storage/localstore.go +++ b/swarm/storage/localstore.go @@ -74,6 +74,4 @@ func (self *LocalStore) Get(key Key) (chunk *Chunk, err error) { } // Close local store -func (self *LocalStore) Close() { - return -} +func (self *LocalStore) Close() {} diff --git a/swarm/storage/memstore.go b/swarm/storage/memstore.go index f96792c6e..155dd0088 100644 --- a/swarm/storage/memstore.go +++ b/swarm/storage/memstore.go @@ -130,10 +130,6 @@ func (s *MemStore) setCapacity(c uint) { s.capacity = c } -func (s *MemStore) getEntryCnt() uint { - return s.entryCnt -} - // entry (not its copy) is going to be in MemStore func (s *MemStore) Put(entry *Chunk) { if s.capacity == 0 { @@ -206,8 +202,6 @@ func (s *MemStore) Put(entry *Chunk) { node.lastDBaccess = s.dbAccessCnt node.updateAccess(s.accessCnt) s.entryCnt++ - - return } func (s *MemStore) Get(hash Key) (chunk *Chunk, err error) { @@ -323,6 +317,4 @@ func (s *MemStore) removeOldest() { } // Close memstore -func (s *MemStore) Close() { - return -} +func (s *MemStore) Close() {} diff --git a/swarm/storage/netstore.go b/swarm/storage/netstore.go index 7c0436c3f..746dd85f6 100644 --- a/swarm/storage/netstore.go +++ b/swarm/storage/netstore.go @@ -19,7 +19,6 @@ package storage import ( "fmt" "path/filepath" - "sync" "time" "github.com/ethereum/go-ethereum/log" @@ -40,7 +39,6 @@ type NetStore struct { hashfunc Hasher localStore *LocalStore cloud CloudStore - lock sync.Mutex } // backend engine for cloud store @@ -134,6 +132,4 @@ func (self *NetStore) Get(key Key) (*Chunk, error) { } // Close netstore -func (self *NetStore) Close() { - return -} +func (self *NetStore) Close() {} diff --git a/swarm/storage/pyramid.go b/swarm/storage/pyramid.go index 79e1927b9..74e00a497 100644 --- a/swarm/storage/pyramid.go +++ b/swarm/storage/pyramid.go @@ -178,10 +178,9 @@ func (self *PyramidChunker) processor(pend, swg *sync.WaitGroup, tasks chan *Tas if swg != nil { swg.Add(1) } - select { - case chunkC <- &Chunk{Key: hash, SData: data, wg: swg}: - // case <- self.quitC - } + + chunkC <- &Chunk{Key: hash, SData: data, wg: swg} + // TODO: consider selecting on self.quitC to avoid blocking forever on shutdown } if depth+1 < len(results.Levels) { delete(results.Levels[depth+1], task.Index/(pow/self.branches)) diff --git a/swarm/swarm.go b/swarm/swarm.go index 830490843..9db15325a 100644 --- a/swarm/swarm.go +++ b/swarm/swarm.go @@ -115,11 +115,11 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *e log.Debug(fmt.Sprintf("Set up swarm network with Kademlia hive")) // setup cloud storage backend - cloud := network.NewForwarder(self.hive) + self.cloud = network.NewForwarder(self.hive) log.Debug(fmt.Sprintf("-> set swarm forwarder as cloud storage backend")) - // setup cloud storage internal access layer - self.storage = storage.NewNetStore(hash, self.lstore, cloud, config.StoreParams) + // setup cloud storage internal access layer + self.storage = storage.NewNetStore(hash, self.lstore, self.cloud, config.StoreParams) log.Debug(fmt.Sprintf("-> swarm net store shared access layer to Swarm Chunk Store")) // set up Depo (storage handler = cloud storage access layer for incoming remote requests) diff --git a/tests/block_test.go b/tests/block_test.go index 3245aca7d..6fc66b17c 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -17,10 +17,7 @@ package tests import ( - "math/big" "testing" - - "github.com/ethereum/go-ethereum/params" ) func TestBlockchain(t *testing.T) { @@ -30,51 +27,19 @@ func TestBlockchain(t *testing.T) { // General state tests are 'exported' as blockchain tests, but we can run them natively. bt.skipLoad(`^GeneralStateTests/`) // Skip random failures due to selfish mining test. - bt.skipLoad(`bcForkUncle\.json/ForkUncle`) - bt.skipLoad(`^bcMultiChainTest\.json/ChainAtoChainB_blockorder`) - bt.skipLoad(`^bcTotalDifficultyTest\.json/(lotsOfLeafs|lotsOfBranches|sideChainWithMoreTransactions)$`) - bt.skipLoad(`^bcMultiChainTest\.json/CallContractFromNotBestBlock`) + bt.skipLoad(`^bcForgedTest/bcForkUncle\.json`) + bt.skipLoad(`^bcMultiChainTest/(ChainAtoChainB_blockorder|CallContractFromNotBestBlock)`) + bt.skipLoad(`^bcTotalDifficultyTest/(lotsOfLeafs|lotsOfBranches|sideChainWithMoreTransactions)`) + // Constantinople is not implemented yet. + bt.skipLoad(`(?i)(constantinople)`) // Expected failures: - bt.fails(`(?i)metropolis`, "metropolis is not supported yet") - bt.fails(`^TestNetwork/bcTheDaoTest\.json/(DaoTransactions$|DaoTransactions_UncleExtradata$)`, "issue in test") - - bt.config(`^TestNetwork/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(5), - DAOForkBlock: big.NewInt(8), - DAOForkSupport: true, - EIP150Block: big.NewInt(10), - EIP155Block: big.NewInt(10), - EIP158Block: big.NewInt(14), - // MetropolisBlock: big.NewInt(16), - }) - bt.config(`^RandomTests/.*EIP150`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - }) - bt.config(`^RandomTests/.*EIP158`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - }) - bt.config(`^RandomTests/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(10), - }) - bt.config(`^Homestead/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - }) - bt.config(`^EIP150/`, params.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - }) - bt.config(`^[^/]+\.json`, params.ChainConfig{ - HomesteadBlock: big.NewInt(1000000), - }) + bt.fails("^TransitionTests/bcEIP158ToByzantium", "byzantium not supported") + bt.fails(`^TransitionTests/bcHomesteadToDao/DaoTransactions(|_UncleExtradata|_EmptyTransactionAndForkBlocksAhead)\.json`, "issue in test") + bt.fails(`^bc(Exploit|Fork|Gas|Multi|Total|State|Random|Uncle|Valid|Wallet).*_Byzantium$`, "byzantium not supported") + bt.fails(`^bcBlockGasLimitTest/(BlockGasLimit2p63m1|TransactionGasHigherThanLimit2p63m1|SuicideTransaction|GasUsedHigherThanBlockGasLimitButNotWithRefundsSuicideFirst|TransactionGasHigherThanLimit2p63m1_2).*_Byzantium$`, "byzantium not supported") bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { - cfg := bt.findConfig(name) - if err := bt.checkFailure(t, name, test.Run(cfg)); err != nil { + if err := bt.checkFailure(t, name, test.Run()); err != nil { t.Error(err) } }) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index a74f7d68d..c1d433ff3 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -53,6 +53,7 @@ type btJSON struct { Pre core.GenesisAlloc `json:"pre"` Post core.GenesisAlloc `json:"postState"` BestBlock common.UnprefixedHash `json:"lastblockhash"` + Network string `json:"network"` } type btBlock struct { @@ -91,7 +92,12 @@ type btHeaderMarshaling struct { Timestamp *math.HexOrDecimal256 } -func (t *BlockTest) Run(config *params.ChainConfig) error { +func (t *BlockTest) Run() error { + config, ok := Forks[t.json.Network] + if !ok { + return UnsupportedForkError{t.json.Network} + } + // import pre accounts & construct test genesis block & state root db, _ := ethdb.NewMemDatabase() gblock, err := t.genesis(config).Commit(db) diff --git a/tests/init.go b/tests/init.go new file mode 100644 index 000000000..0c3fe61d1 --- /dev/null +++ b/tests/init.go @@ -0,0 +1,88 @@ +// Copyright 2017 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 tests + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/params" +) + +// This table defines supported forks and their chain config. +var Forks = map[string]*params.ChainConfig{ + "Frontier": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + }, + "Homestead": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + }, + "EIP150": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + }, + "EIP158": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + }, + "Byzantium": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + DAOForkBlock: big.NewInt(0), + MetropolisBlock: big.NewInt(0), + }, + "FrontierToHomesteadAt5": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: big.NewInt(5), + }, + "HomesteadToEIP150At5": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(5), + }, + "HomesteadToDaoAt5": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: big.NewInt(5), + DAOForkSupport: true, + }, + "EIP158ToByzantiumAt5": ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + MetropolisBlock: big.NewInt(5), + }, +} + +// UnsupportedForkError is returned when a test requests a fork that isn't implemented. +type UnsupportedForkError struct { + Name string +} + +func (e UnsupportedForkError) Error() string { + return fmt.Sprintf("unsupported fork %q", e.Name) +} diff --git a/tests/state_test.go b/tests/state_test.go index e4e691589..ab6dc423f 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -33,11 +33,9 @@ func TestState(t *testing.T) { st.skipShortMode(`^stQuadraticComplexityTest/`) // Broken tests: st.skipLoad(`^stTransactionTest/OverflowGasRequire\.json`) // gasLimit > 256 bits - st.skipLoad(`^stStackTests/shallowStackOK\.json`) // bad hex encoding st.skipLoad(`^stTransactionTest/zeroSigTransa[^/]*\.json`) // EIP-86 is not supported yet // Expected failures: - st.fails(`^stCallCreateCallCodeTest/createJS_ExampleContract\.json`, "bug in test") - st.fails(`^stCodeSizeLimit/codesizeOOGInvalidSize\.json/(Frontier|Homestead)`, + st.fails(`^stCodeSizeLimit/codesizeOOGInvalidSize\.json/(Frontier|Homestead|EIP150)`, "code size limit implementation is not conditional on fork") st.fails(`^stRevertTest/RevertDepthCreateAddressCollision\.json/EIP15[08]/[67]`, "bug in test") st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/EIP158`, "bug in test") @@ -49,8 +47,8 @@ func TestState(t *testing.T) { key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index) name := name + "/" + key t.Run(key, func(t *testing.T) { - if subtest.Fork == "Metropolis" { - t.Skip("metropolis not supported yet") + if subtest.Fork == "Constantinople" || subtest.Fork == "Byzantium" { + t.Skip("constantinople, byzantium not supported yet") } withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { return st.checkFailure(t, name, test.Run(subtest, vmconfig)) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 5c7ed5d67..2bf940bab 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -37,37 +37,6 @@ import ( "github.com/ethereum/go-ethereum/params" ) -// This table defines supported forks and their chain config. -var stateTestForks = map[string]*params.ChainConfig{ - "Frontier": ¶ms.ChainConfig{ - ChainId: big.NewInt(1), - }, - "Homestead": ¶ms.ChainConfig{ - HomesteadBlock: big.NewInt(0), - ChainId: big.NewInt(1), - }, - "EIP150": ¶ms.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - ChainId: big.NewInt(1), - }, - "EIP158": ¶ms.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ChainId: big.NewInt(1), - }, - "Metropolis": ¶ms.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - MetropolisBlock: big.NewInt(0), - ChainId: big.NewInt(1), - }, -} - // StateTest checks transaction processing without block context. // See https://github.com/ethereum/EIPs/issues/176 for the test format specification. type StateTest struct { @@ -167,9 +136,9 @@ func (t *StateTest) Subtests() []StateSubtest { // Run executes a specific subtest. func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) error { - config, ok := stateTestForks[subtest.Fork] + config, ok := Forks[subtest.Fork] if !ok { - return fmt.Errorf("no config for fork %q", subtest.Fork) + return UnsupportedForkError{subtest.Fork} } block, _ := t.genesis(config).ToBlock() db, _ := ethdb.NewMemDatabase() diff --git a/tests/testdata b/tests/testdata -Subproject f1de8c3b7fa2c2c0aa281b6b3a1ad7010356c5f +Subproject 85f6d7cc01b6bd04e071f5ba579fc675cfd2043 diff --git a/trie/sync.go b/trie/sync.go index 9e8449431..1e4f8d87c 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -55,7 +55,7 @@ type SyncResult struct { // syncMemBatch is an in-memory buffer of successfully downloaded but not yet // persisted data items. type syncMemBatch struct { - batch map[common.Hash][]byte // In-memory membatch of recently ocmpleted items + batch map[common.Hash][]byte // In-memory membatch of recently completed items order []common.Hash // Order of completion to prevent out-of-order data loss } diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE new file mode 100644 index 000000000..1b1b1921e --- /dev/null +++ b/vendor/github.com/golang/protobuf/LICENSE @@ -0,0 +1,31 @@ +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/vendor/github.com/golang/protobuf/proto/Makefile b/vendor/github.com/golang/protobuf/proto/Makefile new file mode 100644 index 000000000..e2e0651a9 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/Makefile @@ -0,0 +1,43 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +install: + go install + +test: install generate-test-pbs + go test + + +generate-test-pbs: + make install + make -C testdata + protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto + make diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go new file mode 100644 index 000000000..e392575b3 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/clone.go @@ -0,0 +1,229 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer deep copy and merge. +// TODO: RawMessage. + +package proto + +import ( + "log" + "reflect" + "strings" +) + +// Clone returns a deep copy of a protocol buffer. +func Clone(pb Message) Message { + in := reflect.ValueOf(pb) + if in.IsNil() { + return pb + } + + out := reflect.New(in.Type().Elem()) + // out is empty so a merge is a deep copy. + mergeStruct(out.Elem(), in.Elem()) + return out.Interface().(Message) +} + +// Merge merges src into dst. +// Required and optional fields that are set in src will be set to that value in dst. +// Elements of repeated fields will be appended. +// Merge panics if src and dst are not the same type, or if dst is nil. +func Merge(dst, src Message) { + in := reflect.ValueOf(src) + out := reflect.ValueOf(dst) + if out.IsNil() { + panic("proto: nil destination") + } + if in.Type() != out.Type() { + // Explicit test prior to mergeStruct so that mistyped nils will fail + panic("proto: type mismatch") + } + if in.IsNil() { + // Merging nil into non-nil is a quiet no-op + return + } + mergeStruct(out.Elem(), in.Elem()) +} + +func mergeStruct(out, in reflect.Value) { + sprop := GetProperties(in.Type()) + for i := 0; i < in.NumField(); i++ { + f := in.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) + } + + if emIn, ok := extendable(in.Addr().Interface()); ok { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + uf := in.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return + } + uin := uf.Bytes() + if len(uin) > 0 { + out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) + } +} + +// mergeAny performs a merge between two values of the same type. +// viaPtr indicates whether the values were indirected through a pointer (implying proto2). +// prop is set if this is a struct field (it may be nil). +func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { + if in.Type() == protoMessageType { + if !in.IsNil() { + if out.IsNil() { + out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) + } else { + Merge(out.Interface().(Message), in.Interface().(Message)) + } + } + return + } + switch in.Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + if !viaPtr && isProto3Zero(in) { + return + } + out.Set(in) + case reflect.Interface: + // Probably a oneof field; copy non-nil values. + if in.IsNil() { + return + } + // Allocate destination if it is not set, or set to a different type. + // Otherwise we will merge as normal. + if out.IsNil() || out.Elem().Type() != in.Elem().Type() { + out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) + } + mergeAny(out.Elem(), in.Elem(), false, nil) + case reflect.Map: + if in.Len() == 0 { + return + } + if out.IsNil() { + out.Set(reflect.MakeMap(in.Type())) + } + // For maps with value types of *T or []byte we need to deep copy each value. + elemKind := in.Type().Elem().Kind() + for _, key := range in.MapKeys() { + var val reflect.Value + switch elemKind { + case reflect.Ptr: + val = reflect.New(in.Type().Elem().Elem()) + mergeAny(val, in.MapIndex(key), false, nil) + case reflect.Slice: + val = in.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + default: + val = in.MapIndex(key) + } + out.SetMapIndex(key, val) + } + case reflect.Ptr: + if in.IsNil() { + return + } + if out.IsNil() { + out.Set(reflect.New(in.Elem().Type())) + } + mergeAny(out.Elem(), in.Elem(), true, nil) + case reflect.Slice: + if in.IsNil() { + return + } + if in.Type().Elem().Kind() == reflect.Uint8 { + // []byte is a scalar bytes field, not a repeated field. + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value, and should not + // be merged. + if prop != nil && prop.proto3 && in.Len() == 0 { + return + } + + // Make a deep copy. + // Append to []byte{} instead of []byte(nil) so that we never end up + // with a nil result. + out.SetBytes(append([]byte{}, in.Bytes()...)) + return + } + n := in.Len() + if out.IsNil() { + out.Set(reflect.MakeSlice(in.Type(), 0, n)) + } + switch in.Type().Elem().Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + out.Set(reflect.AppendSlice(out, in)) + default: + for i := 0; i < n; i++ { + x := reflect.Indirect(reflect.New(in.Type().Elem())) + mergeAny(x, in.Index(i), false, nil) + out.Set(reflect.Append(out, x)) + } + } + case reflect.Struct: + mergeStruct(out, in) + default: + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to copy %v", in) + } +} + +func mergeExtension(out, in map[int32]Extension) { + for extNum, eIn := range in { + eOut := Extension{desc: eIn.desc} + if eIn.value != nil { + v := reflect.New(reflect.TypeOf(eIn.value)).Elem() + mergeAny(v, reflect.ValueOf(eIn.value), false, nil) + eOut.value = v.Interface() + } + if eIn.enc != nil { + eOut.enc = make([]byte, len(eIn.enc)) + copy(eOut.enc, eIn.enc) + } + + out[extNum] = eOut + } +} diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go new file mode 100644 index 000000000..aa207298f --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/decode.go @@ -0,0 +1,970 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for decoding protocol buffer data to construct in-memory representations. + */ + +import ( + "errors" + "fmt" + "io" + "os" + "reflect" +) + +// errOverflow is returned when an integer is too large to be represented. +var errOverflow = errors.New("proto: integer overflow") + +// ErrInternalBadWireType is returned by generated code when an incorrect +// wire type is encountered. It does not get returned to user code. +var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") + +// The fundamental decoders that interpret bytes on the wire. +// Those that take integer types all return uint64 and are +// therefore of type valueDecoder. + +// DecodeVarint reads a varint-encoded integer from the slice. +// It returns the integer and the number of bytes consumed, or +// zero if there is not enough. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func DecodeVarint(buf []byte) (x uint64, n int) { + for shift := uint(0); shift < 64; shift += 7 { + if n >= len(buf) { + return 0, 0 + } + b := uint64(buf[n]) + n++ + x |= (b & 0x7F) << shift + if (b & 0x80) == 0 { + return x, n + } + } + + // The number is too large to represent in a 64-bit value. + return 0, 0 +} + +func (p *Buffer) decodeVarintSlow() (x uint64, err error) { + i := p.index + l := len(p.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := p.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + p.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = errOverflow + return +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) DecodeVarint() (x uint64, err error) { + i := p.index + buf := p.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + p.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return p.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x = uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + // x -= 0x80 << 63 // Always zero. + + return 0, errOverflow + +done: + p.index = i + return x, nil +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := p.index + 8 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-8]) + x |= uint64(p.buf[i-7]) << 8 + x |= uint64(p.buf[i-6]) << 16 + x |= uint64(p.buf[i-5]) << 24 + x |= uint64(p.buf[i-4]) << 32 + x |= uint64(p.buf[i-3]) << 40 + x |= uint64(p.buf[i-2]) << 48 + x |= uint64(p.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := p.index + 4 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-4]) + x |= uint64(p.buf[i-3]) << 8 + x |= uint64(p.buf[i-2]) << 16 + x |= uint64(p.buf[i-1]) << 24 + return +} + +// DecodeZigzag64 reads a zigzag-encoded 64-bit integer +// from the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) DecodeZigzag64() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) + return +} + +// DecodeZigzag32 reads a zigzag-encoded 32-bit integer +// from the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) DecodeZigzag32() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) + return +} + +// These are not ValueDecoders: they produce an array of bytes or a string. +// bytes, embedded messages + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := p.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := p.index + nb + if end < p.index || end > len(p.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + // todo: check if can get more uses of alloc=false + buf = p.buf[p.index:end] + p.index += nb + return + } + + buf = make([]byte, nb) + copy(buf, p.buf[p.index:]) + p.index += nb + return +} + +// DecodeStringBytes reads an encoded string from the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) DecodeStringBytes() (s string, err error) { + buf, err := p.DecodeRawBytes(false) + if err != nil { + return + } + return string(buf), nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +// If the protocol buffer has extensions, and the field matches, add it as an extension. +// Otherwise, if the XXX_unrecognized field exists, append the skipped data there. +func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error { + oi := o.index + + err := o.skip(t, tag, wire) + if err != nil { + return err + } + + if !unrecField.IsValid() { + return nil + } + + ptr := structPointer_Bytes(base, unrecField) + + // Add the skipped field to struct field + obuf := o.buf + + o.buf = *ptr + o.EncodeVarint(uint64(tag<<3 | wire)) + *ptr = append(o.buf, obuf[oi:o.index]...) + + o.buf = obuf + + return nil +} + +// Skip the next item in the buffer. Its wire type is decoded and presented as an argument. +func (o *Buffer) skip(t reflect.Type, tag, wire int) error { + + var u uint64 + var err error + + switch wire { + case WireVarint: + _, err = o.DecodeVarint() + case WireFixed64: + _, err = o.DecodeFixed64() + case WireBytes: + _, err = o.DecodeRawBytes(false) + case WireFixed32: + _, err = o.DecodeFixed32() + case WireStartGroup: + for { + u, err = o.DecodeVarint() + if err != nil { + break + } + fwire := int(u & 0x7) + if fwire == WireEndGroup { + break + } + ftag := int(u >> 3) + err = o.skip(t, ftag, fwire) + if err != nil { + break + } + } + default: + err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t) + } + return err +} + +// Unmarshaler is the interface representing objects that can +// unmarshal themselves. The method should reset the receiver before +// decoding starts. The argument points to data that may be +// overwritten, so implementations should not keep references to the +// buffer. +type Unmarshaler interface { + Unmarshal([]byte) error +} + +// Unmarshal parses the protocol buffer representation in buf and places the +// decoded result in pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// Unmarshal resets pb before starting to unmarshal, so any +// existing data in pb is always removed. Use UnmarshalMerge +// to preserve and append to existing data. +func Unmarshal(buf []byte, pb Message) error { + pb.Reset() + return UnmarshalMerge(buf, pb) +} + +// UnmarshalMerge parses the protocol buffer representation in buf and +// writes the decoded result to pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// UnmarshalMerge merges into existing data in pb. +// Most code should use Unmarshal instead. +func UnmarshalMerge(buf []byte, pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// DecodeMessage reads a count-delimited message from the Buffer. +func (p *Buffer) DecodeMessage(pb Message) error { + enc, err := p.DecodeRawBytes(false) + if err != nil { + return err + } + return NewBuffer(enc).Unmarshal(pb) +} + +// DecodeGroup reads a tag-delimited group from the Buffer. +func (p *Buffer) DecodeGroup(pb Message) error { + typ, base, err := getbase(pb) + if err != nil { + return err + } + return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) +} + +// Unmarshal parses the protocol buffer representation in the +// Buffer and places the decoded result in pb. If the struct +// underlying pb does not match the data in the buffer, the results can be +// unpredictable. +// +// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. +func (p *Buffer) Unmarshal(pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(Unmarshaler); ok { + err := u.Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + + typ, base, err := getbase(pb) + if err != nil { + return err + } + + err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) + + if collectStats { + stats.Decode++ + } + + return err +} + +// unmarshalType does the work of unmarshaling a structure. +func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error { + var state errorState + required, reqFields := prop.reqCount, uint64(0) + + var err error + for err == nil && o.index < len(o.buf) { + oi := o.index + var u uint64 + u, err = o.DecodeVarint() + if err != nil { + break + } + wire := int(u & 0x7) + if wire == WireEndGroup { + if is_group { + if required > 0 { + // Not enough information to determine the exact field. + // (See below.) + return &RequiredNotSetError{"{Unknown}"} + } + return nil // input is satisfied + } + return fmt.Errorf("proto: %s: wiretype end group for non-group", st) + } + tag := int(u >> 3) + if tag <= 0 { + return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire) + } + fieldnum, ok := prop.decoderTags.get(tag) + if !ok { + // Maybe it's an extension? + if prop.extendable { + if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) { + if err = o.skip(st, tag, wire); err == nil { + extmap := e.extensionsWrite() + ext := extmap[int32(tag)] // may be missing + ext.enc = append(ext.enc, o.buf[oi:o.index]...) + extmap[int32(tag)] = ext + } + continue + } + } + // Maybe it's a oneof? + if prop.oneofUnmarshaler != nil { + m := structPointer_Interface(base, st).(Message) + // First return value indicates whether tag is a oneof field. + ok, err = prop.oneofUnmarshaler(m, tag, wire, o) + if err == ErrInternalBadWireType { + // Map the error to something more descriptive. + // Do the formatting here to save generated code space. + err = fmt.Errorf("bad wiretype for oneof field in %T", m) + } + if ok { + continue + } + } + err = o.skipAndSave(st, tag, wire, base, prop.unrecField) + continue + } + p := prop.Prop[fieldnum] + + if p.dec == nil { + fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name) + continue + } + dec := p.dec + if wire != WireStartGroup && wire != p.WireType { + if wire == WireBytes && p.packedDec != nil { + // a packable field + dec = p.packedDec + } else { + err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType) + continue + } + } + decErr := dec(o, p, base) + if decErr != nil && !state.shouldContinue(decErr, p) { + err = decErr + } + if err == nil && p.Required { + // Successfully decoded a required field. + if tag <= 64 { + // use bitmap for fields 1-64 to catch field reuse. + var mask uint64 = 1 << uint64(tag-1) + if reqFields&mask == 0 { + // new required field + reqFields |= mask + required-- + } + } else { + // This is imprecise. It can be fooled by a required field + // with a tag > 64 that is encoded twice; that's very rare. + // A fully correct implementation would require allocating + // a data structure, which we would like to avoid. + required-- + } + } + } + if err == nil { + if is_group { + return io.ErrUnexpectedEOF + } + if state.err != nil { + return state.err + } + if required > 0 { + // Not enough information to determine the exact field. If we use extra + // CPU, we could determine the field only if the missing required field + // has a tag <= 64 and we check reqFields. + return &RequiredNotSetError{"{Unknown}"} + } + } + return err +} + +// Individual type decoders +// For each, +// u is the decoded value, +// v is a pointer to the field (pointer) in the struct + +// Sizes of the pools to allocate inside the Buffer. +// The goal is modest amortization and allocation +// on at least 16-byte boundaries. +const ( + boolPoolSize = 16 + uint32PoolSize = 8 + uint64PoolSize = 4 +) + +// Decode a bool. +func (o *Buffer) dec_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + if len(o.bools) == 0 { + o.bools = make([]bool, boolPoolSize) + } + o.bools[0] = u != 0 + *structPointer_Bool(base, p.field) = &o.bools[0] + o.bools = o.bools[1:] + return nil +} + +func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + *structPointer_BoolVal(base, p.field) = u != 0 + return nil +} + +// Decode an int32. +func (o *Buffer) dec_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32_Set(structPointer_Word32(base, p.field), o, uint32(u)) + return nil +} + +func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u)) + return nil +} + +// Decode an int64. +func (o *Buffer) dec_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64_Set(structPointer_Word64(base, p.field), o, u) + return nil +} + +func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + word64Val_Set(structPointer_Word64Val(base, p.field), o, u) + return nil +} + +// Decode a string. +func (o *Buffer) dec_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_String(base, p.field) = &s + return nil +} + +func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + *structPointer_StringVal(base, p.field) = s + return nil +} + +// Decode a slice of bytes ([]byte). +func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + *structPointer_Bytes(base, p.field) = b + return nil +} + +// Decode a slice of bools ([]bool). +func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + v := structPointer_BoolSlice(base, p.field) + *v = append(*v, u != 0) + return nil +} + +// Decode a slice of bools ([]bool) in packed format. +func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error { + v := structPointer_BoolSlice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded bools + fin := o.index + nb + if fin < o.index { + return errOverflow + } + + y := *v + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + y = append(y, u != 0) + } + + *v = y + return nil +} + +// Decode a slice of int32s ([]int32). +func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + structPointer_Word32Slice(base, p.field).Append(uint32(u)) + return nil +} + +// Decode a slice of int32s ([]int32) in packed format. +func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int32s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(uint32(u)) + } + return nil +} + +// Decode a slice of int64s ([]int64). +func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error { + u, err := p.valDec(o) + if err != nil { + return err + } + + structPointer_Word64Slice(base, p.field).Append(u) + return nil +} + +// Decode a slice of int64s ([]int64) in packed format. +func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Slice(base, p.field) + + nn, err := o.DecodeVarint() + if err != nil { + return err + } + nb := int(nn) // number of bytes of encoded int64s + + fin := o.index + nb + if fin < o.index { + return errOverflow + } + for o.index < fin { + u, err := p.valDec(o) + if err != nil { + return err + } + v.Append(u) + } + return nil +} + +// Decode a slice of strings ([]string). +func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error { + s, err := o.DecodeStringBytes() + if err != nil { + return err + } + v := structPointer_StringSlice(base, p.field) + *v = append(*v, s) + return nil +} + +// Decode a slice of slice of bytes ([][]byte). +func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { + b, err := o.DecodeRawBytes(true) + if err != nil { + return err + } + v := structPointer_BytesSlice(base, p.field) + *v = append(*v, b) + return nil +} + +// Decode a map field. +func (o *Buffer) dec_new_map(p *Properties, base structPointer) error { + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + oi := o.index // index at the end of this map entry + o.index -= len(raw) // move buffer back to start of map entry + + mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V + if mptr.Elem().IsNil() { + mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem())) + } + v := mptr.Elem() // map[K]V + + // Prepare addressable doubly-indirect placeholders for the key and value types. + // See enc_new_map for why. + keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K + keybase := toStructPointer(keyptr.Addr()) // **K + + var valbase structPointer + var valptr reflect.Value + switch p.mtype.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valptr = reflect.ValueOf(&dummy) // *[]byte + valbase = toStructPointer(valptr) // *[]byte + case reflect.Ptr: + // message; valptr is **Msg; need to allocate the intermediate pointer + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valptr.Set(reflect.New(valptr.Type().Elem())) + valbase = toStructPointer(valptr) + default: + // everything else + valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V + valbase = toStructPointer(valptr.Addr()) // **V + } + + // Decode. + // This parses a restricted wire format, namely the encoding of a message + // with two fields. See enc_new_map for the format. + for o.index < oi { + // tagcode for key and value properties are always a single byte + // because they have tags 1 and 2. + tagcode := o.buf[o.index] + o.index++ + switch tagcode { + case p.mkeyprop.tagcode[0]: + if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil { + return err + } + case p.mvalprop.tagcode[0]: + if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil { + return err + } + default: + // TODO: Should we silently skip this instead? + return fmt.Errorf("proto: bad map data tag %d", raw[0]) + } + } + keyelem, valelem := keyptr.Elem(), valptr.Elem() + if !keyelem.IsValid() { + keyelem = reflect.Zero(p.mtype.Key()) + } + if !valelem.IsValid() { + valelem = reflect.Zero(p.mtype.Elem()) + } + + v.SetMapIndex(keyelem, valelem) + return nil +} + +// Decode a group. +func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + return o.unmarshalType(p.stype, p.sprop, true, bas) +} + +// Decode an embedded message. +func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) { + raw, e := o.DecodeRawBytes(false) + if e != nil { + return e + } + + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := structPointer_Interface(bas, p.stype) + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, false, bas) + o.buf = obuf + o.index = oi + + return err +} + +// Decode a slice of embedded messages. +func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, false, base) +} + +// Decode a slice of embedded groups. +func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error { + return o.dec_slice_struct(p, true, base) +} + +// Decode a slice of structs ([]*struct). +func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error { + v := reflect.New(p.stype) + bas := toStructPointer(v) + structPointer_StructPointerSlice(base, p.field).Append(bas) + + if is_group { + err := o.unmarshalType(p.stype, p.sprop, is_group, bas) + return err + } + + raw, err := o.DecodeRawBytes(false) + if err != nil { + return err + } + + // If the object can unmarshal itself, let it. + if p.isUnmarshaler { + iv := v.Interface() + return iv.(Unmarshaler).Unmarshal(raw) + } + + obuf := o.buf + oi := o.index + o.buf = raw + o.index = 0 + + err = o.unmarshalType(p.stype, p.sprop, is_group, bas) + + o.buf = obuf + o.index = oi + + return err +} diff --git a/vendor/github.com/golang/protobuf/proto/encode.go b/vendor/github.com/golang/protobuf/proto/encode.go new file mode 100644 index 000000000..8b84d1b22 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/encode.go @@ -0,0 +1,1362 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "errors" + "fmt" + "reflect" + "sort" +) + +// RequiredNotSetError is the error returned if Marshal is called with +// a protocol buffer struct whose required fields have not +// all been initialized. It is also the error returned if Unmarshal is +// called with an encoded protocol buffer that does not include all the +// required fields. +// +// When printed, RequiredNotSetError reports the first unset required field in a +// message. If the field cannot be precisely determined, it is reported as +// "{Unknown}". +type RequiredNotSetError struct { + field string +} + +func (e *RequiredNotSetError) Error() string { + return fmt.Sprintf("proto: required field %q not set", e.field) +} + +var ( + // errRepeatedHasNil is the error returned if Marshal is called with + // a struct with a repeated field containing a nil element. + errRepeatedHasNil = errors.New("proto: repeated field has nil element") + + // errOneofHasNil is the error returned if Marshal is called with + // a struct with a oneof field containing a nil element. + errOneofHasNil = errors.New("proto: oneof field has nil value") + + // ErrNil is the error returned if Marshal is called with nil. + ErrNil = errors.New("proto: Marshal called with nil") + + // ErrTooLarge is the error returned if Marshal is called with a + // message that encodes to >2GB. + ErrTooLarge = errors.New("proto: message encodes to over 2 GB") +) + +// The fundamental encoders that put bytes on the wire. +// Those that take integer types all accept uint64 and are +// therefore of type valueEncoder. + +const maxVarintBytes = 10 // maximum length of a varint + +// maxMarshalSize is the largest allowed size of an encoded protobuf, +// since C++ and Java use signed int32s for the size. +const maxMarshalSize = 1<<31 - 1 + +// EncodeVarint returns the varint encoding of x. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +// Not used by the package itself, but helpful to clients +// wishing to use the same encoding. +func EncodeVarint(x uint64) []byte { + var buf [maxVarintBytes]byte + var n int + for n = 0; x > 127; n++ { + buf[n] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + buf[n] = uint8(x) + n++ + return buf[0:n] +} + +// EncodeVarint writes a varint-encoded integer to the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) EncodeVarint(x uint64) error { + for x >= 1<<7 { + p.buf = append(p.buf, uint8(x&0x7f|0x80)) + x >>= 7 + } + p.buf = append(p.buf, uint8(x)) + return nil +} + +// SizeVarint returns the varint encoding size of an integer. +func SizeVarint(x uint64) int { + return sizeVarint(x) +} + +func sizeVarint(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} + +// EncodeFixed64 writes a 64-bit integer to the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) EncodeFixed64(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24), + uint8(x>>32), + uint8(x>>40), + uint8(x>>48), + uint8(x>>56)) + return nil +} + +func sizeFixed64(x uint64) int { + return 8 +} + +// EncodeFixed32 writes a 32-bit integer to the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) EncodeFixed32(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24)) + return nil +} + +func sizeFixed32(x uint64) int { + return 4 +} + +// EncodeZigzag64 writes a zigzag-encoded 64-bit integer +// to the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) EncodeZigzag64(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63))) +} + +func sizeZigzag64(x uint64) int { + return sizeVarint((x << 1) ^ uint64((int64(x) >> 63))) +} + +// EncodeZigzag32 writes a zigzag-encoded 32-bit integer +// to the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) EncodeZigzag32(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +func sizeZigzag32(x uint64) int { + return sizeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) EncodeRawBytes(b []byte) error { + p.EncodeVarint(uint64(len(b))) + p.buf = append(p.buf, b...) + return nil +} + +func sizeRawBytes(b []byte) int { + return sizeVarint(uint64(len(b))) + + len(b) +} + +// EncodeStringBytes writes an encoded string to the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) EncodeStringBytes(s string) error { + p.EncodeVarint(uint64(len(s))) + p.buf = append(p.buf, s...) + return nil +} + +func sizeStringBytes(s string) int { + return sizeVarint(uint64(len(s))) + + len(s) +} + +// Marshaler is the interface representing objects that can marshal themselves. +type Marshaler interface { + Marshal() ([]byte, error) +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, returning the data. +func Marshal(pb Message) ([]byte, error) { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + return m.Marshal() + } + p := NewBuffer(nil) + err := p.Marshal(pb) + if p.buf == nil && err == nil { + // Return a non-nil slice on success. + return []byte{}, nil + } + return p.buf, err +} + +// EncodeMessage writes the protocol buffer to the Buffer, +// prefixed by a varint-encoded length. +func (p *Buffer) EncodeMessage(pb Message) error { + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + var state errorState + err = p.enc_len_struct(GetProperties(t.Elem()), base, &state) + } + return err +} + +// Marshal takes the protocol buffer +// and encodes it into the wire format, writing the result to the +// Buffer. +func (p *Buffer) Marshal(pb Message) error { + // Can the object marshal itself? + if m, ok := pb.(Marshaler); ok { + data, err := m.Marshal() + p.buf = append(p.buf, data...) + return err + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return ErrNil + } + if err == nil { + err = p.enc_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + (stats).Encode++ // Parens are to work around a goimports bug. + } + + if len(p.buf) > maxMarshalSize { + return ErrTooLarge + } + return err +} + +// Size returns the encoded size of a protocol buffer. +func Size(pb Message) (n int) { + // Can the object marshal itself? If so, Size is slow. + // TODO: add Size to Marshaler, or add a Sizer interface. + if m, ok := pb.(Marshaler); ok { + b, _ := m.Marshal() + return len(b) + } + + t, base, err := getbase(pb) + if structPointer_IsNil(base) { + return 0 + } + if err == nil { + n = size_struct(GetProperties(t.Elem()), base) + } + + if collectStats { + (stats).Size++ // Parens are to work around a goimports bug. + } + + return +} + +// Individual type encoders. + +// Encode a bool. +func (o *Buffer) enc_bool(p *Properties, base structPointer) error { + v := *structPointer_Bool(base, p.field) + if v == nil { + return ErrNil + } + x := 0 + if *v { + x = 1 + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_bool(p *Properties, base structPointer) error { + v := *structPointer_BoolVal(base, p.field) + if !v { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, 1) + return nil +} + +func size_bool(p *Properties, base structPointer) int { + v := *structPointer_Bool(base, p.field) + if v == nil { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +func size_proto3_bool(p *Properties, base structPointer) int { + v := *structPointer_BoolVal(base, p.field) + if !v && !p.oneof { + return 0 + } + return len(p.tagcode) + 1 // each bool takes exactly one byte +} + +// Encode an int32. +func (o *Buffer) enc_int32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_int32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := int32(word32_Get(v)) // permit sign extension to use full 64-bit range + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_int32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode a uint32. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return ErrNil + } + x := word32_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func (o *Buffer) enc_proto3_uint32(p *Properties, base structPointer) error { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, uint64(x)) + return nil +} + +func size_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32(base, p.field) + if word32_IsNil(v) { + return 0 + } + x := word32_Get(v) + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +func size_proto3_uint32(p *Properties, base structPointer) (n int) { + v := structPointer_Word32Val(base, p.field) + x := word32Val_Get(v) + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(uint64(x)) + return +} + +// Encode an int64. +func (o *Buffer) enc_int64(p *Properties, base structPointer) error { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return ErrNil + } + x := word64_Get(v) + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func (o *Buffer) enc_proto3_int64(p *Properties, base structPointer) error { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, x) + return nil +} + +func size_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64(base, p.field) + if word64_IsNil(v) { + return 0 + } + x := word64_Get(v) + n += len(p.tagcode) + n += p.valSize(x) + return +} + +func size_proto3_int64(p *Properties, base structPointer) (n int) { + v := structPointer_Word64Val(base, p.field) + x := word64Val_Get(v) + if x == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += p.valSize(x) + return +} + +// Encode a string. +func (o *Buffer) enc_string(p *Properties, base structPointer) error { + v := *structPointer_String(base, p.field) + if v == nil { + return ErrNil + } + x := *v + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(x) + return nil +} + +func (o *Buffer) enc_proto3_string(p *Properties, base structPointer) error { + v := *structPointer_StringVal(base, p.field) + if v == "" { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(v) + return nil +} + +func size_string(p *Properties, base structPointer) (n int) { + v := *structPointer_String(base, p.field) + if v == nil { + return 0 + } + x := *v + n += len(p.tagcode) + n += sizeStringBytes(x) + return +} + +func size_proto3_string(p *Properties, base structPointer) (n int) { + v := *structPointer_StringVal(base, p.field) + if v == "" && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeStringBytes(v) + return +} + +// All protocol buffer fields are nillable, but be careful. +func isNil(v reflect.Value) bool { + switch v.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + } + return false +} + +// Encode a message struct. +func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error { + var state errorState + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return ErrNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + return state.err + } + + o.buf = append(o.buf, p.tagcode...) + return o.enc_len_struct(p.sprop, structp, &state) +} + +func size_struct_message(p *Properties, base structPointer) int { + structp := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(structp) { + return 0 + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n0 := len(p.tagcode) + n1 := sizeRawBytes(data) + return n0 + n1 + } + + n0 := len(p.tagcode) + n1 := size_struct(p.sprop, structp) + n2 := sizeVarint(uint64(n1)) // size of encoded length + return n0 + n1 + n2 +} + +// Encode a group struct. +func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error { + var state errorState + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return ErrNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + err := o.enc_struct(p.sprop, b) + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return state.err +} + +func size_struct_group(p *Properties, base structPointer) (n int) { + b := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(b) { + return 0 + } + + n += sizeVarint(uint64((p.Tag << 3) | WireStartGroup)) + n += size_struct(p.sprop, b) + n += sizeVarint(uint64((p.Tag << 3) | WireEndGroup)) + return +} + +// Encode a slice of bools ([]bool). +func (o *Buffer) enc_slice_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + for _, x := range s { + o.buf = append(o.buf, p.tagcode...) + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_bool(p *Properties, base structPointer) int { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + return l * (len(p.tagcode) + 1) // each bool takes exactly one byte +} + +// Encode a slice of bools ([]bool) in packed format. +func (o *Buffer) enc_slice_packed_bool(p *Properties, base structPointer) error { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(l)) // each bool takes exactly one byte + for _, x := range s { + v := uint64(0) + if x { + v = 1 + } + p.valEnc(o, v) + } + return nil +} + +func size_slice_packed_bool(p *Properties, base structPointer) (n int) { + s := *structPointer_BoolSlice(base, p.field) + l := len(s) + if l == 0 { + return 0 + } + n += len(p.tagcode) + n += sizeVarint(uint64(l)) + n += l // each bool takes exactly one byte + return +} + +// Encode a slice of bytes ([]byte). +func (o *Buffer) enc_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if s == nil { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 { + return ErrNil + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(s) + return nil +} + +func size_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if s == nil && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +func size_proto3_slice_byte(p *Properties, base structPointer) (n int) { + s := *structPointer_Bytes(base, p.field) + if len(s) == 0 && !p.oneof { + return 0 + } + n += len(p.tagcode) + n += sizeRawBytes(s) + return +} + +// Encode a slice of int32s ([]int32). +func (o *Buffer) enc_slice_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of int32s ([]int32) in packed format. +func (o *Buffer) enc_slice_packed_int32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + p.valEnc(buf, uint64(x)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + x := int32(s.Index(i)) // permit sign extension to use full 64-bit range + bufSize += p.valSize(uint64(x)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of uint32s ([]uint32). +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + x := s.Index(i) + p.valEnc(o, uint64(x)) + } + return nil +} + +func size_slice_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + x := s.Index(i) + n += p.valSize(uint64(x)) + } + return +} + +// Encode a slice of uint32s ([]uint32) in packed format. +// Exactly the same as int32, except for no sign extension. +func (o *Buffer) enc_slice_packed_uint32(p *Properties, base structPointer) error { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, uint64(s.Index(i))) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_uint32(p *Properties, base structPointer) (n int) { + s := structPointer_Word32Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(uint64(s.Index(i))) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of int64s ([]int64). +func (o *Buffer) enc_slice_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + p.valEnc(o, s.Index(i)) + } + return nil +} + +func size_slice_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + for i := 0; i < l; i++ { + n += len(p.tagcode) + n += p.valSize(s.Index(i)) + } + return +} + +// Encode a slice of int64s ([]int64) in packed format. +func (o *Buffer) enc_slice_packed_int64(p *Properties, base structPointer) error { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return ErrNil + } + // TODO: Reuse a Buffer. + buf := NewBuffer(nil) + for i := 0; i < l; i++ { + p.valEnc(buf, s.Index(i)) + } + + o.buf = append(o.buf, p.tagcode...) + o.EncodeVarint(uint64(len(buf.buf))) + o.buf = append(o.buf, buf.buf...) + return nil +} + +func size_slice_packed_int64(p *Properties, base structPointer) (n int) { + s := structPointer_Word64Slice(base, p.field) + l := s.Len() + if l == 0 { + return 0 + } + var bufSize int + for i := 0; i < l; i++ { + bufSize += p.valSize(s.Index(i)) + } + + n += len(p.tagcode) + n += sizeVarint(uint64(bufSize)) + n += bufSize + return +} + +// Encode a slice of slice of bytes ([][]byte). +func (o *Buffer) enc_slice_slice_byte(p *Properties, base structPointer) error { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return ErrNil + } + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(ss[i]) + } + return nil +} + +func size_slice_slice_byte(p *Properties, base structPointer) (n int) { + ss := *structPointer_BytesSlice(base, p.field) + l := len(ss) + if l == 0 { + return 0 + } + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeRawBytes(ss[i]) + } + return +} + +// Encode a slice of strings ([]string). +func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + for i := 0; i < l; i++ { + o.buf = append(o.buf, p.tagcode...) + o.EncodeStringBytes(ss[i]) + } + return nil +} + +func size_slice_string(p *Properties, base structPointer) (n int) { + ss := *structPointer_StringSlice(base, p.field) + l := len(ss) + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + n += sizeStringBytes(ss[i]) + } + return +} + +// Encode a slice of message structs ([]*struct). +func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return errRepeatedHasNil + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, err := m.Marshal() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + o.buf = append(o.buf, p.tagcode...) + o.EncodeRawBytes(data) + continue + } + + o.buf = append(o.buf, p.tagcode...) + err := o.enc_len_struct(p.sprop, structp, &state) + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + } + return state.err +} + +func size_slice_struct_message(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + n += l * len(p.tagcode) + for i := 0; i < l; i++ { + structp := s.Index(i) + if structPointer_IsNil(structp) { + return // return the size up to this point + } + + // Can the object marshal itself? + if p.isMarshaler { + m := structPointer_Interface(structp, p.stype).(Marshaler) + data, _ := m.Marshal() + n += sizeRawBytes(data) + continue + } + + n0 := size_struct(p.sprop, structp) + n1 := sizeVarint(uint64(n0)) // size of encoded length + n += n0 + n1 + } + return +} + +// Encode a slice of group structs ([]*struct). +func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error { + var state errorState + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return errRepeatedHasNil + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup)) + + err := o.enc_struct(p.sprop, b) + + if err != nil && !state.shouldContinue(err, nil) { + if err == ErrNil { + return errRepeatedHasNil + } + return err + } + + o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup)) + } + return state.err +} + +func size_slice_struct_group(p *Properties, base structPointer) (n int) { + s := structPointer_StructPointerSlice(base, p.field) + l := s.Len() + + n += l * sizeVarint(uint64((p.Tag<<3)|WireStartGroup)) + n += l * sizeVarint(uint64((p.Tag<<3)|WireEndGroup)) + for i := 0; i < l; i++ { + b := s.Index(i) + if structPointer_IsNil(b) { + return // return size up to this point + } + + n += size_struct(p.sprop, b) + } + return +} + +// Encode an extension map. +func (o *Buffer) enc_map(p *Properties, base structPointer) error { + exts := structPointer_ExtMap(base, p.field) + if err := encodeExtensionsMap(*exts); err != nil { + return err + } + + return o.enc_map_body(*exts) +} + +func (o *Buffer) enc_exts(p *Properties, base structPointer) error { + exts := structPointer_Extensions(base, p.field) + + v, mu := exts.extensionsRead() + if v == nil { + return nil + } + + mu.Lock() + defer mu.Unlock() + if err := encodeExtensionsMap(v); err != nil { + return err + } + + return o.enc_map_body(v) +} + +func (o *Buffer) enc_map_body(v map[int32]Extension) error { + // Fast-path for common cases: zero or one extensions. + if len(v) <= 1 { + for _, e := range v { + o.buf = append(o.buf, e.enc...) + } + return nil + } + + // Sort keys to provide a deterministic encoding. + keys := make([]int, 0, len(v)) + for k := range v { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + o.buf = append(o.buf, v[int32(k)].enc...) + } + return nil +} + +func size_map(p *Properties, base structPointer) int { + v := structPointer_ExtMap(base, p.field) + return extensionsMapSize(*v) +} + +func size_exts(p *Properties, base structPointer) int { + v := structPointer_Extensions(base, p.field) + return extensionsSize(v) +} + +// Encode a map field. +func (o *Buffer) enc_new_map(p *Properties, base structPointer) error { + var state errorState // XXX: or do we need to plumb this through? + + /* + A map defined as + map<key_type, value_type> map_field = N; + is encoded in the same way as + message MapFieldEntry { + key_type key = 1; + value_type value = 2; + } + repeated MapFieldEntry map_field = N; + */ + + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V + if v.Len() == 0 { + return nil + } + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + enc := func() error { + if err := p.mkeyprop.enc(o, p.mkeyprop, keybase); err != nil { + return err + } + if err := p.mvalprop.enc(o, p.mvalprop, valbase); err != nil && err != ErrNil { + return err + } + return nil + } + + // Don't sort map keys. It is not required by the spec, and C++ doesn't do it. + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + + keycopy.Set(key) + valcopy.Set(val) + + o.buf = append(o.buf, p.tagcode...) + if err := o.enc_len_thing(enc, &state); err != nil { + return err + } + } + return nil +} + +func size_new_map(p *Properties, base structPointer) int { + v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V + + keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype) + + n := 0 + for _, key := range v.MapKeys() { + val := v.MapIndex(key) + keycopy.Set(key) + valcopy.Set(val) + + // Tag codes for key and val are the responsibility of the sub-sizer. + keysize := p.mkeyprop.size(p.mkeyprop, keybase) + valsize := p.mvalprop.size(p.mvalprop, valbase) + entry := keysize + valsize + // Add on tag code and length of map entry itself. + n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry + } + return n +} + +// mapEncodeScratch returns a new reflect.Value matching the map's value type, +// and a structPointer suitable for passing to an encoder or sizer. +func mapEncodeScratch(mapType reflect.Type) (keycopy, valcopy reflect.Value, keybase, valbase structPointer) { + // Prepare addressable doubly-indirect placeholders for the key and value types. + // This is needed because the element-type encoders expect **T, but the map iteration produces T. + + keycopy = reflect.New(mapType.Key()).Elem() // addressable K + keyptr := reflect.New(reflect.PtrTo(keycopy.Type())).Elem() // addressable *K + keyptr.Set(keycopy.Addr()) // + keybase = toStructPointer(keyptr.Addr()) // **K + + // Value types are more varied and require special handling. + switch mapType.Elem().Kind() { + case reflect.Slice: + // []byte + var dummy []byte + valcopy = reflect.ValueOf(&dummy).Elem() // addressable []byte + valbase = toStructPointer(valcopy.Addr()) + case reflect.Ptr: + // message; the generated field type is map[K]*Msg (so V is *Msg), + // so we only need one level of indirection. + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valbase = toStructPointer(valcopy.Addr()) + default: + // everything else + valcopy = reflect.New(mapType.Elem()).Elem() // addressable V + valptr := reflect.New(reflect.PtrTo(valcopy.Type())).Elem() // addressable *V + valptr.Set(valcopy.Addr()) // + valbase = toStructPointer(valptr.Addr()) // **V + } + return +} + +// Encode a struct. +func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error { + var state errorState + // Encode fields in tag order so that decoders may use optimizations + // that depend on the ordering. + // https://developers.google.com/protocol-buffers/docs/encoding#order + for _, i := range prop.order { + p := prop.Prop[i] + if p.enc != nil { + err := p.enc(o, p, base) + if err != nil { + if err == ErrNil { + if p.Required && state.err == nil { + state.err = &RequiredNotSetError{p.Name} + } + } else if err == errRepeatedHasNil { + // Give more context to nil values in repeated fields. + return errors.New("repeated field " + p.OrigName + " has nil element") + } else if !state.shouldContinue(err, p) { + return err + } + } + if len(o.buf) > maxMarshalSize { + return ErrTooLarge + } + } + } + + // Do oneof fields. + if prop.oneofMarshaler != nil { + m := structPointer_Interface(base, prop.stype).(Message) + if err := prop.oneofMarshaler(m, o); err == ErrNil { + return errOneofHasNil + } else if err != nil { + return err + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + if len(o.buf)+len(v) > maxMarshalSize { + return ErrTooLarge + } + if len(v) > 0 { + o.buf = append(o.buf, v...) + } + } + + return state.err +} + +func size_struct(prop *StructProperties, base structPointer) (n int) { + for _, i := range prop.order { + p := prop.Prop[i] + if p.size != nil { + n += p.size(p, base) + } + } + + // Add unrecognized fields at the end. + if prop.unrecField.IsValid() { + v := *structPointer_Bytes(base, prop.unrecField) + n += len(v) + } + + // Factor in any oneof fields. + if prop.oneofSizer != nil { + m := structPointer_Interface(base, prop.stype).(Message) + n += prop.oneofSizer(m) + } + + return +} + +var zeroes [20]byte // longer than any conceivable sizeVarint + +// Encode a struct, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_struct(prop *StructProperties, base structPointer, state *errorState) error { + return o.enc_len_thing(func() error { return o.enc_struct(prop, base) }, state) +} + +// Encode something, preceded by its encoded length (as a varint). +func (o *Buffer) enc_len_thing(enc func() error, state *errorState) error { + iLen := len(o.buf) + o.buf = append(o.buf, 0, 0, 0, 0) // reserve four bytes for length + iMsg := len(o.buf) + err := enc() + if err != nil && !state.shouldContinue(err, nil) { + return err + } + lMsg := len(o.buf) - iMsg + lLen := sizeVarint(uint64(lMsg)) + switch x := lLen - (iMsg - iLen); { + case x > 0: // actual length is x bytes larger than the space we reserved + // Move msg x bytes right. + o.buf = append(o.buf, zeroes[:x]...) + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + case x < 0: // actual length is x bytes smaller than the space we reserved + // Move msg x bytes left. + copy(o.buf[iMsg+x:], o.buf[iMsg:iMsg+lMsg]) + o.buf = o.buf[:len(o.buf)+x] // x is negative + } + // Encode the length in the reserved space. + o.buf = o.buf[:iLen] + o.EncodeVarint(uint64(lMsg)) + o.buf = o.buf[:len(o.buf)+lMsg] + return state.err +} + +// errorState maintains the first error that occurs and updates that error +// with additional context. +type errorState struct { + err error +} + +// shouldContinue reports whether encoding should continue upon encountering the +// given error. If the error is RequiredNotSetError, shouldContinue returns true +// and, if this is the first appearance of that error, remembers it for future +// reporting. +// +// If prop is not nil, it may update any error with additional context about the +// field with the error. +func (s *errorState) shouldContinue(err error, prop *Properties) bool { + // Ignore unset required fields. + reqNotSet, ok := err.(*RequiredNotSetError) + if !ok { + return false + } + if s.err == nil { + if prop != nil { + err = &RequiredNotSetError{prop.Name + "." + reqNotSet.field} + } + s.err = err + } + return true +} diff --git a/vendor/github.com/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go new file mode 100644 index 000000000..2ed1cf596 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/equal.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer comparison. + +package proto + +import ( + "bytes" + "log" + "reflect" + "strings" +) + +/* +Equal returns true iff protocol buffers a and b are equal. +The arguments must both be pointers to protocol buffer structs. + +Equality is defined in this way: + - Two messages are equal iff they are the same type, + corresponding fields are equal, unknown field sets + are equal, and extensions sets are equal. + - Two set scalar fields are equal iff their values are equal. + If the fields are of a floating-point type, remember that + NaN != x for all x, including NaN. If the message is defined + in a proto3 .proto file, fields are not "set"; specifically, + zero length proto3 "bytes" fields are equal (nil == {}). + - Two repeated fields are equal iff their lengths are the same, + and their corresponding elements are equal. Note a "bytes" field, + although represented by []byte, is not a repeated field and the + rule for the scalar fields described above applies. + - Two unset fields are equal. + - Two unknown field sets are equal if their current + encoded state is equal. + - Two extension sets are equal iff they have corresponding + elements that are pairwise equal. + - Two map fields are equal iff their lengths are the same, + and they contain the same set of elements. Zero-length map + fields are equal. + - Every other combination of things are not equal. + +The return value is undefined if a and b are not protocol buffers. +*/ +func Equal(a, b Message) bool { + if a == nil || b == nil { + return a == b + } + v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) + if v1.Type() != v2.Type() { + return false + } + if v1.Kind() == reflect.Ptr { + if v1.IsNil() { + return v2.IsNil() + } + if v2.IsNil() { + return false + } + v1, v2 = v1.Elem(), v2.Elem() + } + if v1.Kind() != reflect.Struct { + return false + } + return equalStruct(v1, v2) +} + +// v1 and v2 are known to have the same type. +func equalStruct(v1, v2 reflect.Value) bool { + sprop := GetProperties(v1.Type()) + for i := 0; i < v1.NumField(); i++ { + f := v1.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + f1, f2 := v1.Field(i), v2.Field(i) + if f.Type.Kind() == reflect.Ptr { + if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { + // both unset + continue + } else if n1 != n2 { + // set/unset mismatch + return false + } + b1, ok := f1.Interface().(raw) + if ok { + b2 := f2.Interface().(raw) + // RawMessage + if !bytes.Equal(b1.Bytes(), b2.Bytes()) { + return false + } + continue + } + f1, f2 = f1.Elem(), f2.Elem() + } + if !equalAny(f1, f2, sprop.Prop[i]) { + return false + } + } + + if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_InternalExtensions") + if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { + return false + } + } + + if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_extensions") + if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + return false + } + } + + uf := v1.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return true + } + + u1 := uf.Bytes() + u2 := v2.FieldByName("XXX_unrecognized").Bytes() + if !bytes.Equal(u1, u2) { + return false + } + + return true +} + +// v1 and v2 are known to have the same type. +// prop may be nil. +func equalAny(v1, v2 reflect.Value, prop *Properties) bool { + if v1.Type() == protoMessageType { + m1, _ := v1.Interface().(Message) + m2, _ := v2.Interface().(Message) + return Equal(m1, m2) + } + switch v1.Kind() { + case reflect.Bool: + return v1.Bool() == v2.Bool() + case reflect.Float32, reflect.Float64: + return v1.Float() == v2.Float() + case reflect.Int32, reflect.Int64: + return v1.Int() == v2.Int() + case reflect.Interface: + // Probably a oneof field; compare the inner values. + n1, n2 := v1.IsNil(), v2.IsNil() + if n1 || n2 { + return n1 == n2 + } + e1, e2 := v1.Elem(), v2.Elem() + if e1.Type() != e2.Type() { + return false + } + return equalAny(e1, e2, nil) + case reflect.Map: + if v1.Len() != v2.Len() { + return false + } + for _, key := range v1.MapKeys() { + val2 := v2.MapIndex(key) + if !val2.IsValid() { + // This key was not found in the second map. + return false + } + if !equalAny(v1.MapIndex(key), val2, nil) { + return false + } + } + return true + case reflect.Ptr: + // Maps may have nil values in them, so check for nil. + if v1.IsNil() && v2.IsNil() { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return equalAny(v1.Elem(), v2.Elem(), prop) + case reflect.Slice: + if v1.Type().Elem().Kind() == reflect.Uint8 { + // short circuit: []byte + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value. + if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) + } + + if v1.Len() != v2.Len() { + return false + } + for i := 0; i < v1.Len(); i++ { + if !equalAny(v1.Index(i), v2.Index(i), prop) { + return false + } + } + return true + case reflect.String: + return v1.Interface().(string) == v2.Interface().(string) + case reflect.Struct: + return equalStruct(v1, v2) + case reflect.Uint32, reflect.Uint64: + return v1.Uint() == v2.Uint() + } + + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to compare %v", v1) + return false +} + +// base is the struct type that the extensions are based on. +// x1 and x2 are InternalExtensions. +func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { + em1, _ := x1.extensionsRead() + em2, _ := x2.extensionsRead() + return equalExtMap(base, em1, em2) +} + +func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { + if len(em1) != len(em2) { + return false + } + + for extNum, e1 := range em1 { + e2, ok := em2[extNum] + if !ok { + return false + } + + m1, m2 := e1.value, e2.value + + if m1 != nil && m2 != nil { + // Both are unencoded. + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + continue + } + + // At least one is encoded. To do a semantically correct comparison + // we need to unmarshal them first. + var desc *ExtensionDesc + if m := extensionMaps[base]; m != nil { + desc = m[extNum] + } + if desc == nil { + log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) + continue + } + var err error + if m1 == nil { + m1, err = decodeExtension(e1.enc, desc) + } + if m2 == nil && err == nil { + m2, err = decodeExtension(e2.enc, desc) + } + if err != nil { + // The encoded form is invalid. + log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) + return false + } + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + } + + return true +} diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go new file mode 100644 index 000000000..eaad21831 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/extensions.go @@ -0,0 +1,587 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Types and routines for supporting protocol buffer extensions. + */ + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "sync" +) + +// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. +var ErrMissingExtension = errors.New("proto: missing extension") + +// ExtensionRange represents a range of message extensions for a protocol buffer. +// Used in code generated by the protocol compiler. +type ExtensionRange struct { + Start, End int32 // both inclusive +} + +// extendableProto is an interface implemented by any protocol buffer generated by the current +// proto compiler that may be extended. +type extendableProto interface { + Message + ExtensionRangeArray() []ExtensionRange + extensionsWrite() map[int32]Extension + extensionsRead() (map[int32]Extension, sync.Locker) +} + +// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous +// version of the proto compiler that may be extended. +type extendableProtoV1 interface { + Message + ExtensionRangeArray() []ExtensionRange + ExtensionMap() map[int32]Extension +} + +// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. +type extensionAdapter struct { + extendableProtoV1 +} + +func (e extensionAdapter) extensionsWrite() map[int32]Extension { + return e.ExtensionMap() +} + +func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + return e.ExtensionMap(), notLocker{} +} + +// notLocker is a sync.Locker whose Lock and Unlock methods are nops. +type notLocker struct{} + +func (n notLocker) Lock() {} +func (n notLocker) Unlock() {} + +// extendable returns the extendableProto interface for the given generated proto message. +// If the proto message has the old extension format, it returns a wrapper that implements +// the extendableProto interface. +func extendable(p interface{}) (extendableProto, bool) { + if ep, ok := p.(extendableProto); ok { + return ep, ok + } + if ep, ok := p.(extendableProtoV1); ok { + return extensionAdapter{ep}, ok + } + return nil, false +} + +// XXX_InternalExtensions is an internal representation of proto extensions. +// +// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, +// thus gaining the unexported 'extensions' method, which can be called only from the proto package. +// +// The methods of XXX_InternalExtensions are not concurrency safe in general, +// but calls to logically read-only methods such as has and get may be executed concurrently. +type XXX_InternalExtensions struct { + // The struct must be indirect so that if a user inadvertently copies a + // generated message and its embedded XXX_InternalExtensions, they + // avoid the mayhem of a copied mutex. + // + // The mutex serializes all logically read-only operations to p.extensionMap. + // It is up to the client to ensure that write operations to p.extensionMap are + // mutually exclusive with other accesses. + p *struct { + mu sync.Mutex + extensionMap map[int32]Extension + } +} + +// extensionsWrite returns the extension map, creating it on first use. +func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { + if e.p == nil { + e.p = new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }) + e.p.extensionMap = make(map[int32]Extension) + } + return e.p.extensionMap +} + +// extensionsRead returns the extensions map for read-only use. It may be nil. +// The caller must hold the returned mutex's lock when accessing Elements within the map. +func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { + if e.p == nil { + return nil, nil + } + return e.p.extensionMap, &e.p.mu +} + +var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() +var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() + +// ExtensionDesc represents an extension specification. +// Used in generated code from the protocol compiler. +type ExtensionDesc struct { + ExtendedType Message // nil pointer to the type that is being extended + ExtensionType interface{} // nil pointer to the extension type + Field int32 // field number + Name string // fully-qualified name of extension, for text formatting + Tag string // protobuf tag style + Filename string // name of the file in which the extension is defined +} + +func (ed *ExtensionDesc) repeated() bool { + t := reflect.TypeOf(ed.ExtensionType) + return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 +} + +// Extension represents an extension in a message. +type Extension struct { + // When an extension is stored in a message using SetExtension + // only desc and value are set. When the message is marshaled + // enc will be set to the encoded form of the message. + // + // When a message is unmarshaled and contains extensions, each + // extension will have only enc set. When such an extension is + // accessed using GetExtension (or GetExtensions) desc and value + // will be set. + desc *ExtensionDesc + value interface{} + enc []byte +} + +// SetRawExtension is for testing only. +func SetRawExtension(base Message, id int32, b []byte) { + epb, ok := extendable(base) + if !ok { + return + } + extmap := epb.extensionsWrite() + extmap[id] = Extension{enc: b} +} + +// isExtensionField returns true iff the given field number is in an extension range. +func isExtensionField(pb extendableProto, field int32) bool { + for _, er := range pb.ExtensionRangeArray() { + if er.Start <= field && field <= er.End { + return true + } + } + return false +} + +// checkExtensionTypes checks that the given extension is valid for pb. +func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + var pbi interface{} = pb + // Check the extended type. + if ea, ok := pbi.(extensionAdapter); ok { + pbi = ea.extendableProtoV1 + } + if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { + return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) + } + // Check the range. + if !isExtensionField(pb, extension.Field) { + return errors.New("proto: bad extension number; not in declared ranges") + } + return nil +} + +// extPropKey is sufficient to uniquely identify an extension. +type extPropKey struct { + base reflect.Type + field int32 +} + +var extProp = struct { + sync.RWMutex + m map[extPropKey]*Properties +}{ + m: make(map[extPropKey]*Properties), +} + +func extensionProperties(ed *ExtensionDesc) *Properties { + key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} + + extProp.RLock() + if prop, ok := extProp.m[key]; ok { + extProp.RUnlock() + return prop + } + extProp.RUnlock() + + extProp.Lock() + defer extProp.Unlock() + // Check again. + if prop, ok := extProp.m[key]; ok { + return prop + } + + prop := new(Properties) + prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) + extProp.m[key] = prop + return prop +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensions(e *XXX_InternalExtensions) error { + m, mu := e.extensionsRead() + if m == nil { + return nil // fast path + } + mu.Lock() + defer mu.Unlock() + return encodeExtensionsMap(m) +} + +// encode encodes any unmarshaled (unencoded) extensions in e. +func encodeExtensionsMap(m map[int32]Extension) error { + for k, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + p := NewBuffer(nil) + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + if err := props.enc(p, props, toStructPointer(x)); err != nil { + return err + } + e.enc = p.buf + m[k] = e + } + return nil +} + +func extensionsSize(e *XXX_InternalExtensions) (n int) { + m, mu := e.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + defer mu.Unlock() + return extensionsMapSize(m) +} + +func extensionsMapSize(m map[int32]Extension) (n int) { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + et := reflect.TypeOf(e.desc.ExtensionType) + props := extensionProperties(e.desc) + + // If e.value has type T, the encoder expects a *struct{ X T }. + // Pass a *T with a zero field and hope it all works out. + x := reflect.New(et) + x.Elem().Set(reflect.ValueOf(e.value)) + n += props.size(props, toStructPointer(x)) + } + return +} + +// HasExtension returns whether the given extension is present in pb. +func HasExtension(pb Message, extension *ExtensionDesc) bool { + // TODO: Check types, field numbers, etc.? + epb, ok := extendable(pb) + if !ok { + return false + } + extmap, mu := epb.extensionsRead() + if extmap == nil { + return false + } + mu.Lock() + _, ok = extmap[extension.Field] + mu.Unlock() + return ok +} + +// ClearExtension removes the given extension from pb. +func ClearExtension(pb Message, extension *ExtensionDesc) { + epb, ok := extendable(pb) + if !ok { + return + } + // TODO: Check types, field numbers, etc.? + extmap := epb.extensionsWrite() + delete(extmap, extension.Field) +} + +// GetExtension parses and returns the given extension of pb. +// If the extension is not present and has no default value it returns ErrMissingExtension. +func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { + epb, ok := extendable(pb) + if !ok { + return nil, errors.New("proto: not an extendable proto") + } + + if err := checkExtensionTypes(epb, extension); err != nil { + return nil, err + } + + emap, mu := epb.extensionsRead() + if emap == nil { + return defaultExtensionValue(extension) + } + mu.Lock() + defer mu.Unlock() + e, ok := emap[extension.Field] + if !ok { + // defaultExtensionValue returns the default value or + // ErrMissingExtension if there is no default. + return defaultExtensionValue(extension) + } + + if e.value != nil { + // Already decoded. Check the descriptor, though. + if e.desc != extension { + // This shouldn't happen. If it does, it means that + // GetExtension was called twice with two different + // descriptors with the same field number. + return nil, errors.New("proto: descriptor conflict") + } + return e.value, nil + } + + v, err := decodeExtension(e.enc, extension) + if err != nil { + return nil, err + } + + // Remember the decoded version and drop the encoded version. + // That way it is safe to mutate what we return. + e.value = v + e.desc = extension + e.enc = nil + emap[extension.Field] = e + return e.value, nil +} + +// defaultExtensionValue returns the default value for extension. +// If no default for an extension is defined ErrMissingExtension is returned. +func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + t := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + + sf, _, err := fieldDefault(t, props) + if err != nil { + return nil, err + } + + if sf == nil || sf.value == nil { + // There is no default value. + return nil, ErrMissingExtension + } + + if t.Kind() != reflect.Ptr { + // We do not need to return a Ptr, we can directly return sf.value. + return sf.value, nil + } + + // We need to return an interface{} that is a pointer to sf.value. + value := reflect.New(t).Elem() + value.Set(reflect.New(value.Type().Elem())) + if sf.kind == reflect.Int32 { + // We may have an int32 or an enum, but the underlying data is int32. + // Since we can't set an int32 into a non int32 reflect.value directly + // set it as a int32. + value.Elem().SetInt(int64(sf.value.(int32))) + } else { + value.Elem().Set(reflect.ValueOf(sf.value)) + } + return value.Interface(), nil +} + +// decodeExtension decodes an extension encoded in b. +func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { + o := NewBuffer(b) + + t := reflect.TypeOf(extension.ExtensionType) + + props := extensionProperties(extension) + + // t is a pointer to a struct, pointer to basic type or a slice. + // Allocate a "field" to store the pointer/slice itself; the + // pointer/slice will be stored here. We pass + // the address of this field to props.dec. + // This passes a zero field and a *t and lets props.dec + // interpret it as a *struct{ x t }. + value := reflect.New(t).Elem() + + for { + // Discard wire type and field number varint. It isn't needed. + if _, err := o.DecodeVarint(); err != nil { + return nil, err + } + + if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { + return nil, err + } + + if o.index >= len(o.buf) { + break + } + } + return value.Interface(), nil +} + +// GetExtensions returns a slice of the extensions present in pb that are also listed in es. +// The returned slice has the same length as es; missing extensions will appear as nil elements. +func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { + epb, ok := extendable(pb) + if !ok { + return nil, errors.New("proto: not an extendable proto") + } + extensions = make([]interface{}, len(es)) + for i, e := range es { + extensions[i], err = GetExtension(epb, e) + if err == ErrMissingExtension { + err = nil + } + if err != nil { + return + } + } + return +} + +// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. +// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing +// just the Field field, which defines the extension's field number. +func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { + epb, ok := extendable(pb) + if !ok { + return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) + } + registeredExtensions := RegisteredExtensions(pb) + + emap, mu := epb.extensionsRead() + if emap == nil { + return nil, nil + } + mu.Lock() + defer mu.Unlock() + extensions := make([]*ExtensionDesc, 0, len(emap)) + for extid, e := range emap { + desc := e.desc + if desc == nil { + desc = registeredExtensions[extid] + if desc == nil { + desc = &ExtensionDesc{Field: extid} + } + } + + extensions = append(extensions, desc) + } + return extensions, nil +} + +// SetExtension sets the specified extension of pb to the specified value. +func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { + epb, ok := extendable(pb) + if !ok { + return errors.New("proto: not an extendable proto") + } + if err := checkExtensionTypes(epb, extension); err != nil { + return err + } + typ := reflect.TypeOf(extension.ExtensionType) + if typ != reflect.TypeOf(value) { + return errors.New("proto: bad extension value type") + } + // nil extension values need to be caught early, because the + // encoder can't distinguish an ErrNil due to a nil extension + // from an ErrNil due to a missing field. Extensions are + // always optional, so the encoder would just swallow the error + // and drop all the extensions from the encoded message. + if reflect.ValueOf(value).IsNil() { + return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) + } + + extmap := epb.extensionsWrite() + extmap[extension.Field] = Extension{desc: extension, value: value} + return nil +} + +// ClearAllExtensions clears all extensions from pb. +func ClearAllExtensions(pb Message) { + epb, ok := extendable(pb) + if !ok { + return + } + m := epb.extensionsWrite() + for k := range m { + delete(m, k) + } +} + +// A global registry of extensions. +// The generated code will register the generated descriptors by calling RegisterExtension. + +var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) + +// RegisterExtension is called from the generated code. +func RegisterExtension(desc *ExtensionDesc) { + st := reflect.TypeOf(desc.ExtendedType).Elem() + m := extensionMaps[st] + if m == nil { + m = make(map[int32]*ExtensionDesc) + extensionMaps[st] = m + } + if _, ok := m[desc.Field]; ok { + panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) + } + m[desc.Field] = desc +} + +// RegisteredExtensions returns a map of the registered extensions of a +// protocol buffer struct, indexed by the extension number. +// The argument pb should be a nil pointer to the struct type. +func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { + return extensionMaps[reflect.TypeOf(pb).Elem()] +} diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go new file mode 100644 index 000000000..1c225504a --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/lib.go @@ -0,0 +1,897 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* +Package proto converts data structures to and from the wire format of +protocol buffers. It works in concert with the Go source code generated +for .proto files by the protocol compiler. + +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. + +When the .proto file specifies `syntax="proto3"`, there are some differences: + + - Non-repeated fields of non-message type are values instead of pointers. + - Enum types do not get an Enum method. + +The simplest way to describe this is to see an example. +Given file test.proto, containing + + package example; + + enum FOO { X = 17; } + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + oneof union { + int32 number = 6; + string name = 7; + } + } + +The resulting file, test.pb.go, is: + + package example + + import proto "github.com/golang/protobuf/proto" + import math "math" + + type FOO int32 + const ( + FOO_X FOO = 17 + ) + var FOO_name = map[int32]string{ + 17: "X", + } + var FOO_value = map[string]int32{ + "X": 17, + } + + func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p + } + func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) + } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err + } + *x = FOO(value) + return nil + } + + type Test struct { + Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` + Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` + Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` + Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + // Types that are valid to be assigned to Union: + // *Test_Number + // *Test_Name + Union isTest_Union `protobuf_oneof:"union"` + XXX_unrecognized []byte `json:"-"` + } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} + + type isTest_Union interface { + isTest_Union() + } + + type Test_Number struct { + Number int32 `protobuf:"varint,6,opt,name=number"` + } + type Test_Name struct { + Name string `protobuf:"bytes,7,opt,name=name"` + } + + func (*Test_Number) isTest_Union() {} + func (*Test_Name) isTest_Union() {} + + func (m *Test) GetUnion() isTest_Union { + if m != nil { + return m.Union + } + return nil + } + const Default_Test_Type int32 = 77 + + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" + } + + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type + } + return Default_Test_Type + } + + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil + } + + type Test_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } + + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" + } + + func (m *Test) GetNumber() int32 { + if x, ok := m.GetUnion().(*Test_Number); ok { + return x.Number + } + return 0 + } + + func (m *Test) GetName() string { + if x, ok := m.GetUnion().(*Test_Name); ok { + return x.Name + } + return "" + } + + func init() { + proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + } + +To create and play with a Test object: + + package main + + import ( + "log" + + "github.com/golang/protobuf/proto" + pb "./example.pb" + ) + + func main() { + test := &pb.Test{ + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &pb.Test_OptionalGroup{ + RequiredField: proto.String("good bye"), + }, + Union: &pb.Test_Name{"fred"}, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &pb.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // Use a type switch to determine which oneof was set. + switch u := test.Union.(type) { + case *pb.Test_Number: // u.Number contains the number. + case *pb.Test_Name: // u.Name contains the string. + } + // etc. + } +*/ +package proto + +import ( + "encoding/json" + "fmt" + "log" + "reflect" + "sort" + "strconv" + "sync" +) + +// Message is implemented by generated protocol buffer messages. +type Message interface { + Reset() + String() string + ProtoMessage() +} + +// Stats records allocation details about the protocol buffer encoders +// and decoders. Useful for tuning the library itself. +type Stats struct { + Emalloc uint64 // mallocs in encode + Dmalloc uint64 // mallocs in decode + Encode uint64 // number of encodes + Decode uint64 // number of decodes + Chit uint64 // number of cache hits + Cmiss uint64 // number of cache misses + Size uint64 // number of sizes +} + +// Set to true to enable stats collection. +const collectStats = false + +var stats Stats + +// GetStats returns a copy of the global Stats structure. +func GetStats() Stats { return stats } + +// A Buffer is a buffer manager for marshaling and unmarshaling +// protocol buffers. It may be reused between invocations to +// reduce memory usage. It is not necessary to use a Buffer; +// the global functions Marshal and Unmarshal create a +// temporary Buffer and are fine for most applications. +type Buffer struct { + buf []byte // encode/decode byte stream + index int // read point + + // pools of basic types to amortize allocation. + bools []bool + uint32s []uint32 + uint64s []uint64 + + // extra pools, only used with pointer_reflect.go + int32s []int32 + int64s []int64 + float32s []float32 + float64s []float64 +} + +// NewBuffer allocates a new Buffer and initializes its internal data to +// the contents of the argument slice. +func NewBuffer(e []byte) *Buffer { + return &Buffer{buf: e} +} + +// Reset resets the Buffer, ready for marshaling a new protocol buffer. +func (p *Buffer) Reset() { + p.buf = p.buf[0:0] // for reading/writing + p.index = 0 // for reading +} + +// SetBuf replaces the internal buffer with the slice, +// ready for unmarshaling the contents of the slice. +func (p *Buffer) SetBuf(s []byte) { + p.buf = s + p.index = 0 +} + +// Bytes returns the contents of the Buffer. +func (p *Buffer) Bytes() []byte { return p.buf } + +/* + * Helper routines for simplifying the creation of optional fields of basic type. + */ + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + return &v +} + +// Int32 is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it. +func Int32(v int32) *int32 { + return &v +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it, but unlike Int32 +// its argument value is an int. +func Int(v int) *int32 { + p := new(int32) + *p = int32(v) + return p +} + +// Int64 is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64(v int64) *int64 { + return &v +} + +// Float32 is a helper routine that allocates a new float32 value +// to store v and returns a pointer to it. +func Float32(v float32) *float32 { + return &v +} + +// Float64 is a helper routine that allocates a new float64 value +// to store v and returns a pointer to it. +func Float64(v float64) *float64 { + return &v +} + +// Uint32 is a helper routine that allocates a new uint32 value +// to store v and returns a pointer to it. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint64 is a helper routine that allocates a new uint64 value +// to store v and returns a pointer to it. +func Uint64(v uint64) *uint64 { + return &v +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + return &v +} + +// EnumName is a helper function to simplify printing protocol buffer enums +// by name. Given an enum map and a value, it returns a useful string. +func EnumName(m map[int32]string, v int32) string { + s, ok := m[v] + if ok { + return s + } + return strconv.Itoa(int(v)) +} + +// UnmarshalJSONEnum is a helper function to simplify recovering enum int values +// from their JSON-encoded representation. Given a map from the enum's symbolic +// names to its int values, and a byte buffer containing the JSON-encoded +// value, it returns an int32 that can be cast to the enum type by the caller. +// +// The function can deal with both JSON representations, numeric and symbolic. +func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { + if data[0] == '"' { + // New style: enums are strings. + var repr string + if err := json.Unmarshal(data, &repr); err != nil { + return -1, err + } + val, ok := m[repr] + if !ok { + return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) + } + return val, nil + } + // Old style: enums are ints. + var val int32 + if err := json.Unmarshal(data, &val); err != nil { + return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) + } + return val, nil +} + +// DebugPrint dumps the encoded data in b in a debugging format with a header +// including the string s. Used in testing but made available for general debugging. +func (p *Buffer) DebugPrint(s string, b []byte) { + var u uint64 + + obuf := p.buf + index := p.index + p.buf = b + p.index = 0 + depth := 0 + + fmt.Printf("\n--- %s ---\n", s) + +out: + for { + for i := 0; i < depth; i++ { + fmt.Print(" ") + } + + index := p.index + if index == len(p.buf) { + break + } + + op, err := p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: fetching op err %v\n", index, err) + break out + } + tag := op >> 3 + wire := op & 7 + + switch wire { + default: + fmt.Printf("%3d: t=%3d unknown wire=%d\n", + index, tag, wire) + break out + + case WireBytes: + var r []byte + + r, err = p.DecodeRawBytes(false) + if err != nil { + break out + } + fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) + if len(r) <= 6 { + for i := 0; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } else { + for i := 0; i < 3; i++ { + fmt.Printf(" %.2x", r[i]) + } + fmt.Printf(" ..") + for i := len(r) - 3; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } + fmt.Printf("\n") + + case WireFixed32: + u, err = p.DecodeFixed32() + if err != nil { + fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) + + case WireFixed64: + u, err = p.DecodeFixed64() + if err != nil { + fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) + + case WireVarint: + u, err = p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) + + case WireStartGroup: + fmt.Printf("%3d: t=%3d start\n", index, tag) + depth++ + + case WireEndGroup: + depth-- + fmt.Printf("%3d: t=%3d end\n", index, tag) + } + } + + if depth != 0 { + fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) + } + fmt.Printf("\n") + + p.buf = obuf + p.index = index +} + +// SetDefaults sets unset protocol buffer fields to their default values. +// It only modifies fields that are both unset and have defined defaults. +// It recursively sets default values in any non-nil sub-messages. +func SetDefaults(pb Message) { + setDefaults(reflect.ValueOf(pb), true, false) +} + +// v is a pointer to a struct. +func setDefaults(v reflect.Value, recur, zeros bool) { + v = v.Elem() + + defaultMu.RLock() + dm, ok := defaults[v.Type()] + defaultMu.RUnlock() + if !ok { + dm = buildDefaultMessage(v.Type()) + defaultMu.Lock() + defaults[v.Type()] = dm + defaultMu.Unlock() + } + + for _, sf := range dm.scalars { + f := v.Field(sf.index) + if !f.IsNil() { + // field already set + continue + } + dv := sf.value + if dv == nil && !zeros { + // no explicit default, and don't want to set zeros + continue + } + fptr := f.Addr().Interface() // **T + // TODO: Consider batching the allocations we do here. + switch sf.kind { + case reflect.Bool: + b := new(bool) + if dv != nil { + *b = dv.(bool) + } + *(fptr.(**bool)) = b + case reflect.Float32: + f := new(float32) + if dv != nil { + *f = dv.(float32) + } + *(fptr.(**float32)) = f + case reflect.Float64: + f := new(float64) + if dv != nil { + *f = dv.(float64) + } + *(fptr.(**float64)) = f + case reflect.Int32: + // might be an enum + if ft := f.Type(); ft != int32PtrType { + // enum + f.Set(reflect.New(ft.Elem())) + if dv != nil { + f.Elem().SetInt(int64(dv.(int32))) + } + } else { + // int32 field + i := new(int32) + if dv != nil { + *i = dv.(int32) + } + *(fptr.(**int32)) = i + } + case reflect.Int64: + i := new(int64) + if dv != nil { + *i = dv.(int64) + } + *(fptr.(**int64)) = i + case reflect.String: + s := new(string) + if dv != nil { + *s = dv.(string) + } + *(fptr.(**string)) = s + case reflect.Uint8: + // exceptional case: []byte + var b []byte + if dv != nil { + db := dv.([]byte) + b = make([]byte, len(db)) + copy(b, db) + } else { + b = []byte{} + } + *(fptr.(*[]byte)) = b + case reflect.Uint32: + u := new(uint32) + if dv != nil { + *u = dv.(uint32) + } + *(fptr.(**uint32)) = u + case reflect.Uint64: + u := new(uint64) + if dv != nil { + *u = dv.(uint64) + } + *(fptr.(**uint64)) = u + default: + log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) + } + } + + for _, ni := range dm.nested { + f := v.Field(ni) + // f is *T or []*T or map[T]*T + switch f.Kind() { + case reflect.Ptr: + if f.IsNil() { + continue + } + setDefaults(f, recur, zeros) + + case reflect.Slice: + for i := 0; i < f.Len(); i++ { + e := f.Index(i) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + + case reflect.Map: + for _, k := range f.MapKeys() { + e := f.MapIndex(k) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + } + } +} + +var ( + // defaults maps a protocol buffer struct type to a slice of the fields, + // with its scalar fields set to their proto-declared non-zero default values. + defaultMu sync.RWMutex + defaults = make(map[reflect.Type]defaultMessage) + + int32PtrType = reflect.TypeOf((*int32)(nil)) +) + +// defaultMessage represents information about the default values of a message. +type defaultMessage struct { + scalars []scalarField + nested []int // struct field index of nested messages +} + +type scalarField struct { + index int // struct field index + kind reflect.Kind // element type (the T in *T or []T) + value interface{} // the proto-declared default value, or nil +} + +// t is a struct type. +func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { + sprop := GetProperties(t) + for _, prop := range sprop.Prop { + fi, ok := sprop.decoderTags.get(prop.Tag) + if !ok { + // XXX_unrecognized + continue + } + ft := t.Field(fi).Type + + sf, nested, err := fieldDefault(ft, prop) + switch { + case err != nil: + log.Print(err) + case nested: + dm.nested = append(dm.nested, fi) + case sf != nil: + sf.index = fi + dm.scalars = append(dm.scalars, *sf) + } + } + + return dm +} + +// fieldDefault returns the scalarField for field type ft. +// sf will be nil if the field can not have a default. +// nestedMessage will be true if this is a nested message. +// Note that sf.index is not set on return. +func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { + var canHaveDefault bool + switch ft.Kind() { + case reflect.Ptr: + if ft.Elem().Kind() == reflect.Struct { + nestedMessage = true + } else { + canHaveDefault = true // proto2 scalar field + } + + case reflect.Slice: + switch ft.Elem().Kind() { + case reflect.Ptr: + nestedMessage = true // repeated message + case reflect.Uint8: + canHaveDefault = true // bytes field + } + + case reflect.Map: + if ft.Elem().Kind() == reflect.Ptr { + nestedMessage = true // map with message values + } + } + + if !canHaveDefault { + if nestedMessage { + return nil, true, nil + } + return nil, false, nil + } + + // We now know that ft is a pointer or slice. + sf = &scalarField{kind: ft.Elem().Kind()} + + // scalar fields without defaults + if !prop.HasDefault { + return sf, false, nil + } + + // a scalar field: either *T or []byte + switch ft.Elem().Kind() { + case reflect.Bool: + x, err := strconv.ParseBool(prop.Default) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Float32: + x, err := strconv.ParseFloat(prop.Default, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) + } + sf.value = float32(x) + case reflect.Float64: + x, err := strconv.ParseFloat(prop.Default, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Int32: + x, err := strconv.ParseInt(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) + } + sf.value = int32(x) + case reflect.Int64: + x, err := strconv.ParseInt(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.String: + sf.value = prop.Default + case reflect.Uint8: + // []byte (not *uint8) + sf.value = []byte(prop.Default) + case reflect.Uint32: + x, err := strconv.ParseUint(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) + } + sf.value = uint32(x) + case reflect.Uint64: + x, err := strconv.ParseUint(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) + } + sf.value = x + default: + return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) + } + + return sf, false, nil +} + +// Map fields may have key types of non-float scalars, strings and enums. +// The easiest way to sort them in some deterministic order is to use fmt. +// If this turns out to be inefficient we can always consider other options, +// such as doing a Schwartzian transform. + +func mapKeys(vs []reflect.Value) sort.Interface { + s := mapKeySorter{ + vs: vs, + // default Less function: textual comparison + less: func(a, b reflect.Value) bool { + return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface()) + }, + } + + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; + // numeric keys are sorted numerically. + if len(vs) == 0 { + return s + } + switch vs[0].Kind() { + case reflect.Int32, reflect.Int64: + s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } + case reflect.Uint32, reflect.Uint64: + s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + } + + return s +} + +type mapKeySorter struct { + vs []reflect.Value + less func(a, b reflect.Value) bool +} + +func (s mapKeySorter) Len() int { return len(s.vs) } +func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } +func (s mapKeySorter) Less(i, j int) bool { + return s.less(s.vs[i], s.vs[j]) +} + +// isProto3Zero reports whether v is a zero proto3 value. +func isProto3Zero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint32, reflect.Uint64: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.String: + return v.String() == "" + } + return false +} + +// ProtoPackageIsVersion2 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const ProtoPackageIsVersion2 = true + +// ProtoPackageIsVersion1 is referenced from generated protocol buffer files +// to assert that that code is compatible with this version of the proto package. +const ProtoPackageIsVersion1 = true diff --git a/vendor/github.com/golang/protobuf/proto/message_set.go b/vendor/github.com/golang/protobuf/proto/message_set.go new file mode 100644 index 000000000..fd982decd --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/message_set.go @@ -0,0 +1,311 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Support for message sets. + */ + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" +) + +// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. +// A message type ID is required for storing a protocol buffer in a message set. +var errNoMessageTypeID = errors.New("proto does not have a message type ID") + +// The first two types (_MessageSet_Item and messageSet) +// model what the protocol compiler produces for the following protocol message: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } +// That is the MessageSet wire format. We can't use a proto to generate these +// because that would introduce a circular dependency between it and this package. + +type _MessageSet_Item struct { + TypeId *int32 `protobuf:"varint,2,req,name=type_id"` + Message []byte `protobuf:"bytes,3,req,name=message"` +} + +type messageSet struct { + Item []*_MessageSet_Item `protobuf:"group,1,rep"` + XXX_unrecognized []byte + // TODO: caching? +} + +// Make sure messageSet is a Message. +var _ Message = (*messageSet)(nil) + +// messageTypeIder is an interface satisfied by a protocol buffer type +// that may be stored in a MessageSet. +type messageTypeIder interface { + MessageTypeId() int32 +} + +func (ms *messageSet) find(pb Message) *_MessageSet_Item { + mti, ok := pb.(messageTypeIder) + if !ok { + return nil + } + id := mti.MessageTypeId() + for _, item := range ms.Item { + if *item.TypeId == id { + return item + } + } + return nil +} + +func (ms *messageSet) Has(pb Message) bool { + if ms.find(pb) != nil { + return true + } + return false +} + +func (ms *messageSet) Unmarshal(pb Message) error { + if item := ms.find(pb); item != nil { + return Unmarshal(item.Message, pb) + } + if _, ok := pb.(messageTypeIder); !ok { + return errNoMessageTypeID + } + return nil // TODO: return error instead? +} + +func (ms *messageSet) Marshal(pb Message) error { + msg, err := Marshal(pb) + if err != nil { + return err + } + if item := ms.find(pb); item != nil { + // reuse existing item + item.Message = msg + return nil + } + + mti, ok := pb.(messageTypeIder) + if !ok { + return errNoMessageTypeID + } + + mtid := mti.MessageTypeId() + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: &mtid, + Message: msg, + }) + return nil +} + +func (ms *messageSet) Reset() { *ms = messageSet{} } +func (ms *messageSet) String() string { return CompactTextString(ms) } +func (*messageSet) ProtoMessage() {} + +// Support for the message_set_wire_format message option. + +func skipVarint(buf []byte) []byte { + i := 0 + for ; buf[i]&0x80 != 0; i++ { + } + return buf[i+1:] +} + +// MarshalMessageSet encodes the extension map represented by m in the message set wire format. +// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSet(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + if err := encodeExtensions(exts); err != nil { + return nil, err + } + m, _ = exts.extensionsRead() + case map[int32]Extension: + if err := encodeExtensionsMap(exts); err != nil { + return nil, err + } + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + + // Sort extension IDs to provide a deterministic encoding. + // See also enc_map in encode.go. + ids := make([]int, 0, len(m)) + for id := range m { + ids = append(ids, int(id)) + } + sort.Ints(ids) + + ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))} + for _, id := range ids { + e := m[int32(id)] + // Remove the wire type and field number varint, as well as the length varint. + msg := skipVarint(skipVarint(e.enc)) + + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: Int32(int32(id)), + Message: msg, + }) + } + return Marshal(ms) +} + +// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSet(buf []byte, exts interface{}) error { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m = exts.extensionsWrite() + case map[int32]Extension: + m = exts + default: + return errors.New("proto: not an extension map") + } + + ms := new(messageSet) + if err := Unmarshal(buf, ms); err != nil { + return err + } + for _, item := range ms.Item { + id := *item.TypeId + msg := item.Message + + // Restore wire type and field number varint, plus length varint. + // Be careful to preserve duplicate items. + b := EncodeVarint(uint64(id)<<3 | WireBytes) + if ext, ok := m[id]; ok { + // Existing data; rip off the tag and length varint + // so we join the new data correctly. + // We can assume that ext.enc is set because we are unmarshaling. + o := ext.enc[len(b):] // skip wire type and field number + _, n := DecodeVarint(o) // calculate length of length varint + o = o[n:] // skip length varint + msg = append(o, msg...) // join old data and new data + } + b = append(b, EncodeVarint(uint64(len(msg)))...) + b = append(b, msg...) + + m[id] = Extension{enc: b} + } + return nil +} + +// MarshalMessageSetJSON encodes the extension map represented by m in JSON format. +// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m, _ = exts.extensionsRead() + case map[int32]Extension: + m = exts + default: + return nil, errors.New("proto: not an extension map") + } + var b bytes.Buffer + b.WriteByte('{') + + // Process the map in key order for deterministic output. + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) // int32Slice defined in text.go + + for i, id := range ids { + ext := m[id] + if i > 0 { + b.WriteByte(',') + } + + msd, ok := messageSetMap[id] + if !ok { + // Unknown type; we can't render it, so skip it. + continue + } + fmt.Fprintf(&b, `"[%s]":`, msd.name) + + x := ext.value + if x == nil { + x = reflect.New(msd.t.Elem()).Interface() + if err := Unmarshal(ext.enc, x.(Message)); err != nil { + return nil, err + } + } + d, err := json.Marshal(x) + if err != nil { + return nil, err + } + b.Write(d) + } + b.WriteByte('}') + return b.Bytes(), nil +} + +// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format. +// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option. +func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error { + // Common-case fast path. + if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) { + return nil + } + + // This is fairly tricky, and it's not clear that it is needed. + return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented") +} + +// A global registry of types that can be used in a MessageSet. + +var messageSetMap = make(map[int32]messageSetDesc) + +type messageSetDesc struct { + t reflect.Type // pointer to struct + name string +} + +// RegisterMessageSetType is called from the generated code. +func RegisterMessageSetType(m Message, fieldNum int32, name string) { + messageSetMap[fieldNum] = messageSetDesc{ + t: reflect.TypeOf(m), + name: name, + } +} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go new file mode 100644 index 000000000..fb512e2e1 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go @@ -0,0 +1,484 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build appengine js + +// This file contains an implementation of proto field accesses using package reflect. +// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can +// be used on App Engine. + +package proto + +import ( + "math" + "reflect" +) + +// A structPointer is a pointer to a struct. +type structPointer struct { + v reflect.Value +} + +// toStructPointer returns a structPointer equivalent to the given reflect value. +// The reflect value must itself be a pointer to a struct. +func toStructPointer(v reflect.Value) structPointer { + return structPointer{v} +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p.v.IsNil() +} + +// Interface returns the struct pointer as an interface value. +func structPointer_Interface(p structPointer, _ reflect.Type) interface{} { + return p.v.Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by the sequence of field indices +// passed to reflect's FieldByIndex. +type field []int + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return f.Index +} + +// invalidField is an invalid field identifier. +var invalidField = field(nil) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { return f != nil } + +// field returns the given field in the struct as a reflect value. +func structPointer_field(p structPointer, f field) reflect.Value { + // Special case: an extension map entry with a value of type T + // passes a *T to the struct-handling code with a zero field, + // expecting that it will be treated as equivalent to *struct{ X T }, + // which has the same memory layout. We have to handle that case + // specially, because reflect will panic if we call FieldByIndex on a + // non-struct. + if f == nil { + return p.v.Elem() + } + + return p.v.Elem().FieldByIndex(f) +} + +// ifield returns the given field in the struct as an interface value. +func structPointer_ifield(p structPointer, f field) interface{} { + return structPointer_field(p, f).Addr().Interface() +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return structPointer_ifield(p, f).(*[]byte) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return structPointer_ifield(p, f).(*[][]byte) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return structPointer_ifield(p, f).(**bool) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return structPointer_ifield(p, f).(*bool) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return structPointer_ifield(p, f).(*[]bool) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return structPointer_ifield(p, f).(**string) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return structPointer_ifield(p, f).(*string) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return structPointer_ifield(p, f).(*[]string) +} + +// Extensions returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return structPointer_ifield(p, f).(*XXX_InternalExtensions) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return structPointer_ifield(p, f).(*map[int32]Extension) +} + +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { + return structPointer_field(p, f).Addr() +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + structPointer_field(p, f).Set(q.v) +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return structPointer{structPointer_field(p, f)} +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice { + return structPointerSlice{structPointer_field(p, f)} +} + +// A structPointerSlice represents the address of a slice of pointers to structs +// (themselves messages or groups). That is, v.Type() is *[]*struct{...}. +type structPointerSlice struct { + v reflect.Value +} + +func (p structPointerSlice) Len() int { return p.v.Len() } +func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } +func (p structPointerSlice) Append(q structPointer) { + p.v.Set(reflect.Append(p.v, q.v)) +} + +var ( + int32Type = reflect.TypeOf(int32(0)) + uint32Type = reflect.TypeOf(uint32(0)) + float32Type = reflect.TypeOf(float32(0)) + int64Type = reflect.TypeOf(int64(0)) + uint64Type = reflect.TypeOf(uint64(0)) + float64Type = reflect.TypeOf(float64(0)) +) + +// A word32 represents a field of type *int32, *uint32, *float32, or *enum. +// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable. +type word32 struct { + v reflect.Value +} + +// IsNil reports whether p is nil. +func word32_IsNil(p word32) bool { + return p.v.IsNil() +} + +// Set sets p to point at a newly allocated word with bits set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + t := p.v.Type().Elem() + switch t { + case int32Type: + if len(o.int32s) == 0 { + o.int32s = make([]int32, uint32PoolSize) + } + o.int32s[0] = int32(x) + p.v.Set(reflect.ValueOf(&o.int32s[0])) + o.int32s = o.int32s[1:] + return + case uint32Type: + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + p.v.Set(reflect.ValueOf(&o.uint32s[0])) + o.uint32s = o.uint32s[1:] + return + case float32Type: + if len(o.float32s) == 0 { + o.float32s = make([]float32, uint32PoolSize) + } + o.float32s[0] = math.Float32frombits(x) + p.v.Set(reflect.ValueOf(&o.float32s[0])) + o.float32s = o.float32s[1:] + return + } + + // must be enum + p.v.Set(reflect.New(t)) + p.v.Elem().SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32_Get(p word32) uint32 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32{structPointer_field(p, f)} +} + +// A word32Val represents a field of type int32, uint32, float32, or enum. +// That is, v.Type() is int32, uint32, float32, or enum and v is assignable. +type word32Val struct { + v reflect.Value +} + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + switch p.v.Type() { + case int32Type: + p.v.SetInt(int64(x)) + return + case uint32Type: + p.v.SetUint(uint64(x)) + return + case float32Type: + p.v.SetFloat(float64(math.Float32frombits(x))) + return + } + + // must be enum + p.v.SetInt(int64(int32(x))) +} + +// Get gets the bits pointed at by p, as a uint32. +func word32Val_Get(p word32Val) uint32 { + elem := p.v + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val{structPointer_field(p, f)} +} + +// A word32Slice is a slice of 32-bit values. +// That is, v.Type() is []int32, []uint32, []float32, or []enum. +type word32Slice struct { + v reflect.Value +} + +func (p word32Slice) Append(x uint32) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int32: + elem.SetInt(int64(int32(x))) + case reflect.Uint32: + elem.SetUint(uint64(x)) + case reflect.Float32: + elem.SetFloat(float64(math.Float32frombits(x))) + } +} + +func (p word32Slice) Len() int { + return p.v.Len() +} + +func (p word32Slice) Index(i int) uint32 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int32: + return uint32(elem.Int()) + case reflect.Uint32: + return uint32(elem.Uint()) + case reflect.Float32: + return math.Float32bits(float32(elem.Float())) + } + panic("unreachable") +} + +// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) word32Slice { + return word32Slice{structPointer_field(p, f)} +} + +// word64 is like word32 but for 64-bit values. +type word64 struct { + v reflect.Value +} + +func word64_Set(p word64, o *Buffer, x uint64) { + t := p.v.Type().Elem() + switch t { + case int64Type: + if len(o.int64s) == 0 { + o.int64s = make([]int64, uint64PoolSize) + } + o.int64s[0] = int64(x) + p.v.Set(reflect.ValueOf(&o.int64s[0])) + o.int64s = o.int64s[1:] + return + case uint64Type: + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + p.v.Set(reflect.ValueOf(&o.uint64s[0])) + o.uint64s = o.uint64s[1:] + return + case float64Type: + if len(o.float64s) == 0 { + o.float64s = make([]float64, uint64PoolSize) + } + o.float64s[0] = math.Float64frombits(x) + p.v.Set(reflect.ValueOf(&o.float64s[0])) + o.float64s = o.float64s[1:] + return + } + panic("unreachable") +} + +func word64_IsNil(p word64) bool { + return p.v.IsNil() +} + +func word64_Get(p word64) uint64 { + elem := p.v.Elem() + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64{structPointer_field(p, f)} +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val struct { + v reflect.Value +} + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + switch p.v.Type() { + case int64Type: + p.v.SetInt(int64(x)) + return + case uint64Type: + p.v.SetUint(x) + return + case float64Type: + p.v.SetFloat(math.Float64frombits(x)) + return + } + panic("unreachable") +} + +func word64Val_Get(p word64Val) uint64 { + elem := p.v + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return elem.Uint() + case reflect.Float64: + return math.Float64bits(elem.Float()) + } + panic("unreachable") +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val{structPointer_field(p, f)} +} + +type word64Slice struct { + v reflect.Value +} + +func (p word64Slice) Append(x uint64) { + n, m := p.v.Len(), p.v.Cap() + if n < m { + p.v.SetLen(n + 1) + } else { + t := p.v.Type().Elem() + p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + } + elem := p.v.Index(n) + switch elem.Kind() { + case reflect.Int64: + elem.SetInt(int64(int64(x))) + case reflect.Uint64: + elem.SetUint(uint64(x)) + case reflect.Float64: + elem.SetFloat(float64(math.Float64frombits(x))) + } +} + +func (p word64Slice) Len() int { + return p.v.Len() +} + +func (p word64Slice) Index(i int) uint64 { + elem := p.v.Index(i) + switch elem.Kind() { + case reflect.Int64: + return uint64(elem.Int()) + case reflect.Uint64: + return uint64(elem.Uint()) + case reflect.Float64: + return math.Float64bits(float64(elem.Float())) + } + panic("unreachable") +} + +func structPointer_Word64Slice(p structPointer, f field) word64Slice { + return word64Slice{structPointer_field(p, f)} +} diff --git a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go new file mode 100644 index 000000000..6b5567d47 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -0,0 +1,270 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build !appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "unsafe" +) + +// NOTE: These type_Foo functions would more idiomatically be methods, +// but Go does not allow methods on pointer types, and we must preserve +// some pointer type for the garbage collector. We use these +// funcs with clunky names as our poor approximation to methods. +// +// An alternative would be +// type structPointer struct { p unsafe.Pointer } +// but that does not registerize as well. + +// A structPointer is a pointer to a struct. +type structPointer unsafe.Pointer + +// toStructPointer returns a structPointer equivalent to the given reflect value. +func toStructPointer(v reflect.Value) structPointer { + return structPointer(unsafe.Pointer(v.Pointer())) +} + +// IsNil reports whether p is nil. +func structPointer_IsNil(p structPointer) bool { + return p == nil +} + +// Interface returns the struct pointer, assumed to have element type t, +// as an interface value. +func structPointer_Interface(p structPointer, t reflect.Type) interface{} { + return reflect.NewAt(t, unsafe.Pointer(p)).Interface() +} + +// A field identifies a field in a struct, accessible from a structPointer. +// In this implementation, a field is identified by its byte offset from the start of the struct. +type field uintptr + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return field(f.Offset) +} + +// invalidField is an invalid field identifier. +const invalidField = ^field(0) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { + return f != ^field(0) +} + +// Bytes returns the address of a []byte field in the struct. +func structPointer_Bytes(p structPointer, f field) *[]byte { + return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BytesSlice returns the address of a [][]byte field in the struct. +func structPointer_BytesSlice(p structPointer, f field) *[][]byte { + return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// Bool returns the address of a *bool field in the struct. +func structPointer_Bool(p structPointer, f field) **bool { + return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolVal returns the address of a bool field in the struct. +func structPointer_BoolVal(p structPointer, f field) *bool { + return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// BoolSlice returns the address of a []bool field in the struct. +func structPointer_BoolSlice(p structPointer, f field) *[]bool { + return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// String returns the address of a *string field in the struct. +func structPointer_String(p structPointer, f field) **string { + return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringVal returns the address of a string field in the struct. +func structPointer_StringVal(p structPointer, f field) *string { + return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StringSlice returns the address of a []string field in the struct. +func structPointer_StringSlice(p structPointer, f field) *[]string { + return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// ExtMap returns the address of an extension map field in the struct. +func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension { + return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// NewAt returns the reflect.Value for a pointer to a field in the struct. +func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value { + return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f))) +} + +// SetStructPointer writes a *struct field in the struct. +func structPointer_SetStructPointer(p structPointer, f field, q structPointer) { + *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q +} + +// GetStructPointer reads a *struct field in the struct. +func structPointer_GetStructPointer(p structPointer, f field) structPointer { + return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// StructPointerSlice the address of a []*struct field in the struct. +func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice { + return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups). +type structPointerSlice []structPointer + +func (v *structPointerSlice) Len() int { return len(*v) } +func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] } +func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) } + +// A word32 is the address of a "pointer to 32-bit value" field. +type word32 **uint32 + +// IsNil reports whether *v is nil. +func word32_IsNil(p word32) bool { + return *p == nil +} + +// Set sets *v to point at a newly allocated word set to x. +func word32_Set(p word32, o *Buffer, x uint32) { + if len(o.uint32s) == 0 { + o.uint32s = make([]uint32, uint32PoolSize) + } + o.uint32s[0] = x + *p = &o.uint32s[0] + o.uint32s = o.uint32s[1:] +} + +// Get gets the value pointed at by *v. +func word32_Get(p word32) uint32 { + return **p +} + +// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32(p structPointer, f field) word32 { + return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Val is the address of a 32-bit value field. +type word32Val *uint32 + +// Set sets *p to x. +func word32Val_Set(p word32Val, x uint32) { + *p = x +} + +// Get gets the value pointed at by p. +func word32Val_Get(p word32Val) uint32 { + return *p +} + +// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct. +func structPointer_Word32Val(p structPointer, f field) word32Val { + return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// A word32Slice is a slice of 32-bit values. +type word32Slice []uint32 + +func (v *word32Slice) Append(x uint32) { *v = append(*v, x) } +func (v *word32Slice) Len() int { return len(*v) } +func (v *word32Slice) Index(i int) uint32 { return (*v)[i] } + +// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct. +func structPointer_Word32Slice(p structPointer, f field) *word32Slice { + return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} + +// word64 is like word32 but for 64-bit values. +type word64 **uint64 + +func word64_Set(p word64, o *Buffer, x uint64) { + if len(o.uint64s) == 0 { + o.uint64s = make([]uint64, uint64PoolSize) + } + o.uint64s[0] = x + *p = &o.uint64s[0] + o.uint64s = o.uint64s[1:] +} + +func word64_IsNil(p word64) bool { + return *p == nil +} + +func word64_Get(p word64) uint64 { + return **p +} + +func structPointer_Word64(p structPointer, f field) word64 { + return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Val is like word32Val but for 64-bit values. +type word64Val *uint64 + +func word64Val_Set(p word64Val, o *Buffer, x uint64) { + *p = x +} + +func word64Val_Get(p word64Val) uint64 { + return *p +} + +func structPointer_Word64Val(p structPointer, f field) word64Val { + return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +} + +// word64Slice is like word32Slice but for 64-bit values. +type word64Slice []uint64 + +func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } +func (v *word64Slice) Len() int { return len(*v) } +func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } + +func structPointer_Word64Slice(p structPointer, f field) *word64Slice { + return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) +} diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go new file mode 100644 index 000000000..ec2289c00 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/properties.go @@ -0,0 +1,872 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "fmt" + "log" + "os" + "reflect" + "sort" + "strconv" + "strings" + "sync" +) + +const debug bool = false + +// Constants that identify the encoding of a value on the wire. +const ( + WireVarint = 0 + WireFixed64 = 1 + WireBytes = 2 + WireStartGroup = 3 + WireEndGroup = 4 + WireFixed32 = 5 +) + +const startSize = 10 // initial slice/string sizes + +// Encoders are defined in encode.go +// An encoder outputs the full representation of a field, including its +// tag and encoder type. +type encoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueEncoder encodes a single integer in a particular encoding. +type valueEncoder func(o *Buffer, x uint64) error + +// Sizers are defined in encode.go +// A sizer returns the encoded size of a field, including its tag and encoder +// type. +type sizer func(prop *Properties, base structPointer) int + +// A valueSizer returns the encoded size of a single integer in a particular +// encoding. +type valueSizer func(x uint64) int + +// Decoders are defined in decode.go +// A decoder creates a value from its wire representation. +// Unrecognized subelements are saved in unrec. +type decoder func(p *Buffer, prop *Properties, base structPointer) error + +// A valueDecoder decodes a single integer in a particular encoding. +type valueDecoder func(o *Buffer) (x uint64, err error) + +// A oneofMarshaler does the marshaling for all oneof fields in a message. +type oneofMarshaler func(Message, *Buffer) error + +// A oneofUnmarshaler does the unmarshaling for a oneof field in a message. +type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error) + +// A oneofSizer does the sizing for all oneof fields in a message. +type oneofSizer func(Message) int + +// tagMap is an optimization over map[int]int for typical protocol buffer +// use-cases. Encoded protocol buffers are often in tag order with small tag +// numbers. +type tagMap struct { + fastTags []int + slowTags map[int]int +} + +// tagMapFastLimit is the upper bound on the tag number that will be stored in +// the tagMap slice rather than its map. +const tagMapFastLimit = 1024 + +func (p *tagMap) get(t int) (int, bool) { + if t > 0 && t < tagMapFastLimit { + if t >= len(p.fastTags) { + return 0, false + } + fi := p.fastTags[t] + return fi, fi >= 0 + } + fi, ok := p.slowTags[t] + return fi, ok +} + +func (p *tagMap) put(t int, fi int) { + if t > 0 && t < tagMapFastLimit { + for len(p.fastTags) < t+1 { + p.fastTags = append(p.fastTags, -1) + } + p.fastTags[t] = fi + return + } + if p.slowTags == nil { + p.slowTags = make(map[int]int) + } + p.slowTags[t] = fi +} + +// StructProperties represents properties for all the fields of a struct. +// decoderTags and decoderOrigNames should only be used by the decoder. +type StructProperties struct { + Prop []*Properties // properties for each field + reqCount int // required count + decoderTags tagMap // map from proto tag to struct field number + decoderOrigNames map[string]int // map from original name to struct field number + order []int // list of struct field numbers in tag order + unrecField field // field id of the XXX_unrecognized []byte field + extendable bool // is this an extendable proto + + oneofMarshaler oneofMarshaler + oneofUnmarshaler oneofUnmarshaler + oneofSizer oneofSizer + stype reflect.Type + + // OneofTypes contains information about the oneof fields in this message. + // It is keyed by the original name of a field. + OneofTypes map[string]*OneofProperties +} + +// OneofProperties represents information about a specific field in a oneof. +type OneofProperties struct { + Type reflect.Type // pointer to generated struct type for this oneof field + Field int // struct field number of the containing oneof in the message + Prop *Properties +} + +// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. +// See encode.go, (*Buffer).enc_struct. + +func (sp *StructProperties) Len() int { return len(sp.order) } +func (sp *StructProperties) Less(i, j int) bool { + return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag +} +func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } + +// Properties represents the protocol-specific behavior of a single struct field. +type Properties struct { + Name string // name of the field, for error messages + OrigName string // original name before protocol compiler (always set) + JSONName string // name to use for JSON; determined by protoc + Wire string + WireType int + Tag int + Required bool + Optional bool + Repeated bool + Packed bool // relevant for repeated primitives only + Enum string // set for enum types only + proto3 bool // whether this is known to be a proto3 field; set for []byte only + oneof bool // whether this is a oneof field + + Default string // default value + HasDefault bool // whether an explicit default was provided + def_uint64 uint64 + + enc encoder + valEnc valueEncoder // set for bool and numeric types only + field field + tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType) + tagbuf [8]byte + stype reflect.Type // set for struct types only + sprop *StructProperties // set for struct types only + isMarshaler bool + isUnmarshaler bool + + mtype reflect.Type // set for map types only + mkeyprop *Properties // set for map types only + mvalprop *Properties // set for map types only + + size sizer + valSize valueSizer // set for bool and numeric types only + + dec decoder + valDec valueDecoder // set for bool and numeric types only + + // If this is a packable field, this will be the decoder for the packed version of the field. + packedDec decoder +} + +// String formats the properties in the protobuf struct field tag style. +func (p *Properties) String() string { + s := p.Wire + s = "," + s += strconv.Itoa(p.Tag) + if p.Required { + s += ",req" + } + if p.Optional { + s += ",opt" + } + if p.Repeated { + s += ",rep" + } + if p.Packed { + s += ",packed" + } + s += ",name=" + p.OrigName + if p.JSONName != p.OrigName { + s += ",json=" + p.JSONName + } + if p.proto3 { + s += ",proto3" + } + if p.oneof { + s += ",oneof" + } + if len(p.Enum) > 0 { + s += ",enum=" + p.Enum + } + if p.HasDefault { + s += ",def=" + p.Default + } + return s +} + +// Parse populates p by parsing a string in the protobuf struct field tag style. +func (p *Properties) Parse(s string) { + // "bytes,49,opt,name=foo,def=hello!" + fields := strings.Split(s, ",") // breaks def=, but handled below. + if len(fields) < 2 { + fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) + return + } + + p.Wire = fields[0] + switch p.Wire { + case "varint": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeVarint + p.valDec = (*Buffer).DecodeVarint + p.valSize = sizeVarint + case "fixed32": + p.WireType = WireFixed32 + p.valEnc = (*Buffer).EncodeFixed32 + p.valDec = (*Buffer).DecodeFixed32 + p.valSize = sizeFixed32 + case "fixed64": + p.WireType = WireFixed64 + p.valEnc = (*Buffer).EncodeFixed64 + p.valDec = (*Buffer).DecodeFixed64 + p.valSize = sizeFixed64 + case "zigzag32": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag32 + p.valDec = (*Buffer).DecodeZigzag32 + p.valSize = sizeZigzag32 + case "zigzag64": + p.WireType = WireVarint + p.valEnc = (*Buffer).EncodeZigzag64 + p.valDec = (*Buffer).DecodeZigzag64 + p.valSize = sizeZigzag64 + case "bytes", "group": + p.WireType = WireBytes + // no numeric converter for non-numeric types + default: + fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) + return + } + + var err error + p.Tag, err = strconv.Atoi(fields[1]) + if err != nil { + return + } + + for i := 2; i < len(fields); i++ { + f := fields[i] + switch { + case f == "req": + p.Required = true + case f == "opt": + p.Optional = true + case f == "rep": + p.Repeated = true + case f == "packed": + p.Packed = true + case strings.HasPrefix(f, "name="): + p.OrigName = f[5:] + case strings.HasPrefix(f, "json="): + p.JSONName = f[5:] + case strings.HasPrefix(f, "enum="): + p.Enum = f[5:] + case f == "proto3": + p.proto3 = true + case f == "oneof": + p.oneof = true + case strings.HasPrefix(f, "def="): + p.HasDefault = true + p.Default = f[4:] // rest of string + if i+1 < len(fields) { + // Commas aren't escaped, and def is always last. + p.Default += "," + strings.Join(fields[i+1:], ",") + break + } + } + } +} + +func logNoSliceEnc(t1, t2 reflect.Type) { + fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2) +} + +var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() + +// Initialize the fields for encoding and decoding. +func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { + p.enc = nil + p.dec = nil + p.size = nil + + switch t1 := typ; t1.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) + + // proto3 scalar types + + case reflect.Bool: + p.enc = (*Buffer).enc_proto3_bool + p.dec = (*Buffer).dec_proto3_bool + p.size = size_proto3_bool + case reflect.Int32: + p.enc = (*Buffer).enc_proto3_int32 + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_int32 + case reflect.Uint32: + p.enc = (*Buffer).enc_proto3_uint32 + p.dec = (*Buffer).dec_proto3_int32 // can reuse + p.size = size_proto3_uint32 + case reflect.Int64, reflect.Uint64: + p.enc = (*Buffer).enc_proto3_int64 + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + case reflect.Float32: + p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int32 + p.size = size_proto3_uint32 + case reflect.Float64: + p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits + p.dec = (*Buffer).dec_proto3_int64 + p.size = size_proto3_int64 + case reflect.String: + p.enc = (*Buffer).enc_proto3_string + p.dec = (*Buffer).dec_proto3_string + p.size = size_proto3_string + + case reflect.Ptr: + switch t2 := t1.Elem(); t2.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2) + break + case reflect.Bool: + p.enc = (*Buffer).enc_bool + p.dec = (*Buffer).dec_bool + p.size = size_bool + case reflect.Int32: + p.enc = (*Buffer).enc_int32 + p.dec = (*Buffer).dec_int32 + p.size = size_int32 + case reflect.Uint32: + p.enc = (*Buffer).enc_uint32 + p.dec = (*Buffer).dec_int32 // can reuse + p.size = size_uint32 + case reflect.Int64, reflect.Uint64: + p.enc = (*Buffer).enc_int64 + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.Float32: + p.enc = (*Buffer).enc_uint32 // can just treat them as bits + p.dec = (*Buffer).dec_int32 + p.size = size_uint32 + case reflect.Float64: + p.enc = (*Buffer).enc_int64 // can just treat them as bits + p.dec = (*Buffer).dec_int64 + p.size = size_int64 + case reflect.String: + p.enc = (*Buffer).enc_string + p.dec = (*Buffer).dec_string + p.size = size_string + case reflect.Struct: + p.stype = t1.Elem() + p.isMarshaler = isMarshaler(t1) + p.isUnmarshaler = isUnmarshaler(t1) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_struct_message + p.dec = (*Buffer).dec_struct_message + p.size = size_struct_message + } else { + p.enc = (*Buffer).enc_struct_group + p.dec = (*Buffer).dec_struct_group + p.size = size_struct_group + } + } + + case reflect.Slice: + switch t2 := t1.Elem(); t2.Kind() { + default: + logNoSliceEnc(t1, t2) + break + case reflect.Bool: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_bool + p.size = size_slice_packed_bool + } else { + p.enc = (*Buffer).enc_slice_bool + p.size = size_slice_bool + } + p.dec = (*Buffer).dec_slice_bool + p.packedDec = (*Buffer).dec_slice_packed_bool + case reflect.Int32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int32 + p.size = size_slice_packed_int32 + } else { + p.enc = (*Buffer).enc_slice_int32 + p.size = size_slice_int32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Uint32: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case reflect.Int64, reflect.Uint64: + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + case reflect.Uint8: + p.dec = (*Buffer).dec_slice_byte + if p.proto3 { + p.enc = (*Buffer).enc_proto3_slice_byte + p.size = size_proto3_slice_byte + } else { + p.enc = (*Buffer).enc_slice_byte + p.size = size_slice_byte + } + case reflect.Float32, reflect.Float64: + switch t2.Bits() { + case 32: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_uint32 + p.size = size_slice_packed_uint32 + } else { + p.enc = (*Buffer).enc_slice_uint32 + p.size = size_slice_uint32 + } + p.dec = (*Buffer).dec_slice_int32 + p.packedDec = (*Buffer).dec_slice_packed_int32 + case 64: + // can just treat them as bits + if p.Packed { + p.enc = (*Buffer).enc_slice_packed_int64 + p.size = size_slice_packed_int64 + } else { + p.enc = (*Buffer).enc_slice_int64 + p.size = size_slice_int64 + } + p.dec = (*Buffer).dec_slice_int64 + p.packedDec = (*Buffer).dec_slice_packed_int64 + default: + logNoSliceEnc(t1, t2) + break + } + case reflect.String: + p.enc = (*Buffer).enc_slice_string + p.dec = (*Buffer).dec_slice_string + p.size = size_slice_string + case reflect.Ptr: + switch t3 := t2.Elem(); t3.Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3) + break + case reflect.Struct: + p.stype = t2.Elem() + p.isMarshaler = isMarshaler(t2) + p.isUnmarshaler = isUnmarshaler(t2) + if p.Wire == "bytes" { + p.enc = (*Buffer).enc_slice_struct_message + p.dec = (*Buffer).dec_slice_struct_message + p.size = size_slice_struct_message + } else { + p.enc = (*Buffer).enc_slice_struct_group + p.dec = (*Buffer).dec_slice_struct_group + p.size = size_slice_struct_group + } + } + case reflect.Slice: + switch t2.Elem().Kind() { + default: + fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem()) + break + case reflect.Uint8: + p.enc = (*Buffer).enc_slice_slice_byte + p.dec = (*Buffer).dec_slice_slice_byte + p.size = size_slice_slice_byte + } + } + + case reflect.Map: + p.enc = (*Buffer).enc_new_map + p.dec = (*Buffer).dec_new_map + p.size = size_new_map + + p.mtype = t1 + p.mkeyprop = &Properties{} + p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.mvalprop = &Properties{} + vtype := p.mtype.Elem() + if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { + // The value type is not a message (*T) or bytes ([]byte), + // so we need encoders for the pointer to this type. + vtype = reflect.PtrTo(vtype) + } + p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + } + + // precalculate tag code + wire := p.WireType + if p.Packed { + wire = WireBytes + } + x := uint32(p.Tag)<<3 | uint32(wire) + i := 0 + for i = 0; x > 127; i++ { + p.tagbuf[i] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + p.tagbuf[i] = uint8(x) + p.tagcode = p.tagbuf[0 : i+1] + + if p.stype != nil { + if lockGetProp { + p.sprop = GetProperties(p.stype) + } else { + p.sprop = getPropertiesLocked(p.stype) + } + } +} + +var ( + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() +) + +// isMarshaler reports whether type t implements Marshaler. +func isMarshaler(t reflect.Type) bool { + // We're checking for (likely) pointer-receiver methods + // so if t is not a pointer, something is very wrong. + // The calls above only invoke isMarshaler on pointer types. + if t.Kind() != reflect.Ptr { + panic("proto: misuse of isMarshaler") + } + return t.Implements(marshalerType) +} + +// isUnmarshaler reports whether type t implements Unmarshaler. +func isUnmarshaler(t reflect.Type) bool { + // We're checking for (likely) pointer-receiver methods + // so if t is not a pointer, something is very wrong. + // The calls above only invoke isUnmarshaler on pointer types. + if t.Kind() != reflect.Ptr { + panic("proto: misuse of isUnmarshaler") + } + return t.Implements(unmarshalerType) +} + +// Init populates the properties from a protocol buffer struct tag. +func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { + p.init(typ, name, tag, f, true) +} + +func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { + // "bytes,49,opt,def=hello!" + p.Name = name + p.OrigName = name + if f != nil { + p.field = toField(f) + } + if tag == "" { + return + } + p.Parse(tag) + p.setEncAndDec(typ, f, lockGetProp) +} + +var ( + propertiesMu sync.RWMutex + propertiesMap = make(map[reflect.Type]*StructProperties) +) + +// GetProperties returns the list of properties for the type represented by t. +// t must represent a generated struct type of a protocol message. +func GetProperties(t reflect.Type) *StructProperties { + if t.Kind() != reflect.Struct { + panic("proto: type must have kind struct") + } + + // Most calls to GetProperties in a long-running program will be + // retrieving details for types we have seen before. + propertiesMu.RLock() + sprop, ok := propertiesMap[t] + propertiesMu.RUnlock() + if ok { + if collectStats { + stats.Chit++ + } + return sprop + } + + propertiesMu.Lock() + sprop = getPropertiesLocked(t) + propertiesMu.Unlock() + return sprop +} + +// getPropertiesLocked requires that propertiesMu is held. +func getPropertiesLocked(t reflect.Type) *StructProperties { + if prop, ok := propertiesMap[t]; ok { + if collectStats { + stats.Chit++ + } + return prop + } + if collectStats { + stats.Cmiss++ + } + + prop := new(StructProperties) + // in case of recursive protos, fill this in now. + propertiesMap[t] = prop + + // build properties + prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || + reflect.PtrTo(t).Implements(extendableProtoV1Type) + prop.unrecField = invalidField + prop.Prop = make([]*Properties, t.NumField()) + prop.order = make([]int, t.NumField()) + + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + p := new(Properties) + name := f.Name + p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) + + if f.Name == "XXX_InternalExtensions" { // special case + p.enc = (*Buffer).enc_exts + p.dec = nil // not needed + p.size = size_exts + } else if f.Name == "XXX_extensions" { // special case + p.enc = (*Buffer).enc_map + p.dec = nil // not needed + p.size = size_map + } else if f.Name == "XXX_unrecognized" { // special case + prop.unrecField = toField(&f) + } + oneof := f.Tag.Get("protobuf_oneof") // special case + if oneof != "" { + // Oneof fields don't use the traditional protobuf tag. + p.OrigName = oneof + } + prop.Prop[i] = p + prop.order[i] = i + if debug { + print(i, " ", f.Name, " ", t.String(), " ") + if p.Tag > 0 { + print(p.String()) + } + print("\n") + } + if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" { + fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]") + } + } + + // Re-order prop.order. + sort.Sort(prop) + + type oneofMessage interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { + var oots []interface{} + prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() + prop.stype = t + + // Interpret oneof metadata. + prop.OneofTypes = make(map[string]*OneofProperties) + for _, oot := range oots { + oop := &OneofProperties{ + Type: reflect.ValueOf(oot).Type(), // *T + Prop: new(Properties), + } + sft := oop.Type.Elem().Field(0) + oop.Prop.Name = sft.Name + oop.Prop.Parse(sft.Tag.Get("protobuf")) + // There will be exactly one interface field that + // this new value is assignable to. + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Type.Kind() != reflect.Interface { + continue + } + if !oop.Type.AssignableTo(f.Type) { + continue + } + oop.Field = i + break + } + prop.OneofTypes[oop.Prop.OrigName] = oop + } + } + + // build required counts + // build tags + reqCount := 0 + prop.decoderOrigNames = make(map[string]int) + for i, p := range prop.Prop { + if strings.HasPrefix(p.Name, "XXX_") { + // Internal fields should not appear in tags/origNames maps. + // They are handled specially when encoding and decoding. + continue + } + if p.Required { + reqCount++ + } + prop.decoderTags.put(p.Tag, i) + prop.decoderOrigNames[p.OrigName] = i + } + prop.reqCount = reqCount + + return prop +} + +// Return the Properties object for the x[0]'th field of the structure. +func propByIndex(t reflect.Type, x []int) *Properties { + if len(x) != 1 { + fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t) + return nil + } + prop := GetProperties(t) + return prop.Prop[x[0]] +} + +// Get the address and type of a pointer to a struct from an interface. +func getbase(pb Message) (t reflect.Type, b structPointer, err error) { + if pb == nil { + err = ErrNil + return + } + // get the reflect type of the pointer to the struct. + t = reflect.TypeOf(pb) + // get the address of the struct. + value := reflect.ValueOf(pb) + b = toStructPointer(value) + return +} + +// A global registry of enum types. +// The generated code will register the generated maps by calling RegisterEnum. + +var enumValueMaps = make(map[string]map[string]int32) + +// RegisterEnum is called from the generated code to install the enum descriptor +// maps into the global table to aid parsing text format protocol buffers. +func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { + if _, ok := enumValueMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumValueMaps[typeName] = valueMap +} + +// EnumValueMap returns the mapping from names to integers of the +// enum type enumType, or a nil if not found. +func EnumValueMap(enumType string) map[string]int32 { + return enumValueMaps[enumType] +} + +// A registry of all linked message types. +// The string is a fully-qualified proto name ("pkg.Message"). +var ( + protoTypes = make(map[string]reflect.Type) + revProtoTypes = make(map[reflect.Type]string) +) + +// RegisterType is called from generated code and maps from the fully qualified +// proto name to the type (pointer to struct) of the protocol buffer. +func RegisterType(x Message, name string) { + if _, ok := protoTypes[name]; ok { + // TODO: Some day, make this a panic. + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoTypes[name] = t + revProtoTypes[t] = name +} + +// MessageName returns the fully-qualified proto name for the given message type. +func MessageName(x Message) string { + type xname interface { + XXX_MessageName() string + } + if m, ok := x.(xname); ok { + return m.XXX_MessageName() + } + return revProtoTypes[reflect.TypeOf(x)] +} + +// MessageType returns the message type (pointer to struct) for a named message. +func MessageType(name string) reflect.Type { return protoTypes[name] } + +// A registry of all linked proto files. +var ( + protoFiles = make(map[string][]byte) // file name => fileDescriptor +) + +// RegisterFile is called from generated code and maps from the +// full file name of a .proto file to its compressed FileDescriptorProto. +func RegisterFile(filename string, fileDescriptor []byte) { + protoFiles[filename] = fileDescriptor +} + +// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. +func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/golang/protobuf/proto/text.go b/vendor/github.com/golang/protobuf/proto/text.go new file mode 100644 index 000000000..965876bf0 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text.go @@ -0,0 +1,854 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for writing the text protocol buffer format. + +import ( + "bufio" + "bytes" + "encoding" + "errors" + "fmt" + "io" + "log" + "math" + "reflect" + "sort" + "strings" +) + +var ( + newline = []byte("\n") + spaces = []byte(" ") + gtNewline = []byte(">\n") + endBraceNewline = []byte("}\n") + backslashN = []byte{'\\', 'n'} + backslashR = []byte{'\\', 'r'} + backslashT = []byte{'\\', 't'} + backslashDQ = []byte{'\\', '"'} + backslashBS = []byte{'\\', '\\'} + posInf = []byte("inf") + negInf = []byte("-inf") + nan = []byte("nan") +) + +type writer interface { + io.Writer + WriteByte(byte) error +} + +// textWriter is an io.Writer that tracks its indentation level. +type textWriter struct { + ind int + complete bool // if the current position is a complete line + compact bool // whether to write out as a one-liner + w writer +} + +func (w *textWriter) WriteString(s string) (n int, err error) { + if !strings.Contains(s, "\n") { + if !w.compact && w.complete { + w.writeIndent() + } + w.complete = false + return io.WriteString(w.w, s) + } + // WriteString is typically called without newlines, so this + // codepath and its copy are rare. We copy to avoid + // duplicating all of Write's logic here. + return w.Write([]byte(s)) +} + +func (w *textWriter) Write(p []byte) (n int, err error) { + newlines := bytes.Count(p, newline) + if newlines == 0 { + if !w.compact && w.complete { + w.writeIndent() + } + n, err = w.w.Write(p) + w.complete = false + return n, err + } + + frags := bytes.SplitN(p, newline, newlines+1) + if w.compact { + for i, frag := range frags { + if i > 0 { + if err := w.w.WriteByte(' '); err != nil { + return n, err + } + n++ + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + } + return n, nil + } + + for i, frag := range frags { + if w.complete { + w.writeIndent() + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + if i+1 < len(frags) { + if err := w.w.WriteByte('\n'); err != nil { + return n, err + } + n++ + } + } + w.complete = len(frags[len(frags)-1]) == 0 + return n, nil +} + +func (w *textWriter) WriteByte(c byte) error { + if w.compact && c == '\n' { + c = ' ' + } + if !w.compact && w.complete { + w.writeIndent() + } + err := w.w.WriteByte(c) + w.complete = c == '\n' + return err +} + +func (w *textWriter) indent() { w.ind++ } + +func (w *textWriter) unindent() { + if w.ind == 0 { + log.Print("proto: textWriter unindented too far") + return + } + w.ind-- +} + +func writeName(w *textWriter, props *Properties) error { + if _, err := w.WriteString(props.OrigName); err != nil { + return err + } + if props.Wire != "group" { + return w.WriteByte(':') + } + return nil +} + +// raw is the interface satisfied by RawMessage. +type raw interface { + Bytes() []byte +} + +func requiresQuotes(u string) bool { + // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. + for _, ch := range u { + switch { + case ch == '.' || ch == '/' || ch == '_': + continue + case '0' <= ch && ch <= '9': + continue + case 'A' <= ch && ch <= 'Z': + continue + case 'a' <= ch && ch <= 'z': + continue + default: + return true + } + } + return false +} + +// isAny reports whether sv is a google.protobuf.Any message +func isAny(sv reflect.Value) bool { + type wkt interface { + XXX_WellKnownType() string + } + t, ok := sv.Addr().Interface().(wkt) + return ok && t.XXX_WellKnownType() == "Any" +} + +// writeProto3Any writes an expanded google.protobuf.Any message. +// +// It returns (false, nil) if sv value can't be unmarshaled (e.g. because +// required messages are not linked in). +// +// It returns (true, error) when sv was written in expanded format or an error +// was encountered. +func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { + turl := sv.FieldByName("TypeUrl") + val := sv.FieldByName("Value") + if !turl.IsValid() || !val.IsValid() { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + b, ok := val.Interface().([]byte) + if !ok { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + parts := strings.Split(turl.String(), "/") + mt := MessageType(parts[len(parts)-1]) + if mt == nil { + return false, nil + } + m := reflect.New(mt.Elem()) + if err := Unmarshal(b, m.Interface().(Message)); err != nil { + return false, nil + } + w.Write([]byte("[")) + u := turl.String() + if requiresQuotes(u) { + writeString(w, u) + } else { + w.Write([]byte(u)) + } + if w.compact { + w.Write([]byte("]:<")) + } else { + w.Write([]byte("]: <\n")) + w.ind++ + } + if err := tm.writeStruct(w, m.Elem()); err != nil { + return true, err + } + if w.compact { + w.Write([]byte("> ")) + } else { + w.ind-- + w.Write([]byte(">\n")) + } + return true, nil +} + +func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { + if tm.ExpandAny && isAny(sv) { + if canExpand, err := tm.writeProto3Any(w, sv); canExpand { + return err + } + } + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < sv.NumField(); i++ { + fv := sv.Field(i) + props := sprops.Prop[i] + name := st.Field(i).Name + + if strings.HasPrefix(name, "XXX_") { + // There are two XXX_ fields: + // XXX_unrecognized []byte + // XXX_extensions map[int32]proto.Extension + // The first is handled here; + // the second is handled at the bottom of this function. + if name == "XXX_unrecognized" && !fv.IsNil() { + if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Field not filled in. This could be an optional field or + // a required field that wasn't filled in. Either way, there + // isn't anything we can show for it. + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + // Repeated field that is empty, or a bytes field that is unused. + continue + } + + if props.Repeated && fv.Kind() == reflect.Slice { + // Repeated field. + for j := 0; j < fv.Len(); j++ { + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + v := fv.Index(j) + if v.Kind() == reflect.Ptr && v.IsNil() { + // A nil message in a repeated field is not valid, + // but we can handle that more gracefully than panicking. + if _, err := w.Write([]byte("<nil>\n")); err != nil { + return err + } + continue + } + if err := tm.writeAny(w, v, props); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Map { + // Map fields are rendered as a repeated struct with key/value fields. + keys := fv.MapKeys() + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := fv.MapIndex(key) + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + // open struct + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + // key + if _, err := w.WriteString("key:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, key, props.mkeyprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // nil values aren't legal, but we can avoid panicking because of them. + if val.Kind() != reflect.Ptr || !val.IsNil() { + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, val, props.mvalprop); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + // close struct + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { + // empty bytes field + continue + } + if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { + // proto3 non-repeated scalar field; skip if zero value + if isProto3Zero(fv) { + continue + } + } + + if fv.Kind() == reflect.Interface { + // Check if it is a oneof. + if st.Field(i).Tag.Get("protobuf_oneof") != "" { + // fv is nil, or holds a pointer to generated struct. + // That generated struct has exactly one field, + // which has a protobuf struct tag. + if fv.IsNil() { + continue + } + inner := fv.Elem().Elem() // interface -> *T -> T + tag := inner.Type().Field(0).Tag.Get("protobuf") + props = new(Properties) // Overwrite the outer props var, but not its pointee. + props.Parse(tag) + // Write the value in the oneof, not the oneof itself. + fv = inner.Field(0) + + // Special case to cope with malformed messages gracefully: + // If the value in the oneof is a nil pointer, don't panic + // in writeAny. + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Use errors.New so writeAny won't render quotes. + msg := errors.New("/* nil */") + fv = reflect.ValueOf(&msg).Elem() + } + } + } + + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if b, ok := fv.Interface().(raw); ok { + if err := writeRaw(w, b.Bytes()); err != nil { + return err + } + continue + } + + // Enums have a String method, so writeAny will work fine. + if err := tm.writeAny(w, fv, props); err != nil { + return err + } + + if err := w.WriteByte('\n'); err != nil { + return err + } + } + + // Extensions (the XXX_extensions field). + pv := sv.Addr() + if _, ok := extendable(pv.Interface()); ok { + if err := tm.writeExtensions(w, pv); err != nil { + return err + } + } + + return nil +} + +// writeRaw writes an uninterpreted raw message. +func writeRaw(w *textWriter, b []byte) error { + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if err := writeUnknownStruct(w, b); err != nil { + return err + } + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + return nil +} + +// writeAny writes an arbitrary field. +func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { + v = reflect.Indirect(v) + + // Floats have special cases. + if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { + x := v.Float() + var b []byte + switch { + case math.IsInf(x, 1): + b = posInf + case math.IsInf(x, -1): + b = negInf + case math.IsNaN(x): + b = nan + } + if b != nil { + _, err := w.Write(b) + return err + } + // Other values are handled below. + } + + // We don't attempt to serialise every possible value type; only those + // that can occur in protocol buffers. + switch v.Kind() { + case reflect.Slice: + // Should only be a []byte; repeated fields are handled in writeStruct. + if err := writeString(w, string(v.Bytes())); err != nil { + return err + } + case reflect.String: + if err := writeString(w, v.String()); err != nil { + return err + } + case reflect.Struct: + // Required/optional group/message. + var bra, ket byte = '<', '>' + if props != nil && props.Wire == "group" { + bra, ket = '{', '}' + } + if err := w.WriteByte(bra); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if etm, ok := v.Interface().(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = w.Write(text); err != nil { + return err + } + } else if err := tm.writeStruct(w, v); err != nil { + return err + } + w.unindent() + if err := w.WriteByte(ket); err != nil { + return err + } + default: + _, err := fmt.Fprint(w, v.Interface()) + return err + } + return nil +} + +// equivalent to C's isprint. +func isprint(c byte) bool { + return c >= 0x20 && c < 0x7f +} + +// writeString writes a string in the protocol buffer text format. +// It is similar to strconv.Quote except we don't use Go escape sequences, +// we treat the string as a byte sequence, and we use octal escapes. +// These differences are to maintain interoperability with the other +// languages' implementations of the text format. +func writeString(w *textWriter, s string) error { + // use WriteByte here to get any needed indent + if err := w.WriteByte('"'); err != nil { + return err + } + // Loop over the bytes, not the runes. + for i := 0; i < len(s); i++ { + var err error + // Divergence from C++: we don't escape apostrophes. + // There's no need to escape them, and the C++ parser + // copes with a naked apostrophe. + switch c := s[i]; c { + case '\n': + _, err = w.w.Write(backslashN) + case '\r': + _, err = w.w.Write(backslashR) + case '\t': + _, err = w.w.Write(backslashT) + case '"': + _, err = w.w.Write(backslashDQ) + case '\\': + _, err = w.w.Write(backslashBS) + default: + if isprint(c) { + err = w.w.WriteByte(c) + } else { + _, err = fmt.Fprintf(w.w, "\\%03o", c) + } + } + if err != nil { + return err + } + } + return w.WriteByte('"') +} + +func writeUnknownStruct(w *textWriter, data []byte) (err error) { + if !w.compact { + if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { + return err + } + } + b := NewBuffer(data) + for b.index < len(b.buf) { + x, err := b.DecodeVarint() + if err != nil { + _, err := fmt.Fprintf(w, "/* %v */\n", err) + return err + } + wire, tag := x&7, x>>3 + if wire == WireEndGroup { + w.unindent() + if _, err := w.Write(endBraceNewline); err != nil { + return err + } + continue + } + if _, err := fmt.Fprint(w, tag); err != nil { + return err + } + if wire != WireStartGroup { + if err := w.WriteByte(':'); err != nil { + return err + } + } + if !w.compact || wire == WireStartGroup { + if err := w.WriteByte(' '); err != nil { + return err + } + } + switch wire { + case WireBytes: + buf, e := b.DecodeRawBytes(false) + if e == nil { + _, err = fmt.Fprintf(w, "%q", buf) + } else { + _, err = fmt.Fprintf(w, "/* %v */", e) + } + case WireFixed32: + x, err = b.DecodeFixed32() + err = writeUnknownInt(w, x, err) + case WireFixed64: + x, err = b.DecodeFixed64() + err = writeUnknownInt(w, x, err) + case WireStartGroup: + err = w.WriteByte('{') + w.indent() + case WireVarint: + x, err = b.DecodeVarint() + err = writeUnknownInt(w, x, err) + default: + _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) + } + if err != nil { + return err + } + if err = w.WriteByte('\n'); err != nil { + return err + } + } + return nil +} + +func writeUnknownInt(w *textWriter, x uint64, err error) error { + if err == nil { + _, err = fmt.Fprint(w, x) + } else { + _, err = fmt.Fprintf(w, "/* %v */", err) + } + return err +} + +type int32Slice []int32 + +func (s int32Slice) Len() int { return len(s) } +func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } +func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// writeExtensions writes all the extensions in pv. +// pv is assumed to be a pointer to a protocol message struct that is extendable. +func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { + emap := extensionMaps[pv.Type().Elem()] + ep, _ := extendable(pv.Interface()) + + // Order the extensions by ID. + // This isn't strictly necessary, but it will give us + // canonical output, which will also make testing easier. + m, mu := ep.extensionsRead() + if m == nil { + return nil + } + mu.Lock() + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) + mu.Unlock() + + for _, extNum := range ids { + ext := m[extNum] + var desc *ExtensionDesc + if emap != nil { + desc = emap[extNum] + } + if desc == nil { + // Unknown extension. + if err := writeUnknownStruct(w, ext.enc); err != nil { + return err + } + continue + } + + pb, err := GetExtension(ep, desc) + if err != nil { + return fmt.Errorf("failed getting extension: %v", err) + } + + // Repeated extensions will appear as a slice. + if !desc.repeated() { + if err := tm.writeExtension(w, desc.Name, pb); err != nil { + return err + } + } else { + v := reflect.ValueOf(pb) + for i := 0; i < v.Len(); i++ { + if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { + return err + } + } + } + } + return nil +} + +func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { + if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + return nil +} + +func (w *textWriter) writeIndent() { + if !w.complete { + return + } + remain := w.ind * 2 + for remain > 0 { + n := remain + if n > len(spaces) { + n = len(spaces) + } + w.w.Write(spaces[:n]) + remain -= n + } + w.complete = false +} + +// TextMarshaler is a configurable text format marshaler. +type TextMarshaler struct { + Compact bool // use compact text format (one line). + ExpandAny bool // expand google.protobuf.Any messages of known types +} + +// Marshal writes a given protocol buffer in text format. +// The only errors returned are from w. +func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { + val := reflect.ValueOf(pb) + if pb == nil || val.IsNil() { + w.Write([]byte("<nil>")) + return nil + } + var bw *bufio.Writer + ww, ok := w.(writer) + if !ok { + bw = bufio.NewWriter(w) + ww = bw + } + aw := &textWriter{ + w: ww, + complete: true, + compact: tm.Compact, + } + + if etm, ok := pb.(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = aw.Write(text); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil + } + // Dereference the received pointer so we don't have outer < and >. + v := reflect.Indirect(val) + if err := tm.writeStruct(aw, v); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil +} + +// Text is the same as Marshal, but returns the string directly. +func (tm *TextMarshaler) Text(pb Message) string { + var buf bytes.Buffer + tm.Marshal(&buf, pb) + return buf.String() +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true} +) + +// TODO: consider removing some of the Marshal functions below. + +// MarshalText writes a given protocol buffer in text format. +// The only errors returned are from w. +func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } + +// MarshalTextString is the same as MarshalText, but returns the string directly. +func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } + +// CompactText writes a given protocol buffer in compact text format (one line). +func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } + +// CompactTextString is the same as CompactText, but returns the string directly. +func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go new file mode 100644 index 000000000..5e14513f2 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text_parser.go @@ -0,0 +1,895 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for parsing the Text protocol buffer format. +// TODO: message sets. + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "unicode/utf8" +) + +// Error string emitted when deserializing Any and fields are already set +const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" + +type ParseError struct { + Message string + Line int // 1-based line number + Offset int // 0-based byte offset from start of input +} + +func (p *ParseError) Error() string { + if p.Line == 1 { + // show offset only for first line + return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) + } + return fmt.Sprintf("line %d: %v", p.Line, p.Message) +} + +type token struct { + value string + err *ParseError + line int // line number + offset int // byte number from start of input, not start of line + unquoted string // the unquoted version of value, if it was a quoted string +} + +func (t *token) String() string { + if t.err == nil { + return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) + } + return fmt.Sprintf("parse error: %v", t.err) +} + +type textParser struct { + s string // remaining input + done bool // whether the parsing is finished (success or error) + backed bool // whether back() was called + offset, line int + cur token +} + +func newTextParser(s string) *textParser { + p := new(textParser) + p.s = s + p.line = 1 + p.cur.line = 1 + return p +} + +func (p *textParser) errorf(format string, a ...interface{}) *ParseError { + pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} + p.cur.err = pe + p.done = true + return pe +} + +// Numbers and identifiers are matched by [-+._A-Za-z0-9] +func isIdentOrNumberChar(c byte) bool { + switch { + case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': + return true + case '0' <= c && c <= '9': + return true + } + switch c { + case '-', '+', '.', '_': + return true + } + return false +} + +func isWhitespace(c byte) bool { + switch c { + case ' ', '\t', '\n', '\r': + return true + } + return false +} + +func isQuote(c byte) bool { + switch c { + case '"', '\'': + return true + } + return false +} + +func (p *textParser) skipWhitespace() { + i := 0 + for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { + if p.s[i] == '#' { + // comment; skip to end of line or input + for i < len(p.s) && p.s[i] != '\n' { + i++ + } + if i == len(p.s) { + break + } + } + if p.s[i] == '\n' { + p.line++ + } + i++ + } + p.offset += i + p.s = p.s[i:len(p.s)] + if len(p.s) == 0 { + p.done = true + } +} + +func (p *textParser) advance() { + // Skip whitespace + p.skipWhitespace() + if p.done { + return + } + + // Start of non-whitespace + p.cur.err = nil + p.cur.offset, p.cur.line = p.offset, p.line + p.cur.unquoted = "" + switch p.s[0] { + case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': + // Single symbol + p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] + case '"', '\'': + // Quoted string + i := 1 + for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { + if p.s[i] == '\\' && i+1 < len(p.s) { + // skip escaped char + i++ + } + i++ + } + if i >= len(p.s) || p.s[i] != p.s[0] { + p.errorf("unmatched quote") + return + } + unq, err := unquoteC(p.s[1:i], rune(p.s[0])) + if err != nil { + p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) + return + } + p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] + p.cur.unquoted = unq + default: + i := 0 + for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { + i++ + } + if i == 0 { + p.errorf("unexpected byte %#x", p.s[0]) + return + } + p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] + } + p.offset += len(p.cur.value) +} + +var ( + errBadUTF8 = errors.New("proto: bad UTF-8") + errBadHex = errors.New("proto: bad hexadecimal") +) + +func unquoteC(s string, quote rune) (string, error) { + // This is based on C++'s tokenizer.cc. + // Despite its name, this is *not* parsing C syntax. + // For instance, "\0" is an invalid quoted string. + + // Avoid allocation in trivial cases. + simple := true + for _, r := range s { + if r == '\\' || r == quote { + simple = false + break + } + } + if simple { + return s, nil + } + + buf := make([]byte, 0, 3*len(s)/2) + for len(s) > 0 { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", errBadUTF8 + } + s = s[n:] + if r != '\\' { + if r < utf8.RuneSelf { + buf = append(buf, byte(r)) + } else { + buf = append(buf, string(r)...) + } + continue + } + + ch, tail, err := unescape(s) + if err != nil { + return "", err + } + buf = append(buf, ch...) + s = tail + } + return string(buf), nil +} + +func unescape(s string) (ch string, tail string, err error) { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", "", errBadUTF8 + } + s = s[n:] + switch r { + case 'a': + return "\a", s, nil + case 'b': + return "\b", s, nil + case 'f': + return "\f", s, nil + case 'n': + return "\n", s, nil + case 'r': + return "\r", s, nil + case 't': + return "\t", s, nil + case 'v': + return "\v", s, nil + case '?': + return "?", s, nil // trigraph workaround + case '\'', '"', '\\': + return string(r), s, nil + case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': + if len(s) < 2 { + return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) + } + base := 8 + ss := s[:2] + s = s[2:] + if r == 'x' || r == 'X' { + base = 16 + } else { + ss = string(r) + ss + } + i, err := strconv.ParseUint(ss, base, 8) + if err != nil { + return "", "", err + } + return string([]byte{byte(i)}), s, nil + case 'u', 'U': + n := 4 + if r == 'U' { + n = 8 + } + if len(s) < n { + return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) + } + + bs := make([]byte, n/2) + for i := 0; i < n; i += 2 { + a, ok1 := unhex(s[i]) + b, ok2 := unhex(s[i+1]) + if !ok1 || !ok2 { + return "", "", errBadHex + } + bs[i/2] = a<<4 | b + } + s = s[n:] + return string(bs), s, nil + } + return "", "", fmt.Errorf(`unknown escape \%c`, r) +} + +// Adapted from src/pkg/strconv/quote.go. +func unhex(b byte) (v byte, ok bool) { + switch { + case '0' <= b && b <= '9': + return b - '0', true + case 'a' <= b && b <= 'f': + return b - 'a' + 10, true + case 'A' <= b && b <= 'F': + return b - 'A' + 10, true + } + return 0, false +} + +// Back off the parser by one token. Can only be done between calls to next(). +// It makes the next advance() a no-op. +func (p *textParser) back() { p.backed = true } + +// Advances the parser and returns the new current token. +func (p *textParser) next() *token { + if p.backed || p.done { + p.backed = false + return &p.cur + } + p.advance() + if p.done { + p.cur.value = "" + } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { + // Look for multiple quoted strings separated by whitespace, + // and concatenate them. + cat := p.cur + for { + p.skipWhitespace() + if p.done || !isQuote(p.s[0]) { + break + } + p.advance() + if p.cur.err != nil { + return &p.cur + } + cat.value += " " + p.cur.value + cat.unquoted += p.cur.unquoted + } + p.done = false // parser may have seen EOF, but we want to return cat + p.cur = cat + } + return &p.cur +} + +func (p *textParser) consumeToken(s string) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != s { + p.back() + return p.errorf("expected %q, found %q", s, tok.value) + } + return nil +} + +// Return a RequiredNotSetError indicating which required field was not set. +func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < st.NumField(); i++ { + if !isNil(sv.Field(i)) { + continue + } + + props := sprops.Prop[i] + if props.Required { + return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} + } + } + return &RequiredNotSetError{fmt.Sprintf("%v.<unknown field name>", st)} // should not happen +} + +// Returns the index in the struct for the named field, as well as the parsed tag properties. +func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { + i, ok := sprops.decoderOrigNames[name] + if ok { + return i, sprops.Prop[i], true + } + return -1, nil, false +} + +// Consume a ':' from the input stream (if the next token is a colon), +// returning an error if a colon is needed but not present. +func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ":" { + // Colon is optional when the field is a group or message. + needColon := true + switch props.Wire { + case "group": + needColon = false + case "bytes": + // A "bytes" field is either a message, a string, or a repeated field; + // those three become *T, *string and []T respectively, so we can check for + // this field being a pointer to a non-string. + if typ.Kind() == reflect.Ptr { + // *T or *string + if typ.Elem().Kind() == reflect.String { + break + } + } else if typ.Kind() == reflect.Slice { + // []T or []*T + if typ.Elem().Kind() != reflect.Ptr { + break + } + } else if typ.Kind() == reflect.String { + // The proto3 exception is for a string field, + // which requires a colon. + break + } + needColon = false + } + if needColon { + return p.errorf("expected ':', found %q", tok.value) + } + p.back() + } + return nil +} + +func (p *textParser) readStruct(sv reflect.Value, terminator string) error { + st := sv.Type() + sprops := GetProperties(st) + reqCount := sprops.reqCount + var reqFieldErr error + fieldSet := make(map[string]bool) + // A struct is a sequence of "name: value", terminated by one of + // '>' or '}', or the end of the input. A name may also be + // "[extension]" or "[type/url]". + // + // The whole struct can also be an expanded Any message, like: + // [type/url] < ... struct contents ... > + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + if tok.value == "[" { + // Looks like an extension or an Any. + // + // TODO: Check whether we need to handle + // namespace rooted names (e.g. ".something.Foo"). + extName, err := p.consumeExtName() + if err != nil { + return err + } + + if s := strings.LastIndex(extName, "/"); s >= 0 { + // If it contains a slash, it's an Any type URL. + messageName := extName[s+1:] + mt := MessageType(messageName) + if mt == nil { + return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) + } + tok = p.next() + if tok.err != nil { + return tok.err + } + // consume an optional colon + if tok.value == ":" { + tok = p.next() + if tok.err != nil { + return tok.err + } + } + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + v := reflect.New(mt.Elem()) + if pe := p.readStruct(v.Elem(), terminator); pe != nil { + return pe + } + b, err := Marshal(v.Interface().(Message)) + if err != nil { + return p.errorf("failed to marshal message of type %q: %v", messageName, err) + } + if fieldSet["type_url"] { + return p.errorf(anyRepeatedlyUnpacked, "type_url") + } + if fieldSet["value"] { + return p.errorf(anyRepeatedlyUnpacked, "value") + } + sv.FieldByName("TypeUrl").SetString(extName) + sv.FieldByName("Value").SetBytes(b) + fieldSet["type_url"] = true + fieldSet["value"] = true + continue + } + + var desc *ExtensionDesc + // This could be faster, but it's functional. + // TODO: Do something smarter than a linear scan. + for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { + if d.Name == extName { + desc = d + break + } + } + if desc == nil { + return p.errorf("unrecognized extension %q", extName) + } + + props := &Properties{} + props.Parse(desc.Tag) + + typ := reflect.TypeOf(desc.ExtensionType) + if err := p.checkForColon(props, typ); err != nil { + return err + } + + rep := desc.repeated() + + // Read the extension structure, and set it in + // the value we're constructing. + var ext reflect.Value + if !rep { + ext = reflect.New(typ).Elem() + } else { + ext = reflect.New(typ.Elem()).Elem() + } + if err := p.readAny(ext, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + ep := sv.Addr().Interface().(Message) + if !rep { + SetExtension(ep, desc, ext.Interface()) + } else { + old, err := GetExtension(ep, desc) + var sl reflect.Value + if err == nil { + sl = reflect.ValueOf(old) // existing slice + } else { + sl = reflect.MakeSlice(typ, 0, 1) + } + sl = reflect.Append(sl, ext) + SetExtension(ep, desc, sl.Interface()) + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + continue + } + + // This is a normal, non-extension field. + name := tok.value + var dst reflect.Value + fi, props, ok := structFieldByName(sprops, name) + if ok { + dst = sv.Field(fi) + } else if oop, ok := sprops.OneofTypes[name]; ok { + // It is a oneof. + props = oop.Prop + nv := reflect.New(oop.Type.Elem()) + dst = nv.Elem().Field(0) + field := sv.Field(oop.Field) + if !field.IsNil() { + return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) + } + field.Set(nv) + } + if !dst.IsValid() { + return p.errorf("unknown field name %q in %v", name, st) + } + + if dst.Kind() == reflect.Map { + // Consume any colon. + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Construct the map if it doesn't already exist. + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + key := reflect.New(dst.Type().Key()).Elem() + val := reflect.New(dst.Type().Elem()).Elem() + + // The map entry should be this sequence of tokens: + // < key : KEY value : VALUE > + // However, implementations may omit key or value, and technically + // we should support them in any order. See b/28924776 for a time + // this went wrong. + + tok := p.next() + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + switch tok.value { + case "key": + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.mkeyprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + case "value": + if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.mvalprop); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + default: + p.back() + return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) + } + } + + dst.SetMapIndex(key, val) + continue + } + + // Check that it's not already set if it's not a repeated field. + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) + } + + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Parse into the field. + fieldSet[name] = true + if err := p.readAny(dst, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + if props.Required { + reqCount-- + } + + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + + } + + if reqCount > 0 { + return p.missingRequiredFieldError(sv) + } + return reqFieldErr +} + +// consumeExtName consumes extension name or expanded Any type URL and the +// following ']'. It returns the name or URL consumed. +func (p *textParser) consumeExtName() (string, error) { + tok := p.next() + if tok.err != nil { + return "", tok.err + } + + // If extension name or type url is quoted, it's a single token. + if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { + name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) + if err != nil { + return "", err + } + return name, p.consumeToken("]") + } + + // Consume everything up to "]" + var parts []string + for tok.value != "]" { + parts = append(parts, tok.value) + tok = p.next() + if tok.err != nil { + return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) + } + } + return strings.Join(parts, ""), nil +} + +// consumeOptionalSeparator consumes an optional semicolon or comma. +// It is used in readStruct to provide backward compatibility. +func (p *textParser) consumeOptionalSeparator() error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ";" && tok.value != "," { + p.back() + } + return nil +} + +func (p *textParser) readAny(v reflect.Value, props *Properties) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "" { + return p.errorf("unexpected EOF") + } + + switch fv := v; fv.Kind() { + case reflect.Slice: + at := v.Type() + if at.Elem().Kind() == reflect.Uint8 { + // Special case for []byte + if tok.value[0] != '"' && tok.value[0] != '\'' { + // Deliberately written out here, as the error after + // this switch statement would write "invalid []byte: ...", + // which is not as user-friendly. + return p.errorf("invalid string: %v", tok.value) + } + bytes := []byte(tok.unquoted) + fv.Set(reflect.ValueOf(bytes)) + return nil + } + // Repeated field. + if tok.value == "[" { + // Repeated field with list notation, like [1,2,3]. + for { + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + err := p.readAny(fv.Index(fv.Len()-1), props) + if err != nil { + return err + } + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "]" { + break + } + if tok.value != "," { + return p.errorf("Expected ']' or ',' found %q", tok.value) + } + } + return nil + } + // One value of the repeated field. + p.back() + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + return p.readAny(fv.Index(fv.Len()-1), props) + case reflect.Bool: + // true/1/t/True or false/f/0/False. + switch tok.value { + case "true", "1", "t", "True": + fv.SetBool(true) + return nil + case "false", "0", "f", "False": + fv.SetBool(false) + return nil + } + case reflect.Float32, reflect.Float64: + v := tok.value + // Ignore 'f' for compatibility with output generated by C++, but don't + // remove 'f' when the value is "-inf" or "inf". + if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { + v = v[:len(v)-1] + } + if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { + fv.SetFloat(f) + return nil + } + case reflect.Int32: + if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { + fv.SetInt(x) + return nil + } + + if len(props.Enum) == 0 { + break + } + m, ok := enumValueMaps[props.Enum] + if !ok { + break + } + x, ok := m[tok.value] + if !ok { + break + } + fv.SetInt(int64(x)) + return nil + case reflect.Int64: + if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { + fv.SetInt(x) + return nil + } + + case reflect.Ptr: + // A basic field (indirected through pointer), or a repeated message/group + p.back() + fv.Set(reflect.New(fv.Type().Elem())) + return p.readAny(fv.Elem(), props) + case reflect.String: + if tok.value[0] == '"' || tok.value[0] == '\'' { + fv.SetString(tok.unquoted) + return nil + } + case reflect.Struct: + var terminator string + switch tok.value { + case "{": + terminator = "}" + case "<": + terminator = ">" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + // TODO: Handle nested messages which implement encoding.TextUnmarshaler. + return p.readStruct(fv, terminator) + case reflect.Uint32: + if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { + fv.SetUint(x) + return nil + } + case reflect.Uint64: + if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { + fv.SetUint(x) + return nil + } + } + return p.errorf("invalid %v: %v", v.Type(), tok.value) +} + +// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb +// before starting to unmarshal, so any existing data in pb is always removed. +// If a required field is not set and no other error occurs, +// UnmarshalText returns *RequiredNotSetError. +func UnmarshalText(s string, pb Message) error { + if um, ok := pb.(encoding.TextUnmarshaler); ok { + err := um.UnmarshalText([]byte(s)) + return err + } + pb.Reset() + v := reflect.ValueOf(pb) + if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { + return pe + } + return nil +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile new file mode 100644 index 000000000..41a2d04d0 --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/Makefile @@ -0,0 +1,36 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Not stored here, but descriptor.proto is in https://github.com/google/protobuf/ +# at src/google/protobuf/descriptor.proto +regenerate: + @echo WARNING! THIS RULE IS PROBABLY NOT RIGHT FOR YOUR INSTALLATION + protoc --go_out=../../../../.. -I$(HOME)/src/protobuf/include $(HOME)/src/protobuf/include/google/protobuf/descriptor.proto diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go new file mode 100644 index 000000000..63cf2c80a --- /dev/null +++ b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go @@ -0,0 +1,2152 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/descriptor.proto + +/* +Package descriptor is a generated protocol buffer package. + +It is generated from these files: + google/protobuf/descriptor.proto + +It has these top-level messages: + FileDescriptorSet + FileDescriptorProto + DescriptorProto + FieldDescriptorProto + OneofDescriptorProto + EnumDescriptorProto + EnumValueDescriptorProto + ServiceDescriptorProto + MethodDescriptorProto + FileOptions + MessageOptions + FieldOptions + OneofOptions + EnumOptions + EnumValueOptions + ServiceOptions + MethodOptions + UninterpretedOption + SourceCodeInfo + GeneratedCodeInfo +*/ +package descriptor + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type FieldDescriptorProto_Type int32 + +const ( + // 0 is reserved for errors. + // Order is weird for historical reasons. + FieldDescriptorProto_TYPE_DOUBLE FieldDescriptorProto_Type = 1 + FieldDescriptorProto_TYPE_FLOAT FieldDescriptorProto_Type = 2 + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + FieldDescriptorProto_TYPE_INT64 FieldDescriptorProto_Type = 3 + FieldDescriptorProto_TYPE_UINT64 FieldDescriptorProto_Type = 4 + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + FieldDescriptorProto_TYPE_INT32 FieldDescriptorProto_Type = 5 + FieldDescriptorProto_TYPE_FIXED64 FieldDescriptorProto_Type = 6 + FieldDescriptorProto_TYPE_FIXED32 FieldDescriptorProto_Type = 7 + FieldDescriptorProto_TYPE_BOOL FieldDescriptorProto_Type = 8 + FieldDescriptorProto_TYPE_STRING FieldDescriptorProto_Type = 9 + // Tag-delimited aggregate. + // Group type is deprecated and not supported in proto3. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. + FieldDescriptorProto_TYPE_GROUP FieldDescriptorProto_Type = 10 + FieldDescriptorProto_TYPE_MESSAGE FieldDescriptorProto_Type = 11 + // New in version 2. + FieldDescriptorProto_TYPE_BYTES FieldDescriptorProto_Type = 12 + FieldDescriptorProto_TYPE_UINT32 FieldDescriptorProto_Type = 13 + FieldDescriptorProto_TYPE_ENUM FieldDescriptorProto_Type = 14 + FieldDescriptorProto_TYPE_SFIXED32 FieldDescriptorProto_Type = 15 + FieldDescriptorProto_TYPE_SFIXED64 FieldDescriptorProto_Type = 16 + FieldDescriptorProto_TYPE_SINT32 FieldDescriptorProto_Type = 17 + FieldDescriptorProto_TYPE_SINT64 FieldDescriptorProto_Type = 18 +) + +var FieldDescriptorProto_Type_name = map[int32]string{ + 1: "TYPE_DOUBLE", + 2: "TYPE_FLOAT", + 3: "TYPE_INT64", + 4: "TYPE_UINT64", + 5: "TYPE_INT32", + 6: "TYPE_FIXED64", + 7: "TYPE_FIXED32", + 8: "TYPE_BOOL", + 9: "TYPE_STRING", + 10: "TYPE_GROUP", + 11: "TYPE_MESSAGE", + 12: "TYPE_BYTES", + 13: "TYPE_UINT32", + 14: "TYPE_ENUM", + 15: "TYPE_SFIXED32", + 16: "TYPE_SFIXED64", + 17: "TYPE_SINT32", + 18: "TYPE_SINT64", +} +var FieldDescriptorProto_Type_value = map[string]int32{ + "TYPE_DOUBLE": 1, + "TYPE_FLOAT": 2, + "TYPE_INT64": 3, + "TYPE_UINT64": 4, + "TYPE_INT32": 5, + "TYPE_FIXED64": 6, + "TYPE_FIXED32": 7, + "TYPE_BOOL": 8, + "TYPE_STRING": 9, + "TYPE_GROUP": 10, + "TYPE_MESSAGE": 11, + "TYPE_BYTES": 12, + "TYPE_UINT32": 13, + "TYPE_ENUM": 14, + "TYPE_SFIXED32": 15, + "TYPE_SFIXED64": 16, + "TYPE_SINT32": 17, + "TYPE_SINT64": 18, +} + +func (x FieldDescriptorProto_Type) Enum() *FieldDescriptorProto_Type { + p := new(FieldDescriptorProto_Type) + *p = x + return p +} +func (x FieldDescriptorProto_Type) String() string { + return proto.EnumName(FieldDescriptorProto_Type_name, int32(x)) +} +func (x *FieldDescriptorProto_Type) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FieldDescriptorProto_Type_value, data, "FieldDescriptorProto_Type") + if err != nil { + return err + } + *x = FieldDescriptorProto_Type(value) + return nil +} +func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} } + +type FieldDescriptorProto_Label int32 + +const ( + // 0 is reserved for errors + FieldDescriptorProto_LABEL_OPTIONAL FieldDescriptorProto_Label = 1 + FieldDescriptorProto_LABEL_REQUIRED FieldDescriptorProto_Label = 2 + FieldDescriptorProto_LABEL_REPEATED FieldDescriptorProto_Label = 3 +) + +var FieldDescriptorProto_Label_name = map[int32]string{ + 1: "LABEL_OPTIONAL", + 2: "LABEL_REQUIRED", + 3: "LABEL_REPEATED", +} +var FieldDescriptorProto_Label_value = map[string]int32{ + "LABEL_OPTIONAL": 1, + "LABEL_REQUIRED": 2, + "LABEL_REPEATED": 3, +} + +func (x FieldDescriptorProto_Label) Enum() *FieldDescriptorProto_Label { + p := new(FieldDescriptorProto_Label) + *p = x + return p +} +func (x FieldDescriptorProto_Label) String() string { + return proto.EnumName(FieldDescriptorProto_Label_name, int32(x)) +} +func (x *FieldDescriptorProto_Label) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FieldDescriptorProto_Label_value, data, "FieldDescriptorProto_Label") + if err != nil { + return err + } + *x = FieldDescriptorProto_Label(value) + return nil +} +func (FieldDescriptorProto_Label) EnumDescriptor() ([]byte, []int) { + return fileDescriptor0, []int{3, 1} +} + +// Generated classes can be optimized for speed or code size. +type FileOptions_OptimizeMode int32 + +const ( + FileOptions_SPEED FileOptions_OptimizeMode = 1 + // etc. + FileOptions_CODE_SIZE FileOptions_OptimizeMode = 2 + FileOptions_LITE_RUNTIME FileOptions_OptimizeMode = 3 +) + +var FileOptions_OptimizeMode_name = map[int32]string{ + 1: "SPEED", + 2: "CODE_SIZE", + 3: "LITE_RUNTIME", +} +var FileOptions_OptimizeMode_value = map[string]int32{ + "SPEED": 1, + "CODE_SIZE": 2, + "LITE_RUNTIME": 3, +} + +func (x FileOptions_OptimizeMode) Enum() *FileOptions_OptimizeMode { + p := new(FileOptions_OptimizeMode) + *p = x + return p +} +func (x FileOptions_OptimizeMode) String() string { + return proto.EnumName(FileOptions_OptimizeMode_name, int32(x)) +} +func (x *FileOptions_OptimizeMode) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FileOptions_OptimizeMode_value, data, "FileOptions_OptimizeMode") + if err != nil { + return err + } + *x = FileOptions_OptimizeMode(value) + return nil +} +func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{9, 0} } + +type FieldOptions_CType int32 + +const ( + // Default mode. + FieldOptions_STRING FieldOptions_CType = 0 + FieldOptions_CORD FieldOptions_CType = 1 + FieldOptions_STRING_PIECE FieldOptions_CType = 2 +) + +var FieldOptions_CType_name = map[int32]string{ + 0: "STRING", + 1: "CORD", + 2: "STRING_PIECE", +} +var FieldOptions_CType_value = map[string]int32{ + "STRING": 0, + "CORD": 1, + "STRING_PIECE": 2, +} + +func (x FieldOptions_CType) Enum() *FieldOptions_CType { + p := new(FieldOptions_CType) + *p = x + return p +} +func (x FieldOptions_CType) String() string { + return proto.EnumName(FieldOptions_CType_name, int32(x)) +} +func (x *FieldOptions_CType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FieldOptions_CType_value, data, "FieldOptions_CType") + if err != nil { + return err + } + *x = FieldOptions_CType(value) + return nil +} +func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{11, 0} } + +type FieldOptions_JSType int32 + +const ( + // Use the default type. + FieldOptions_JS_NORMAL FieldOptions_JSType = 0 + // Use JavaScript strings. + FieldOptions_JS_STRING FieldOptions_JSType = 1 + // Use JavaScript numbers. + FieldOptions_JS_NUMBER FieldOptions_JSType = 2 +) + +var FieldOptions_JSType_name = map[int32]string{ + 0: "JS_NORMAL", + 1: "JS_STRING", + 2: "JS_NUMBER", +} +var FieldOptions_JSType_value = map[string]int32{ + "JS_NORMAL": 0, + "JS_STRING": 1, + "JS_NUMBER": 2, +} + +func (x FieldOptions_JSType) Enum() *FieldOptions_JSType { + p := new(FieldOptions_JSType) + *p = x + return p +} +func (x FieldOptions_JSType) String() string { + return proto.EnumName(FieldOptions_JSType_name, int32(x)) +} +func (x *FieldOptions_JSType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FieldOptions_JSType_value, data, "FieldOptions_JSType") + if err != nil { + return err + } + *x = FieldOptions_JSType(value) + return nil +} +func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{11, 1} } + +// Is this method side-effect-free (or safe in HTTP parlance), or idempotent, +// or neither? HTTP based RPC implementation may choose GET verb for safe +// methods, and PUT verb for idempotent methods instead of the default POST. +type MethodOptions_IdempotencyLevel int32 + +const ( + MethodOptions_IDEMPOTENCY_UNKNOWN MethodOptions_IdempotencyLevel = 0 + MethodOptions_NO_SIDE_EFFECTS MethodOptions_IdempotencyLevel = 1 + MethodOptions_IDEMPOTENT MethodOptions_IdempotencyLevel = 2 +) + +var MethodOptions_IdempotencyLevel_name = map[int32]string{ + 0: "IDEMPOTENCY_UNKNOWN", + 1: "NO_SIDE_EFFECTS", + 2: "IDEMPOTENT", +} +var MethodOptions_IdempotencyLevel_value = map[string]int32{ + "IDEMPOTENCY_UNKNOWN": 0, + "NO_SIDE_EFFECTS": 1, + "IDEMPOTENT": 2, +} + +func (x MethodOptions_IdempotencyLevel) Enum() *MethodOptions_IdempotencyLevel { + p := new(MethodOptions_IdempotencyLevel) + *p = x + return p +} +func (x MethodOptions_IdempotencyLevel) String() string { + return proto.EnumName(MethodOptions_IdempotencyLevel_name, int32(x)) +} +func (x *MethodOptions_IdempotencyLevel) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(MethodOptions_IdempotencyLevel_value, data, "MethodOptions_IdempotencyLevel") + if err != nil { + return err + } + *x = MethodOptions_IdempotencyLevel(value) + return nil +} +func (MethodOptions_IdempotencyLevel) EnumDescriptor() ([]byte, []int) { + return fileDescriptor0, []int{16, 0} +} + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +type FileDescriptorSet struct { + File []*FileDescriptorProto `protobuf:"bytes,1,rep,name=file" json:"file,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FileDescriptorSet) Reset() { *m = FileDescriptorSet{} } +func (m *FileDescriptorSet) String() string { return proto.CompactTextString(m) } +func (*FileDescriptorSet) ProtoMessage() {} +func (*FileDescriptorSet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *FileDescriptorSet) GetFile() []*FileDescriptorProto { + if m != nil { + return m.File + } + return nil +} + +// Describes a complete .proto file. +type FileDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Package *string `protobuf:"bytes,2,opt,name=package" json:"package,omitempty"` + // Names of files imported by this file. + Dependency []string `protobuf:"bytes,3,rep,name=dependency" json:"dependency,omitempty"` + // Indexes of the public imported files in the dependency list above. + PublicDependency []int32 `protobuf:"varint,10,rep,name=public_dependency,json=publicDependency" json:"public_dependency,omitempty"` + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + WeakDependency []int32 `protobuf:"varint,11,rep,name=weak_dependency,json=weakDependency" json:"weak_dependency,omitempty"` + // All top-level definitions in this file. + MessageType []*DescriptorProto `protobuf:"bytes,4,rep,name=message_type,json=messageType" json:"message_type,omitempty"` + EnumType []*EnumDescriptorProto `protobuf:"bytes,5,rep,name=enum_type,json=enumType" json:"enum_type,omitempty"` + Service []*ServiceDescriptorProto `protobuf:"bytes,6,rep,name=service" json:"service,omitempty"` + Extension []*FieldDescriptorProto `protobuf:"bytes,7,rep,name=extension" json:"extension,omitempty"` + Options *FileOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` + // This field contains optional information about the original source code. + // You may safely remove this entire field without harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + SourceCodeInfo *SourceCodeInfo `protobuf:"bytes,9,opt,name=source_code_info,json=sourceCodeInfo" json:"source_code_info,omitempty"` + // The syntax of the proto file. + // The supported values are "proto2" and "proto3". + Syntax *string `protobuf:"bytes,12,opt,name=syntax" json:"syntax,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FileDescriptorProto) Reset() { *m = FileDescriptorProto{} } +func (m *FileDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*FileDescriptorProto) ProtoMessage() {} +func (*FileDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *FileDescriptorProto) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *FileDescriptorProto) GetPackage() string { + if m != nil && m.Package != nil { + return *m.Package + } + return "" +} + +func (m *FileDescriptorProto) GetDependency() []string { + if m != nil { + return m.Dependency + } + return nil +} + +func (m *FileDescriptorProto) GetPublicDependency() []int32 { + if m != nil { + return m.PublicDependency + } + return nil +} + +func (m *FileDescriptorProto) GetWeakDependency() []int32 { + if m != nil { + return m.WeakDependency + } + return nil +} + +func (m *FileDescriptorProto) GetMessageType() []*DescriptorProto { + if m != nil { + return m.MessageType + } + return nil +} + +func (m *FileDescriptorProto) GetEnumType() []*EnumDescriptorProto { + if m != nil { + return m.EnumType + } + return nil +} + +func (m *FileDescriptorProto) GetService() []*ServiceDescriptorProto { + if m != nil { + return m.Service + } + return nil +} + +func (m *FileDescriptorProto) GetExtension() []*FieldDescriptorProto { + if m != nil { + return m.Extension + } + return nil +} + +func (m *FileDescriptorProto) GetOptions() *FileOptions { + if m != nil { + return m.Options + } + return nil +} + +func (m *FileDescriptorProto) GetSourceCodeInfo() *SourceCodeInfo { + if m != nil { + return m.SourceCodeInfo + } + return nil +} + +func (m *FileDescriptorProto) GetSyntax() string { + if m != nil && m.Syntax != nil { + return *m.Syntax + } + return "" +} + +// Describes a message type. +type DescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Field []*FieldDescriptorProto `protobuf:"bytes,2,rep,name=field" json:"field,omitempty"` + Extension []*FieldDescriptorProto `protobuf:"bytes,6,rep,name=extension" json:"extension,omitempty"` + NestedType []*DescriptorProto `protobuf:"bytes,3,rep,name=nested_type,json=nestedType" json:"nested_type,omitempty"` + EnumType []*EnumDescriptorProto `protobuf:"bytes,4,rep,name=enum_type,json=enumType" json:"enum_type,omitempty"` + ExtensionRange []*DescriptorProto_ExtensionRange `protobuf:"bytes,5,rep,name=extension_range,json=extensionRange" json:"extension_range,omitempty"` + OneofDecl []*OneofDescriptorProto `protobuf:"bytes,8,rep,name=oneof_decl,json=oneofDecl" json:"oneof_decl,omitempty"` + Options *MessageOptions `protobuf:"bytes,7,opt,name=options" json:"options,omitempty"` + ReservedRange []*DescriptorProto_ReservedRange `protobuf:"bytes,9,rep,name=reserved_range,json=reservedRange" json:"reserved_range,omitempty"` + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + ReservedName []string `protobuf:"bytes,10,rep,name=reserved_name,json=reservedName" json:"reserved_name,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DescriptorProto) Reset() { *m = DescriptorProto{} } +func (m *DescriptorProto) String() string { return proto.CompactTextString(m) } +func (*DescriptorProto) ProtoMessage() {} +func (*DescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *DescriptorProto) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *DescriptorProto) GetField() []*FieldDescriptorProto { + if m != nil { + return m.Field + } + return nil +} + +func (m *DescriptorProto) GetExtension() []*FieldDescriptorProto { + if m != nil { + return m.Extension + } + return nil +} + +func (m *DescriptorProto) GetNestedType() []*DescriptorProto { + if m != nil { + return m.NestedType + } + return nil +} + +func (m *DescriptorProto) GetEnumType() []*EnumDescriptorProto { + if m != nil { + return m.EnumType + } + return nil +} + +func (m *DescriptorProto) GetExtensionRange() []*DescriptorProto_ExtensionRange { + if m != nil { + return m.ExtensionRange + } + return nil +} + +func (m *DescriptorProto) GetOneofDecl() []*OneofDescriptorProto { + if m != nil { + return m.OneofDecl + } + return nil +} + +func (m *DescriptorProto) GetOptions() *MessageOptions { + if m != nil { + return m.Options + } + return nil +} + +func (m *DescriptorProto) GetReservedRange() []*DescriptorProto_ReservedRange { + if m != nil { + return m.ReservedRange + } + return nil +} + +func (m *DescriptorProto) GetReservedName() []string { + if m != nil { + return m.ReservedName + } + return nil +} + +type DescriptorProto_ExtensionRange struct { + Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DescriptorProto_ExtensionRange) Reset() { *m = DescriptorProto_ExtensionRange{} } +func (m *DescriptorProto_ExtensionRange) String() string { return proto.CompactTextString(m) } +func (*DescriptorProto_ExtensionRange) ProtoMessage() {} +func (*DescriptorProto_ExtensionRange) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{2, 0} +} + +func (m *DescriptorProto_ExtensionRange) GetStart() int32 { + if m != nil && m.Start != nil { + return *m.Start + } + return 0 +} + +func (m *DescriptorProto_ExtensionRange) GetEnd() int32 { + if m != nil && m.End != nil { + return *m.End + } + return 0 +} + +// Range of reserved tag numbers. Reserved tag numbers may not be used by +// fields or extension ranges in the same message. Reserved ranges may +// not overlap. +type DescriptorProto_ReservedRange struct { + Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *DescriptorProto_ReservedRange) Reset() { *m = DescriptorProto_ReservedRange{} } +func (m *DescriptorProto_ReservedRange) String() string { return proto.CompactTextString(m) } +func (*DescriptorProto_ReservedRange) ProtoMessage() {} +func (*DescriptorProto_ReservedRange) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{2, 1} +} + +func (m *DescriptorProto_ReservedRange) GetStart() int32 { + if m != nil && m.Start != nil { + return *m.Start + } + return 0 +} + +func (m *DescriptorProto_ReservedRange) GetEnd() int32 { + if m != nil && m.End != nil { + return *m.End + } + return 0 +} + +// Describes a field within a message. +type FieldDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Number *int32 `protobuf:"varint,3,opt,name=number" json:"number,omitempty"` + Label *FieldDescriptorProto_Label `protobuf:"varint,4,opt,name=label,enum=google.protobuf.FieldDescriptorProto_Label" json:"label,omitempty"` + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + Type *FieldDescriptorProto_Type `protobuf:"varint,5,opt,name=type,enum=google.protobuf.FieldDescriptorProto_Type" json:"type,omitempty"` + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + TypeName *string `protobuf:"bytes,6,opt,name=type_name,json=typeName" json:"type_name,omitempty"` + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + Extendee *string `protobuf:"bytes,2,opt,name=extendee" json:"extendee,omitempty"` + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + // TODO(kenton): Base-64 encode? + DefaultValue *string `protobuf:"bytes,7,opt,name=default_value,json=defaultValue" json:"default_value,omitempty"` + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + OneofIndex *int32 `protobuf:"varint,9,opt,name=oneof_index,json=oneofIndex" json:"oneof_index,omitempty"` + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + JsonName *string `protobuf:"bytes,10,opt,name=json_name,json=jsonName" json:"json_name,omitempty"` + Options *FieldOptions `protobuf:"bytes,8,opt,name=options" json:"options,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} } +func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*FieldDescriptorProto) ProtoMessage() {} +func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *FieldDescriptorProto) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *FieldDescriptorProto) GetNumber() int32 { + if m != nil && m.Number != nil { + return *m.Number + } + return 0 +} + +func (m *FieldDescriptorProto) GetLabel() FieldDescriptorProto_Label { + if m != nil && m.Label != nil { + return *m.Label + } + return FieldDescriptorProto_LABEL_OPTIONAL +} + +func (m *FieldDescriptorProto) GetType() FieldDescriptorProto_Type { + if m != nil && m.Type != nil { + return *m.Type + } + return FieldDescriptorProto_TYPE_DOUBLE +} + +func (m *FieldDescriptorProto) GetTypeName() string { + if m != nil && m.TypeName != nil { + return *m.TypeName + } + return "" +} + +func (m *FieldDescriptorProto) GetExtendee() string { + if m != nil && m.Extendee != nil { + return *m.Extendee + } + return "" +} + +func (m *FieldDescriptorProto) GetDefaultValue() string { + if m != nil && m.DefaultValue != nil { + return *m.DefaultValue + } + return "" +} + +func (m *FieldDescriptorProto) GetOneofIndex() int32 { + if m != nil && m.OneofIndex != nil { + return *m.OneofIndex + } + return 0 +} + +func (m *FieldDescriptorProto) GetJsonName() string { + if m != nil && m.JsonName != nil { + return *m.JsonName + } + return "" +} + +func (m *FieldDescriptorProto) GetOptions() *FieldOptions { + if m != nil { + return m.Options + } + return nil +} + +// Describes a oneof. +type OneofDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Options *OneofOptions `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} } +func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*OneofDescriptorProto) ProtoMessage() {} +func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *OneofDescriptorProto) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *OneofDescriptorProto) GetOptions() *OneofOptions { + if m != nil { + return m.Options + } + return nil +} + +// Describes an enum type. +type EnumDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Value []*EnumValueDescriptorProto `protobuf:"bytes,2,rep,name=value" json:"value,omitempty"` + Options *EnumOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} } +func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*EnumDescriptorProto) ProtoMessage() {} +func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *EnumDescriptorProto) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *EnumDescriptorProto) GetValue() []*EnumValueDescriptorProto { + if m != nil { + return m.Value + } + return nil +} + +func (m *EnumDescriptorProto) GetOptions() *EnumOptions { + if m != nil { + return m.Options + } + return nil +} + +// Describes a value within an enum. +type EnumValueDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Number *int32 `protobuf:"varint,2,opt,name=number" json:"number,omitempty"` + Options *EnumValueOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} } +func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*EnumValueDescriptorProto) ProtoMessage() {} +func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *EnumValueDescriptorProto) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *EnumValueDescriptorProto) GetNumber() int32 { + if m != nil && m.Number != nil { + return *m.Number + } + return 0 +} + +func (m *EnumValueDescriptorProto) GetOptions() *EnumValueOptions { + if m != nil { + return m.Options + } + return nil +} + +// Describes a service. +type ServiceDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Method []*MethodDescriptorProto `protobuf:"bytes,2,rep,name=method" json:"method,omitempty"` + Options *ServiceOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} } +func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*ServiceDescriptorProto) ProtoMessage() {} +func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *ServiceDescriptorProto) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *ServiceDescriptorProto) GetMethod() []*MethodDescriptorProto { + if m != nil { + return m.Method + } + return nil +} + +func (m *ServiceDescriptorProto) GetOptions() *ServiceOptions { + if m != nil { + return m.Options + } + return nil +} + +// Describes a method of a service. +type MethodDescriptorProto struct { + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + InputType *string `protobuf:"bytes,2,opt,name=input_type,json=inputType" json:"input_type,omitempty"` + OutputType *string `protobuf:"bytes,3,opt,name=output_type,json=outputType" json:"output_type,omitempty"` + Options *MethodOptions `protobuf:"bytes,4,opt,name=options" json:"options,omitempty"` + // Identifies if client streams multiple client messages + ClientStreaming *bool `protobuf:"varint,5,opt,name=client_streaming,json=clientStreaming,def=0" json:"client_streaming,omitempty"` + // Identifies if server streams multiple server messages + ServerStreaming *bool `protobuf:"varint,6,opt,name=server_streaming,json=serverStreaming,def=0" json:"server_streaming,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} } +func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) } +func (*MethodDescriptorProto) ProtoMessage() {} +func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +const Default_MethodDescriptorProto_ClientStreaming bool = false +const Default_MethodDescriptorProto_ServerStreaming bool = false + +func (m *MethodDescriptorProto) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *MethodDescriptorProto) GetInputType() string { + if m != nil && m.InputType != nil { + return *m.InputType + } + return "" +} + +func (m *MethodDescriptorProto) GetOutputType() string { + if m != nil && m.OutputType != nil { + return *m.OutputType + } + return "" +} + +func (m *MethodDescriptorProto) GetOptions() *MethodOptions { + if m != nil { + return m.Options + } + return nil +} + +func (m *MethodDescriptorProto) GetClientStreaming() bool { + if m != nil && m.ClientStreaming != nil { + return *m.ClientStreaming + } + return Default_MethodDescriptorProto_ClientStreaming +} + +func (m *MethodDescriptorProto) GetServerStreaming() bool { + if m != nil && m.ServerStreaming != nil { + return *m.ServerStreaming + } + return Default_MethodDescriptorProto_ServerStreaming +} + +type FileOptions struct { + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + JavaPackage *string `protobuf:"bytes,1,opt,name=java_package,json=javaPackage" json:"java_package,omitempty"` + // If set, all the classes from the .proto file are wrapped in a single + // outer class with the given name. This applies to both Proto1 + // (equivalent to the old "--one_java_file" option) and Proto2 (where + // a .proto always translates to a single class, but you may want to + // explicitly choose the class name). + JavaOuterClassname *string `protobuf:"bytes,8,opt,name=java_outer_classname,json=javaOuterClassname" json:"java_outer_classname,omitempty"` + // If set true, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the outer class + // named by java_outer_classname. However, the outer class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + JavaMultipleFiles *bool `protobuf:"varint,10,opt,name=java_multiple_files,json=javaMultipleFiles,def=0" json:"java_multiple_files,omitempty"` + // This option does nothing. + JavaGenerateEqualsAndHash *bool `protobuf:"varint,20,opt,name=java_generate_equals_and_hash,json=javaGenerateEqualsAndHash" json:"java_generate_equals_and_hash,omitempty"` + // If set true, then the Java2 code generator will generate code that + // throws an exception whenever an attempt is made to assign a non-UTF-8 + // byte sequence to a string field. + // Message reflection will do the same. + // However, an extension field still accepts non-UTF-8 byte sequences. + // This option has no effect on when used with the lite runtime. + JavaStringCheckUtf8 *bool `protobuf:"varint,27,opt,name=java_string_check_utf8,json=javaStringCheckUtf8,def=0" json:"java_string_check_utf8,omitempty"` + OptimizeFor *FileOptions_OptimizeMode `protobuf:"varint,9,opt,name=optimize_for,json=optimizeFor,enum=google.protobuf.FileOptions_OptimizeMode,def=1" json:"optimize_for,omitempty"` + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + GoPackage *string `protobuf:"bytes,11,opt,name=go_package,json=goPackage" json:"go_package,omitempty"` + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + CcGenericServices *bool `protobuf:"varint,16,opt,name=cc_generic_services,json=ccGenericServices,def=0" json:"cc_generic_services,omitempty"` + JavaGenericServices *bool `protobuf:"varint,17,opt,name=java_generic_services,json=javaGenericServices,def=0" json:"java_generic_services,omitempty"` + PyGenericServices *bool `protobuf:"varint,18,opt,name=py_generic_services,json=pyGenericServices,def=0" json:"py_generic_services,omitempty"` + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + Deprecated *bool `protobuf:"varint,23,opt,name=deprecated,def=0" json:"deprecated,omitempty"` + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + CcEnableArenas *bool `protobuf:"varint,31,opt,name=cc_enable_arenas,json=ccEnableArenas,def=0" json:"cc_enable_arenas,omitempty"` + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + ObjcClassPrefix *string `protobuf:"bytes,36,opt,name=objc_class_prefix,json=objcClassPrefix" json:"objc_class_prefix,omitempty"` + // Namespace for generated classes; defaults to the package. + CsharpNamespace *string `protobuf:"bytes,37,opt,name=csharp_namespace,json=csharpNamespace" json:"csharp_namespace,omitempty"` + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + SwiftPrefix *string `protobuf:"bytes,39,opt,name=swift_prefix,json=swiftPrefix" json:"swift_prefix,omitempty"` + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + PhpClassPrefix *string `protobuf:"bytes,40,opt,name=php_class_prefix,json=phpClassPrefix" json:"php_class_prefix,omitempty"` + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FileOptions) Reset() { *m = FileOptions{} } +func (m *FileOptions) String() string { return proto.CompactTextString(m) } +func (*FileOptions) ProtoMessage() {} +func (*FileOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +var extRange_FileOptions = []proto.ExtensionRange{ + {1000, 536870911}, +} + +func (*FileOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_FileOptions +} + +const Default_FileOptions_JavaMultipleFiles bool = false +const Default_FileOptions_JavaStringCheckUtf8 bool = false +const Default_FileOptions_OptimizeFor FileOptions_OptimizeMode = FileOptions_SPEED +const Default_FileOptions_CcGenericServices bool = false +const Default_FileOptions_JavaGenericServices bool = false +const Default_FileOptions_PyGenericServices bool = false +const Default_FileOptions_Deprecated bool = false +const Default_FileOptions_CcEnableArenas bool = false + +func (m *FileOptions) GetJavaPackage() string { + if m != nil && m.JavaPackage != nil { + return *m.JavaPackage + } + return "" +} + +func (m *FileOptions) GetJavaOuterClassname() string { + if m != nil && m.JavaOuterClassname != nil { + return *m.JavaOuterClassname + } + return "" +} + +func (m *FileOptions) GetJavaMultipleFiles() bool { + if m != nil && m.JavaMultipleFiles != nil { + return *m.JavaMultipleFiles + } + return Default_FileOptions_JavaMultipleFiles +} + +func (m *FileOptions) GetJavaGenerateEqualsAndHash() bool { + if m != nil && m.JavaGenerateEqualsAndHash != nil { + return *m.JavaGenerateEqualsAndHash + } + return false +} + +func (m *FileOptions) GetJavaStringCheckUtf8() bool { + if m != nil && m.JavaStringCheckUtf8 != nil { + return *m.JavaStringCheckUtf8 + } + return Default_FileOptions_JavaStringCheckUtf8 +} + +func (m *FileOptions) GetOptimizeFor() FileOptions_OptimizeMode { + if m != nil && m.OptimizeFor != nil { + return *m.OptimizeFor + } + return Default_FileOptions_OptimizeFor +} + +func (m *FileOptions) GetGoPackage() string { + if m != nil && m.GoPackage != nil { + return *m.GoPackage + } + return "" +} + +func (m *FileOptions) GetCcGenericServices() bool { + if m != nil && m.CcGenericServices != nil { + return *m.CcGenericServices + } + return Default_FileOptions_CcGenericServices +} + +func (m *FileOptions) GetJavaGenericServices() bool { + if m != nil && m.JavaGenericServices != nil { + return *m.JavaGenericServices + } + return Default_FileOptions_JavaGenericServices +} + +func (m *FileOptions) GetPyGenericServices() bool { + if m != nil && m.PyGenericServices != nil { + return *m.PyGenericServices + } + return Default_FileOptions_PyGenericServices +} + +func (m *FileOptions) GetDeprecated() bool { + if m != nil && m.Deprecated != nil { + return *m.Deprecated + } + return Default_FileOptions_Deprecated +} + +func (m *FileOptions) GetCcEnableArenas() bool { + if m != nil && m.CcEnableArenas != nil { + return *m.CcEnableArenas + } + return Default_FileOptions_CcEnableArenas +} + +func (m *FileOptions) GetObjcClassPrefix() string { + if m != nil && m.ObjcClassPrefix != nil { + return *m.ObjcClassPrefix + } + return "" +} + +func (m *FileOptions) GetCsharpNamespace() string { + if m != nil && m.CsharpNamespace != nil { + return *m.CsharpNamespace + } + return "" +} + +func (m *FileOptions) GetSwiftPrefix() string { + if m != nil && m.SwiftPrefix != nil { + return *m.SwiftPrefix + } + return "" +} + +func (m *FileOptions) GetPhpClassPrefix() string { + if m != nil && m.PhpClassPrefix != nil { + return *m.PhpClassPrefix + } + return "" +} + +func (m *FileOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + +type MessageOptions struct { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + MessageSetWireFormat *bool `protobuf:"varint,1,opt,name=message_set_wire_format,json=messageSetWireFormat,def=0" json:"message_set_wire_format,omitempty"` + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + NoStandardDescriptorAccessor *bool `protobuf:"varint,2,opt,name=no_standard_descriptor_accessor,json=noStandardDescriptorAccessor,def=0" json:"no_standard_descriptor_accessor,omitempty"` + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map<KeyType, ValueType> map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementions still need to work as + // if the field is a repeated message field. + // + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + MapEntry *bool `protobuf:"varint,7,opt,name=map_entry,json=mapEntry" json:"map_entry,omitempty"` + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MessageOptions) Reset() { *m = MessageOptions{} } +func (m *MessageOptions) String() string { return proto.CompactTextString(m) } +func (*MessageOptions) ProtoMessage() {} +func (*MessageOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +var extRange_MessageOptions = []proto.ExtensionRange{ + {1000, 536870911}, +} + +func (*MessageOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_MessageOptions +} + +const Default_MessageOptions_MessageSetWireFormat bool = false +const Default_MessageOptions_NoStandardDescriptorAccessor bool = false +const Default_MessageOptions_Deprecated bool = false + +func (m *MessageOptions) GetMessageSetWireFormat() bool { + if m != nil && m.MessageSetWireFormat != nil { + return *m.MessageSetWireFormat + } + return Default_MessageOptions_MessageSetWireFormat +} + +func (m *MessageOptions) GetNoStandardDescriptorAccessor() bool { + if m != nil && m.NoStandardDescriptorAccessor != nil { + return *m.NoStandardDescriptorAccessor + } + return Default_MessageOptions_NoStandardDescriptorAccessor +} + +func (m *MessageOptions) GetDeprecated() bool { + if m != nil && m.Deprecated != nil { + return *m.Deprecated + } + return Default_MessageOptions_Deprecated +} + +func (m *MessageOptions) GetMapEntry() bool { + if m != nil && m.MapEntry != nil { + return *m.MapEntry + } + return false +} + +func (m *MessageOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + +type FieldOptions struct { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is not yet implemented in the open source + // release -- sorry, we'll try to include it in a future version! + Ctype *FieldOptions_CType `protobuf:"varint,1,opt,name=ctype,enum=google.protobuf.FieldOptions_CType,def=0" json:"ctype,omitempty"` + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. + Packed *bool `protobuf:"varint,2,opt,name=packed" json:"packed,omitempty"` + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). By default these types are + // represented as JavaScript strings. This avoids loss of precision that can + // happen when a large value is converted to a floating point JavaScript + // numbers. Specifying JS_NUMBER for the jstype causes the generated + // JavaScript code to use the JavaScript "number" type instead of strings. + // This option is an enum to permit additional types to be added, + // e.g. goog.math.Integer. + Jstype *FieldOptions_JSType `protobuf:"varint,6,opt,name=jstype,enum=google.protobuf.FieldOptions_JSType,def=0" json:"jstype,omitempty"` + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // + // Note that implementations may choose not to check required fields within + // a lazy sub-message. That is, calling IsInitialized() on the outer message + // may return true even if the inner message has missing required fields. + // This is necessary because otherwise the inner message would have to be + // parsed in order to perform the check, defeating the purpose of lazy + // parsing. An implementation which chooses not to check required fields + // must be consistent about it. That is, for any particular sub-message, the + // implementation must either *always* check its required fields, or *never* + // check its required fields, regardless of whether or not the message has + // been parsed. + Lazy *bool `protobuf:"varint,5,opt,name=lazy,def=0" json:"lazy,omitempty"` + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` + // For Google-internal migration only. Do not use. + Weak *bool `protobuf:"varint,10,opt,name=weak,def=0" json:"weak,omitempty"` + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *FieldOptions) Reset() { *m = FieldOptions{} } +func (m *FieldOptions) String() string { return proto.CompactTextString(m) } +func (*FieldOptions) ProtoMessage() {} +func (*FieldOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +var extRange_FieldOptions = []proto.ExtensionRange{ + {1000, 536870911}, +} + +func (*FieldOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_FieldOptions +} + +const Default_FieldOptions_Ctype FieldOptions_CType = FieldOptions_STRING +const Default_FieldOptions_Jstype FieldOptions_JSType = FieldOptions_JS_NORMAL +const Default_FieldOptions_Lazy bool = false +const Default_FieldOptions_Deprecated bool = false +const Default_FieldOptions_Weak bool = false + +func (m *FieldOptions) GetCtype() FieldOptions_CType { + if m != nil && m.Ctype != nil { + return *m.Ctype + } + return Default_FieldOptions_Ctype +} + +func (m *FieldOptions) GetPacked() bool { + if m != nil && m.Packed != nil { + return *m.Packed + } + return false +} + +func (m *FieldOptions) GetJstype() FieldOptions_JSType { + if m != nil && m.Jstype != nil { + return *m.Jstype + } + return Default_FieldOptions_Jstype +} + +func (m *FieldOptions) GetLazy() bool { + if m != nil && m.Lazy != nil { + return *m.Lazy + } + return Default_FieldOptions_Lazy +} + +func (m *FieldOptions) GetDeprecated() bool { + if m != nil && m.Deprecated != nil { + return *m.Deprecated + } + return Default_FieldOptions_Deprecated +} + +func (m *FieldOptions) GetWeak() bool { + if m != nil && m.Weak != nil { + return *m.Weak + } + return Default_FieldOptions_Weak +} + +func (m *FieldOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + +type OneofOptions struct { + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *OneofOptions) Reset() { *m = OneofOptions{} } +func (m *OneofOptions) String() string { return proto.CompactTextString(m) } +func (*OneofOptions) ProtoMessage() {} +func (*OneofOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } + +var extRange_OneofOptions = []proto.ExtensionRange{ + {1000, 536870911}, +} + +func (*OneofOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_OneofOptions +} + +func (m *OneofOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + +type EnumOptions struct { + // Set this option to true to allow mapping different tag names to the same + // value. + AllowAlias *bool `protobuf:"varint,2,opt,name=allow_alias,json=allowAlias" json:"allow_alias,omitempty"` + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + Deprecated *bool `protobuf:"varint,3,opt,name=deprecated,def=0" json:"deprecated,omitempty"` + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EnumOptions) Reset() { *m = EnumOptions{} } +func (m *EnumOptions) String() string { return proto.CompactTextString(m) } +func (*EnumOptions) ProtoMessage() {} +func (*EnumOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } + +var extRange_EnumOptions = []proto.ExtensionRange{ + {1000, 536870911}, +} + +func (*EnumOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_EnumOptions +} + +const Default_EnumOptions_Deprecated bool = false + +func (m *EnumOptions) GetAllowAlias() bool { + if m != nil && m.AllowAlias != nil { + return *m.AllowAlias + } + return false +} + +func (m *EnumOptions) GetDeprecated() bool { + if m != nil && m.Deprecated != nil { + return *m.Deprecated + } + return Default_EnumOptions_Deprecated +} + +func (m *EnumOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + +type EnumValueOptions struct { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + Deprecated *bool `protobuf:"varint,1,opt,name=deprecated,def=0" json:"deprecated,omitempty"` + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} } +func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) } +func (*EnumValueOptions) ProtoMessage() {} +func (*EnumValueOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } + +var extRange_EnumValueOptions = []proto.ExtensionRange{ + {1000, 536870911}, +} + +func (*EnumValueOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_EnumValueOptions +} + +const Default_EnumValueOptions_Deprecated bool = false + +func (m *EnumValueOptions) GetDeprecated() bool { + if m != nil && m.Deprecated != nil { + return *m.Deprecated + } + return Default_EnumValueOptions_Deprecated +} + +func (m *EnumValueOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + +type ServiceOptions struct { + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"` + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ServiceOptions) Reset() { *m = ServiceOptions{} } +func (m *ServiceOptions) String() string { return proto.CompactTextString(m) } +func (*ServiceOptions) ProtoMessage() {} +func (*ServiceOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } + +var extRange_ServiceOptions = []proto.ExtensionRange{ + {1000, 536870911}, +} + +func (*ServiceOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_ServiceOptions +} + +const Default_ServiceOptions_Deprecated bool = false + +func (m *ServiceOptions) GetDeprecated() bool { + if m != nil && m.Deprecated != nil { + return *m.Deprecated + } + return Default_ServiceOptions_Deprecated +} + +func (m *ServiceOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + +type MethodOptions struct { + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + Deprecated *bool `protobuf:"varint,33,opt,name=deprecated,def=0" json:"deprecated,omitempty"` + IdempotencyLevel *MethodOptions_IdempotencyLevel `protobuf:"varint,34,opt,name=idempotency_level,json=idempotencyLevel,enum=google.protobuf.MethodOptions_IdempotencyLevel,def=0" json:"idempotency_level,omitempty"` + // The parser stores options it doesn't recognize here. See above. + UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"` + proto.XXX_InternalExtensions `json:"-"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *MethodOptions) Reset() { *m = MethodOptions{} } +func (m *MethodOptions) String() string { return proto.CompactTextString(m) } +func (*MethodOptions) ProtoMessage() {} +func (*MethodOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } + +var extRange_MethodOptions = []proto.ExtensionRange{ + {1000, 536870911}, +} + +func (*MethodOptions) ExtensionRangeArray() []proto.ExtensionRange { + return extRange_MethodOptions +} + +const Default_MethodOptions_Deprecated bool = false +const Default_MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel = MethodOptions_IDEMPOTENCY_UNKNOWN + +func (m *MethodOptions) GetDeprecated() bool { + if m != nil && m.Deprecated != nil { + return *m.Deprecated + } + return Default_MethodOptions_Deprecated +} + +func (m *MethodOptions) GetIdempotencyLevel() MethodOptions_IdempotencyLevel { + if m != nil && m.IdempotencyLevel != nil { + return *m.IdempotencyLevel + } + return Default_MethodOptions_IdempotencyLevel +} + +func (m *MethodOptions) GetUninterpretedOption() []*UninterpretedOption { + if m != nil { + return m.UninterpretedOption + } + return nil +} + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +type UninterpretedOption struct { + Name []*UninterpretedOption_NamePart `protobuf:"bytes,2,rep,name=name" json:"name,omitempty"` + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + IdentifierValue *string `protobuf:"bytes,3,opt,name=identifier_value,json=identifierValue" json:"identifier_value,omitempty"` + PositiveIntValue *uint64 `protobuf:"varint,4,opt,name=positive_int_value,json=positiveIntValue" json:"positive_int_value,omitempty"` + NegativeIntValue *int64 `protobuf:"varint,5,opt,name=negative_int_value,json=negativeIntValue" json:"negative_int_value,omitempty"` + DoubleValue *float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue" json:"double_value,omitempty"` + StringValue []byte `protobuf:"bytes,7,opt,name=string_value,json=stringValue" json:"string_value,omitempty"` + AggregateValue *string `protobuf:"bytes,8,opt,name=aggregate_value,json=aggregateValue" json:"aggregate_value,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} } +func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) } +func (*UninterpretedOption) ProtoMessage() {} +func (*UninterpretedOption) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } + +func (m *UninterpretedOption) GetName() []*UninterpretedOption_NamePart { + if m != nil { + return m.Name + } + return nil +} + +func (m *UninterpretedOption) GetIdentifierValue() string { + if m != nil && m.IdentifierValue != nil { + return *m.IdentifierValue + } + return "" +} + +func (m *UninterpretedOption) GetPositiveIntValue() uint64 { + if m != nil && m.PositiveIntValue != nil { + return *m.PositiveIntValue + } + return 0 +} + +func (m *UninterpretedOption) GetNegativeIntValue() int64 { + if m != nil && m.NegativeIntValue != nil { + return *m.NegativeIntValue + } + return 0 +} + +func (m *UninterpretedOption) GetDoubleValue() float64 { + if m != nil && m.DoubleValue != nil { + return *m.DoubleValue + } + return 0 +} + +func (m *UninterpretedOption) GetStringValue() []byte { + if m != nil { + return m.StringValue + } + return nil +} + +func (m *UninterpretedOption) GetAggregateValue() string { + if m != nil && m.AggregateValue != nil { + return *m.AggregateValue + } + return "" +} + +// The name of the uninterpreted option. Each string represents a segment in +// a dot-separated name. is_extension is true iff a segment represents an +// extension (denoted with parentheses in options specs in .proto files). +// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents +// "foo.(bar.baz).qux". +type UninterpretedOption_NamePart struct { + NamePart *string `protobuf:"bytes,1,req,name=name_part,json=namePart" json:"name_part,omitempty"` + IsExtension *bool `protobuf:"varint,2,req,name=is_extension,json=isExtension" json:"is_extension,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *UninterpretedOption_NamePart) Reset() { *m = UninterpretedOption_NamePart{} } +func (m *UninterpretedOption_NamePart) String() string { return proto.CompactTextString(m) } +func (*UninterpretedOption_NamePart) ProtoMessage() {} +func (*UninterpretedOption_NamePart) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{17, 0} +} + +func (m *UninterpretedOption_NamePart) GetNamePart() string { + if m != nil && m.NamePart != nil { + return *m.NamePart + } + return "" +} + +func (m *UninterpretedOption_NamePart) GetIsExtension() bool { + if m != nil && m.IsExtension != nil { + return *m.IsExtension + } + return false +} + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +type SourceCodeInfo struct { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendent. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + Location []*SourceCodeInfo_Location `protobuf:"bytes,1,rep,name=location" json:"location,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} } +func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) } +func (*SourceCodeInfo) ProtoMessage() {} +func (*SourceCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } + +func (m *SourceCodeInfo) GetLocation() []*SourceCodeInfo_Location { + if m != nil { + return m.Location + } + return nil +} + +type SourceCodeInfo_Location struct { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition. For + // example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + Path []int32 `protobuf:"varint,1,rep,packed,name=path" json:"path,omitempty"` + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + Span []int32 `protobuf:"varint,2,rep,packed,name=span" json:"span,omitempty"` + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to qux. + // // + // // Another line attached to qux. + // optional double qux = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to qux or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + LeadingComments *string `protobuf:"bytes,3,opt,name=leading_comments,json=leadingComments" json:"leading_comments,omitempty"` + TrailingComments *string `protobuf:"bytes,4,opt,name=trailing_comments,json=trailingComments" json:"trailing_comments,omitempty"` + LeadingDetachedComments []string `protobuf:"bytes,6,rep,name=leading_detached_comments,json=leadingDetachedComments" json:"leading_detached_comments,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} } +func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) } +func (*SourceCodeInfo_Location) ProtoMessage() {} +func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18, 0} } + +func (m *SourceCodeInfo_Location) GetPath() []int32 { + if m != nil { + return m.Path + } + return nil +} + +func (m *SourceCodeInfo_Location) GetSpan() []int32 { + if m != nil { + return m.Span + } + return nil +} + +func (m *SourceCodeInfo_Location) GetLeadingComments() string { + if m != nil && m.LeadingComments != nil { + return *m.LeadingComments + } + return "" +} + +func (m *SourceCodeInfo_Location) GetTrailingComments() string { + if m != nil && m.TrailingComments != nil { + return *m.TrailingComments + } + return "" +} + +func (m *SourceCodeInfo_Location) GetLeadingDetachedComments() []string { + if m != nil { + return m.LeadingDetachedComments + } + return nil +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +type GeneratedCodeInfo struct { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + Annotation []*GeneratedCodeInfo_Annotation `protobuf:"bytes,1,rep,name=annotation" json:"annotation,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} } +func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) } +func (*GeneratedCodeInfo) ProtoMessage() {} +func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } + +func (m *GeneratedCodeInfo) GetAnnotation() []*GeneratedCodeInfo_Annotation { + if m != nil { + return m.Annotation + } + return nil +} + +type GeneratedCodeInfo_Annotation struct { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + Path []int32 `protobuf:"varint,1,rep,packed,name=path" json:"path,omitempty"` + // Identifies the filesystem path to the original source .proto. + SourceFile *string `protobuf:"bytes,2,opt,name=source_file,json=sourceFile" json:"source_file,omitempty"` + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + Begin *int32 `protobuf:"varint,3,opt,name=begin" json:"begin,omitempty"` + // Identifies the ending offset in bytes in the generated code that + // relates to the identified offset. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + End *int32 `protobuf:"varint,4,opt,name=end" json:"end,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *GeneratedCodeInfo_Annotation) Reset() { *m = GeneratedCodeInfo_Annotation{} } +func (m *GeneratedCodeInfo_Annotation) String() string { return proto.CompactTextString(m) } +func (*GeneratedCodeInfo_Annotation) ProtoMessage() {} +func (*GeneratedCodeInfo_Annotation) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{19, 0} +} + +func (m *GeneratedCodeInfo_Annotation) GetPath() []int32 { + if m != nil { + return m.Path + } + return nil +} + +func (m *GeneratedCodeInfo_Annotation) GetSourceFile() string { + if m != nil && m.SourceFile != nil { + return *m.SourceFile + } + return "" +} + +func (m *GeneratedCodeInfo_Annotation) GetBegin() int32 { + if m != nil && m.Begin != nil { + return *m.Begin + } + return 0 +} + +func (m *GeneratedCodeInfo_Annotation) GetEnd() int32 { + if m != nil && m.End != nil { + return *m.End + } + return 0 +} + +func init() { + proto.RegisterType((*FileDescriptorSet)(nil), "google.protobuf.FileDescriptorSet") + proto.RegisterType((*FileDescriptorProto)(nil), "google.protobuf.FileDescriptorProto") + proto.RegisterType((*DescriptorProto)(nil), "google.protobuf.DescriptorProto") + proto.RegisterType((*DescriptorProto_ExtensionRange)(nil), "google.protobuf.DescriptorProto.ExtensionRange") + proto.RegisterType((*DescriptorProto_ReservedRange)(nil), "google.protobuf.DescriptorProto.ReservedRange") + proto.RegisterType((*FieldDescriptorProto)(nil), "google.protobuf.FieldDescriptorProto") + proto.RegisterType((*OneofDescriptorProto)(nil), "google.protobuf.OneofDescriptorProto") + proto.RegisterType((*EnumDescriptorProto)(nil), "google.protobuf.EnumDescriptorProto") + proto.RegisterType((*EnumValueDescriptorProto)(nil), "google.protobuf.EnumValueDescriptorProto") + proto.RegisterType((*ServiceDescriptorProto)(nil), "google.protobuf.ServiceDescriptorProto") + proto.RegisterType((*MethodDescriptorProto)(nil), "google.protobuf.MethodDescriptorProto") + proto.RegisterType((*FileOptions)(nil), "google.protobuf.FileOptions") + proto.RegisterType((*MessageOptions)(nil), "google.protobuf.MessageOptions") + proto.RegisterType((*FieldOptions)(nil), "google.protobuf.FieldOptions") + proto.RegisterType((*OneofOptions)(nil), "google.protobuf.OneofOptions") + proto.RegisterType((*EnumOptions)(nil), "google.protobuf.EnumOptions") + proto.RegisterType((*EnumValueOptions)(nil), "google.protobuf.EnumValueOptions") + proto.RegisterType((*ServiceOptions)(nil), "google.protobuf.ServiceOptions") + proto.RegisterType((*MethodOptions)(nil), "google.protobuf.MethodOptions") + proto.RegisterType((*UninterpretedOption)(nil), "google.protobuf.UninterpretedOption") + proto.RegisterType((*UninterpretedOption_NamePart)(nil), "google.protobuf.UninterpretedOption.NamePart") + proto.RegisterType((*SourceCodeInfo)(nil), "google.protobuf.SourceCodeInfo") + proto.RegisterType((*SourceCodeInfo_Location)(nil), "google.protobuf.SourceCodeInfo.Location") + proto.RegisterType((*GeneratedCodeInfo)(nil), "google.protobuf.GeneratedCodeInfo") + proto.RegisterType((*GeneratedCodeInfo_Annotation)(nil), "google.protobuf.GeneratedCodeInfo.Annotation") + proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value) + proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value) + proto.RegisterEnum("google.protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value) + proto.RegisterEnum("google.protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value) + proto.RegisterEnum("google.protobuf.FieldOptions_JSType", FieldOptions_JSType_name, FieldOptions_JSType_value) + proto.RegisterEnum("google.protobuf.MethodOptions_IdempotencyLevel", MethodOptions_IdempotencyLevel_name, MethodOptions_IdempotencyLevel_value) +} + +func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 2460 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x5b, 0x6f, 0xdb, 0xc8, + 0x15, 0x5e, 0x5d, 0x2d, 0x1d, 0xc9, 0xf2, 0x78, 0xec, 0x4d, 0x18, 0xef, 0x25, 0x8e, 0xf6, 0x12, + 0x6f, 0xd2, 0xc8, 0x0b, 0xe7, 0xb2, 0x59, 0xa7, 0x48, 0x21, 0x4b, 0x8c, 0x57, 0xa9, 0x2c, 0xa9, + 0x94, 0xdc, 0x4d, 0xf6, 0x85, 0x18, 0x93, 0x23, 0x99, 0x09, 0x45, 0x72, 0x49, 0x2a, 0x89, 0xf7, + 0x29, 0x40, 0x9f, 0x0a, 0xf4, 0x07, 0x14, 0x45, 0xd1, 0x87, 0x7d, 0x59, 0xa0, 0x3f, 0xa0, 0xcf, + 0xfd, 0x05, 0x05, 0xf6, 0xb9, 0x2f, 0x45, 0x51, 0xa0, 0xfd, 0x07, 0x7d, 0x2d, 0x66, 0x86, 0xa4, + 0x48, 0x5d, 0x12, 0x77, 0x81, 0xec, 0x3e, 0xd9, 0x73, 0xce, 0x77, 0x0e, 0xcf, 0x9c, 0xf9, 0x66, + 0xce, 0x99, 0x11, 0x6c, 0x8f, 0x6c, 0x7b, 0x64, 0xd2, 0x5d, 0xc7, 0xb5, 0x7d, 0xfb, 0x64, 0x32, + 0xdc, 0xd5, 0xa9, 0xa7, 0xb9, 0x86, 0xe3, 0xdb, 0x6e, 0x8d, 0xcb, 0xf0, 0x9a, 0x40, 0xd4, 0x42, + 0x44, 0xf5, 0x08, 0xd6, 0x1f, 0x18, 0x26, 0x6d, 0x46, 0xc0, 0x3e, 0xf5, 0xf1, 0x5d, 0xc8, 0x0e, + 0x0d, 0x93, 0x4a, 0xa9, 0xed, 0xcc, 0x4e, 0x69, 0xef, 0xc3, 0xda, 0x8c, 0x51, 0x2d, 0x69, 0xd1, + 0x63, 0x62, 0x85, 0x5b, 0x54, 0xff, 0x95, 0x85, 0x8d, 0x05, 0x5a, 0x8c, 0x21, 0x6b, 0x91, 0x31, + 0xf3, 0x98, 0xda, 0x29, 0x2a, 0xfc, 0x7f, 0x2c, 0xc1, 0x8a, 0x43, 0xb4, 0xa7, 0x64, 0x44, 0xa5, + 0x34, 0x17, 0x87, 0x43, 0xfc, 0x3e, 0x80, 0x4e, 0x1d, 0x6a, 0xe9, 0xd4, 0xd2, 0xce, 0xa4, 0xcc, + 0x76, 0x66, 0xa7, 0xa8, 0xc4, 0x24, 0xf8, 0x3a, 0xac, 0x3b, 0x93, 0x13, 0xd3, 0xd0, 0xd4, 0x18, + 0x0c, 0xb6, 0x33, 0x3b, 0x39, 0x05, 0x09, 0x45, 0x73, 0x0a, 0xbe, 0x0a, 0x6b, 0xcf, 0x29, 0x79, + 0x1a, 0x87, 0x96, 0x38, 0xb4, 0xc2, 0xc4, 0x31, 0x60, 0x03, 0xca, 0x63, 0xea, 0x79, 0x64, 0x44, + 0x55, 0xff, 0xcc, 0xa1, 0x52, 0x96, 0xcf, 0x7e, 0x7b, 0x6e, 0xf6, 0xb3, 0x33, 0x2f, 0x05, 0x56, + 0x83, 0x33, 0x87, 0xe2, 0x3a, 0x14, 0xa9, 0x35, 0x19, 0x0b, 0x0f, 0xb9, 0x25, 0xf9, 0x93, 0xad, + 0xc9, 0x78, 0xd6, 0x4b, 0x81, 0x99, 0x05, 0x2e, 0x56, 0x3c, 0xea, 0x3e, 0x33, 0x34, 0x2a, 0xe5, + 0xb9, 0x83, 0xab, 0x73, 0x0e, 0xfa, 0x42, 0x3f, 0xeb, 0x23, 0xb4, 0xc3, 0x0d, 0x28, 0xd2, 0x17, + 0x3e, 0xb5, 0x3c, 0xc3, 0xb6, 0xa4, 0x15, 0xee, 0xe4, 0xa3, 0x05, 0xab, 0x48, 0x4d, 0x7d, 0xd6, + 0xc5, 0xd4, 0x0e, 0xdf, 0x81, 0x15, 0xdb, 0xf1, 0x0d, 0xdb, 0xf2, 0xa4, 0xc2, 0x76, 0x6a, 0xa7, + 0xb4, 0xf7, 0xee, 0x42, 0x22, 0x74, 0x05, 0x46, 0x09, 0xc1, 0xb8, 0x05, 0xc8, 0xb3, 0x27, 0xae, + 0x46, 0x55, 0xcd, 0xd6, 0xa9, 0x6a, 0x58, 0x43, 0x5b, 0x2a, 0x72, 0x07, 0x97, 0xe7, 0x27, 0xc2, + 0x81, 0x0d, 0x5b, 0xa7, 0x2d, 0x6b, 0x68, 0x2b, 0x15, 0x2f, 0x31, 0xc6, 0x17, 0x20, 0xef, 0x9d, + 0x59, 0x3e, 0x79, 0x21, 0x95, 0x39, 0x43, 0x82, 0x51, 0xf5, 0xbf, 0x39, 0x58, 0x3b, 0x0f, 0xc5, + 0xee, 0x41, 0x6e, 0xc8, 0x66, 0x29, 0xa5, 0xff, 0x9f, 0x1c, 0x08, 0x9b, 0x64, 0x12, 0xf3, 0x3f, + 0x30, 0x89, 0x75, 0x28, 0x59, 0xd4, 0xf3, 0xa9, 0x2e, 0x18, 0x91, 0x39, 0x27, 0xa7, 0x40, 0x18, + 0xcd, 0x53, 0x2a, 0xfb, 0x83, 0x28, 0xf5, 0x08, 0xd6, 0xa2, 0x90, 0x54, 0x97, 0x58, 0xa3, 0x90, + 0x9b, 0xbb, 0xaf, 0x8b, 0xa4, 0x26, 0x87, 0x76, 0x0a, 0x33, 0x53, 0x2a, 0x34, 0x31, 0xc6, 0x4d, + 0x00, 0xdb, 0xa2, 0xf6, 0x50, 0xd5, 0xa9, 0x66, 0x4a, 0x85, 0x25, 0x59, 0xea, 0x32, 0xc8, 0x5c, + 0x96, 0x6c, 0x21, 0xd5, 0x4c, 0xfc, 0xf9, 0x94, 0x6a, 0x2b, 0x4b, 0x98, 0x72, 0x24, 0x36, 0xd9, + 0x1c, 0xdb, 0x8e, 0xa1, 0xe2, 0x52, 0xc6, 0x7b, 0xaa, 0x07, 0x33, 0x2b, 0xf2, 0x20, 0x6a, 0xaf, + 0x9d, 0x99, 0x12, 0x98, 0x89, 0x89, 0xad, 0xba, 0xf1, 0x21, 0xfe, 0x00, 0x22, 0x81, 0xca, 0x69, + 0x05, 0xfc, 0x14, 0x2a, 0x87, 0xc2, 0x0e, 0x19, 0xd3, 0xad, 0xbb, 0x50, 0x49, 0xa6, 0x07, 0x6f, + 0x42, 0xce, 0xf3, 0x89, 0xeb, 0x73, 0x16, 0xe6, 0x14, 0x31, 0xc0, 0x08, 0x32, 0xd4, 0xd2, 0xf9, + 0x29, 0x97, 0x53, 0xd8, 0xbf, 0x5b, 0x9f, 0xc1, 0x6a, 0xe2, 0xf3, 0xe7, 0x35, 0xac, 0xfe, 0x3e, + 0x0f, 0x9b, 0x8b, 0x38, 0xb7, 0x90, 0xfe, 0x17, 0x20, 0x6f, 0x4d, 0xc6, 0x27, 0xd4, 0x95, 0x32, + 0xdc, 0x43, 0x30, 0xc2, 0x75, 0xc8, 0x99, 0xe4, 0x84, 0x9a, 0x52, 0x76, 0x3b, 0xb5, 0x53, 0xd9, + 0xbb, 0x7e, 0x2e, 0x56, 0xd7, 0xda, 0xcc, 0x44, 0x11, 0x96, 0xf8, 0x3e, 0x64, 0x83, 0x23, 0x8e, + 0x79, 0xb8, 0x76, 0x3e, 0x0f, 0x8c, 0x8b, 0x0a, 0xb7, 0xc3, 0xef, 0x40, 0x91, 0xfd, 0x15, 0xb9, + 0xcd, 0xf3, 0x98, 0x0b, 0x4c, 0xc0, 0xf2, 0x8a, 0xb7, 0xa0, 0xc0, 0x69, 0xa6, 0xd3, 0xb0, 0x34, + 0x44, 0x63, 0xb6, 0x30, 0x3a, 0x1d, 0x92, 0x89, 0xe9, 0xab, 0xcf, 0x88, 0x39, 0xa1, 0x9c, 0x30, + 0x45, 0xa5, 0x1c, 0x08, 0x7f, 0xcd, 0x64, 0xf8, 0x32, 0x94, 0x04, 0x2b, 0x0d, 0x4b, 0xa7, 0x2f, + 0xf8, 0xe9, 0x93, 0x53, 0x04, 0x51, 0x5b, 0x4c, 0xc2, 0x3e, 0xff, 0xc4, 0xb3, 0xad, 0x70, 0x69, + 0xf9, 0x27, 0x98, 0x80, 0x7f, 0xfe, 0xb3, 0xd9, 0x83, 0xef, 0xbd, 0xc5, 0xd3, 0x9b, 0xe5, 0x62, + 0xf5, 0x2f, 0x69, 0xc8, 0xf2, 0xfd, 0xb6, 0x06, 0xa5, 0xc1, 0xe3, 0x9e, 0xac, 0x36, 0xbb, 0xc7, + 0x07, 0x6d, 0x19, 0xa5, 0x70, 0x05, 0x80, 0x0b, 0x1e, 0xb4, 0xbb, 0xf5, 0x01, 0x4a, 0x47, 0xe3, + 0x56, 0x67, 0x70, 0xe7, 0x16, 0xca, 0x44, 0x06, 0xc7, 0x42, 0x90, 0x8d, 0x03, 0x6e, 0xee, 0xa1, + 0x1c, 0x46, 0x50, 0x16, 0x0e, 0x5a, 0x8f, 0xe4, 0xe6, 0x9d, 0x5b, 0x28, 0x9f, 0x94, 0xdc, 0xdc, + 0x43, 0x2b, 0x78, 0x15, 0x8a, 0x5c, 0x72, 0xd0, 0xed, 0xb6, 0x51, 0x21, 0xf2, 0xd9, 0x1f, 0x28, + 0xad, 0xce, 0x21, 0x2a, 0x46, 0x3e, 0x0f, 0x95, 0xee, 0x71, 0x0f, 0x41, 0xe4, 0xe1, 0x48, 0xee, + 0xf7, 0xeb, 0x87, 0x32, 0x2a, 0x45, 0x88, 0x83, 0xc7, 0x03, 0xb9, 0x8f, 0xca, 0x89, 0xb0, 0x6e, + 0xee, 0xa1, 0xd5, 0xe8, 0x13, 0x72, 0xe7, 0xf8, 0x08, 0x55, 0xf0, 0x3a, 0xac, 0x8a, 0x4f, 0x84, + 0x41, 0xac, 0xcd, 0x88, 0xee, 0xdc, 0x42, 0x68, 0x1a, 0x88, 0xf0, 0xb2, 0x9e, 0x10, 0xdc, 0xb9, + 0x85, 0x70, 0xb5, 0x01, 0x39, 0xce, 0x2e, 0x8c, 0xa1, 0xd2, 0xae, 0x1f, 0xc8, 0x6d, 0xb5, 0xdb, + 0x1b, 0xb4, 0xba, 0x9d, 0x7a, 0x1b, 0xa5, 0xa6, 0x32, 0x45, 0xfe, 0xd5, 0x71, 0x4b, 0x91, 0x9b, + 0x28, 0x1d, 0x97, 0xf5, 0xe4, 0xfa, 0x40, 0x6e, 0xa2, 0x4c, 0x55, 0x83, 0xcd, 0x45, 0xe7, 0xcc, + 0xc2, 0x9d, 0x11, 0x5b, 0xe2, 0xf4, 0x92, 0x25, 0xe6, 0xbe, 0xe6, 0x96, 0xf8, 0xdb, 0x14, 0x6c, + 0x2c, 0x38, 0x6b, 0x17, 0x7e, 0xe4, 0x17, 0x90, 0x13, 0x14, 0x15, 0xd5, 0xe7, 0x93, 0x85, 0x87, + 0x36, 0x27, 0xec, 0x5c, 0x05, 0xe2, 0x76, 0xf1, 0x0a, 0x9c, 0x59, 0x52, 0x81, 0x99, 0x8b, 0xb9, + 0x20, 0x7f, 0x93, 0x02, 0x69, 0x99, 0xef, 0xd7, 0x1c, 0x14, 0xe9, 0xc4, 0x41, 0x71, 0x6f, 0x36, + 0x80, 0x2b, 0xcb, 0xe7, 0x30, 0x17, 0xc5, 0x77, 0x29, 0xb8, 0xb0, 0xb8, 0x51, 0x59, 0x18, 0xc3, + 0x7d, 0xc8, 0x8f, 0xa9, 0x7f, 0x6a, 0x87, 0xc5, 0xfa, 0xe3, 0x05, 0x25, 0x80, 0xa9, 0x67, 0x73, + 0x15, 0x58, 0xc5, 0x6b, 0x48, 0x66, 0x59, 0xb7, 0x21, 0xa2, 0x99, 0x8b, 0xf4, 0xb7, 0x69, 0x78, + 0x7b, 0xa1, 0xf3, 0x85, 0x81, 0xbe, 0x07, 0x60, 0x58, 0xce, 0xc4, 0x17, 0x05, 0x59, 0x9c, 0x4f, + 0x45, 0x2e, 0xe1, 0x7b, 0x9f, 0x9d, 0x3d, 0x13, 0x3f, 0xd2, 0x67, 0xb8, 0x1e, 0x84, 0x88, 0x03, + 0xee, 0x4e, 0x03, 0xcd, 0xf2, 0x40, 0xdf, 0x5f, 0x32, 0xd3, 0xb9, 0x5a, 0xf7, 0x29, 0x20, 0xcd, + 0x34, 0xa8, 0xe5, 0xab, 0x9e, 0xef, 0x52, 0x32, 0x36, 0xac, 0x11, 0x3f, 0x80, 0x0b, 0xfb, 0xb9, + 0x21, 0x31, 0x3d, 0xaa, 0xac, 0x09, 0x75, 0x3f, 0xd4, 0x32, 0x0b, 0x5e, 0x65, 0xdc, 0x98, 0x45, + 0x3e, 0x61, 0x21, 0xd4, 0x91, 0x45, 0xf5, 0xef, 0x2b, 0x50, 0x8a, 0xb5, 0x75, 0xf8, 0x0a, 0x94, + 0x9f, 0x90, 0x67, 0x44, 0x0d, 0x5b, 0x75, 0x91, 0x89, 0x12, 0x93, 0xf5, 0x82, 0x76, 0xfd, 0x53, + 0xd8, 0xe4, 0x10, 0x7b, 0xe2, 0x53, 0x57, 0xd5, 0x4c, 0xe2, 0x79, 0x3c, 0x69, 0x05, 0x0e, 0xc5, + 0x4c, 0xd7, 0x65, 0xaa, 0x46, 0xa8, 0xc1, 0xb7, 0x61, 0x83, 0x5b, 0x8c, 0x27, 0xa6, 0x6f, 0x38, + 0x26, 0x55, 0xd9, 0xe5, 0xc1, 0xe3, 0x07, 0x71, 0x14, 0xd9, 0x3a, 0x43, 0x1c, 0x05, 0x00, 0x16, + 0x91, 0x87, 0x9b, 0xf0, 0x1e, 0x37, 0x1b, 0x51, 0x8b, 0xba, 0xc4, 0xa7, 0x2a, 0xfd, 0x7a, 0x42, + 0x4c, 0x4f, 0x25, 0x96, 0xae, 0x9e, 0x12, 0xef, 0x54, 0xda, 0x64, 0x0e, 0x0e, 0xd2, 0x52, 0x4a, + 0xb9, 0xc4, 0x80, 0x87, 0x01, 0x4e, 0xe6, 0xb0, 0xba, 0xa5, 0x7f, 0x41, 0xbc, 0x53, 0xbc, 0x0f, + 0x17, 0xb8, 0x17, 0xcf, 0x77, 0x0d, 0x6b, 0xa4, 0x6a, 0xa7, 0x54, 0x7b, 0xaa, 0x4e, 0xfc, 0xe1, + 0x5d, 0xe9, 0x9d, 0xf8, 0xf7, 0x79, 0x84, 0x7d, 0x8e, 0x69, 0x30, 0xc8, 0xb1, 0x3f, 0xbc, 0x8b, + 0xfb, 0x50, 0x66, 0x8b, 0x31, 0x36, 0xbe, 0xa1, 0xea, 0xd0, 0x76, 0x79, 0x65, 0xa9, 0x2c, 0xd8, + 0xd9, 0xb1, 0x0c, 0xd6, 0xba, 0x81, 0xc1, 0x91, 0xad, 0xd3, 0xfd, 0x5c, 0xbf, 0x27, 0xcb, 0x4d, + 0xa5, 0x14, 0x7a, 0x79, 0x60, 0xbb, 0x8c, 0x50, 0x23, 0x3b, 0x4a, 0x70, 0x49, 0x10, 0x6a, 0x64, + 0x87, 0xe9, 0xbd, 0x0d, 0x1b, 0x9a, 0x26, 0xe6, 0x6c, 0x68, 0x6a, 0xd0, 0xe2, 0x7b, 0x12, 0x4a, + 0x24, 0x4b, 0xd3, 0x0e, 0x05, 0x20, 0xe0, 0xb8, 0x87, 0x3f, 0x87, 0xb7, 0xa7, 0xc9, 0x8a, 0x1b, + 0xae, 0xcf, 0xcd, 0x72, 0xd6, 0xf4, 0x36, 0x6c, 0x38, 0x67, 0xf3, 0x86, 0x38, 0xf1, 0x45, 0xe7, + 0x6c, 0xd6, 0xec, 0x23, 0x7e, 0x6d, 0x73, 0xa9, 0x46, 0x7c, 0xaa, 0x4b, 0x17, 0xe3, 0xe8, 0x98, + 0x02, 0xef, 0x02, 0xd2, 0x34, 0x95, 0x5a, 0xe4, 0xc4, 0xa4, 0x2a, 0x71, 0xa9, 0x45, 0x3c, 0xe9, + 0x72, 0x1c, 0x5c, 0xd1, 0x34, 0x99, 0x6b, 0xeb, 0x5c, 0x89, 0xaf, 0xc1, 0xba, 0x7d, 0xf2, 0x44, + 0x13, 0xcc, 0x52, 0x1d, 0x97, 0x0e, 0x8d, 0x17, 0xd2, 0x87, 0x3c, 0x4d, 0x6b, 0x4c, 0xc1, 0x79, + 0xd5, 0xe3, 0x62, 0xfc, 0x09, 0x20, 0xcd, 0x3b, 0x25, 0xae, 0xc3, 0x4b, 0xbb, 0xe7, 0x10, 0x8d, + 0x4a, 0x1f, 0x09, 0xa8, 0x90, 0x77, 0x42, 0x31, 0x63, 0xb6, 0xf7, 0xdc, 0x18, 0xfa, 0xa1, 0xc7, + 0xab, 0x82, 0xd9, 0x5c, 0x16, 0x78, 0xdb, 0x01, 0xe4, 0x9c, 0x3a, 0xc9, 0x0f, 0xef, 0x70, 0x58, + 0xc5, 0x39, 0x75, 0xe2, 0xdf, 0x7d, 0x04, 0x9b, 0x13, 0xcb, 0xb0, 0x7c, 0xea, 0x3a, 0x2e, 0x65, + 0xed, 0xbe, 0xd8, 0xb3, 0xd2, 0xbf, 0x57, 0x96, 0x34, 0xec, 0xc7, 0x71, 0xb4, 0xa0, 0x8a, 0xb2, + 0x31, 0x99, 0x17, 0x56, 0xf7, 0xa1, 0x1c, 0x67, 0x10, 0x2e, 0x82, 0xe0, 0x10, 0x4a, 0xb1, 0x6a, + 0xdc, 0xe8, 0x36, 0x59, 0x1d, 0xfd, 0x4a, 0x46, 0x69, 0x56, 0xcf, 0xdb, 0xad, 0x81, 0xac, 0x2a, + 0xc7, 0x9d, 0x41, 0xeb, 0x48, 0x46, 0x99, 0x6b, 0xc5, 0xc2, 0x7f, 0x56, 0xd0, 0xcb, 0x97, 0x2f, + 0x5f, 0xa6, 0x1f, 0x66, 0x0b, 0x1f, 0xa3, 0xab, 0xd5, 0xef, 0xd3, 0x50, 0x49, 0x76, 0xd2, 0xf8, + 0xe7, 0x70, 0x31, 0xbc, 0xf6, 0x7a, 0xd4, 0x57, 0x9f, 0x1b, 0x2e, 0xa7, 0xf6, 0x98, 0x88, 0x5e, + 0x34, 0x5a, 0x95, 0xcd, 0x00, 0xd5, 0xa7, 0xfe, 0x97, 0x86, 0xcb, 0x88, 0x3b, 0x26, 0x3e, 0x6e, + 0xc3, 0x65, 0xcb, 0x56, 0x3d, 0x9f, 0x58, 0x3a, 0x71, 0x75, 0x75, 0xfa, 0xe0, 0xa0, 0x12, 0x4d, + 0xa3, 0x9e, 0x67, 0x8b, 0x92, 0x12, 0x79, 0x79, 0xd7, 0xb2, 0xfb, 0x01, 0x78, 0x7a, 0xd6, 0xd6, + 0x03, 0xe8, 0x0c, 0x83, 0x32, 0xcb, 0x18, 0xf4, 0x0e, 0x14, 0xc7, 0xc4, 0x51, 0xa9, 0xe5, 0xbb, + 0x67, 0xbc, 0xff, 0x2b, 0x28, 0x85, 0x31, 0x71, 0x64, 0x36, 0x7e, 0x73, 0x2b, 0x91, 0xcc, 0x66, + 0x01, 0x15, 0x1f, 0x66, 0x0b, 0x45, 0x04, 0xd5, 0x7f, 0x66, 0xa0, 0x1c, 0xef, 0x07, 0x59, 0x7b, + 0xad, 0xf1, 0xb3, 0x3f, 0xc5, 0x4f, 0x87, 0x0f, 0x5e, 0xd9, 0x3d, 0xd6, 0x1a, 0xac, 0x28, 0xec, + 0xe7, 0x45, 0x97, 0xa6, 0x08, 0x4b, 0x56, 0x90, 0xd9, 0x79, 0x40, 0x45, 0xef, 0x5f, 0x50, 0x82, + 0x11, 0x3e, 0x84, 0xfc, 0x13, 0x8f, 0xfb, 0xce, 0x73, 0xdf, 0x1f, 0xbe, 0xda, 0xf7, 0xc3, 0x3e, + 0x77, 0x5e, 0x7c, 0xd8, 0x57, 0x3b, 0x5d, 0xe5, 0xa8, 0xde, 0x56, 0x02, 0x73, 0x7c, 0x09, 0xb2, + 0x26, 0xf9, 0xe6, 0x2c, 0x59, 0x3e, 0xb8, 0xe8, 0xbc, 0x8b, 0x70, 0x09, 0xb2, 0xcf, 0x29, 0x79, + 0x9a, 0x3c, 0xb4, 0xb9, 0xe8, 0x0d, 0x6e, 0x86, 0x5d, 0xc8, 0xf1, 0x7c, 0x61, 0x80, 0x20, 0x63, + 0xe8, 0x2d, 0x5c, 0x80, 0x6c, 0xa3, 0xab, 0xb0, 0x0d, 0x81, 0xa0, 0x2c, 0xa4, 0x6a, 0xaf, 0x25, + 0x37, 0x64, 0x94, 0xae, 0xde, 0x86, 0xbc, 0x48, 0x02, 0xdb, 0x2c, 0x51, 0x1a, 0xd0, 0x5b, 0xc1, + 0x30, 0xf0, 0x91, 0x0a, 0xb5, 0xc7, 0x47, 0x07, 0xb2, 0x82, 0xd2, 0xc9, 0xa5, 0xce, 0xa2, 0x5c, + 0xd5, 0x83, 0x72, 0xbc, 0x21, 0xfc, 0x51, 0x58, 0x56, 0xfd, 0x6b, 0x0a, 0x4a, 0xb1, 0x06, 0x8f, + 0xb5, 0x16, 0xc4, 0x34, 0xed, 0xe7, 0x2a, 0x31, 0x0d, 0xe2, 0x05, 0xd4, 0x00, 0x2e, 0xaa, 0x33, + 0xc9, 0x79, 0x97, 0xee, 0x47, 0xda, 0x22, 0x39, 0x94, 0xaf, 0xfe, 0x29, 0x05, 0x68, 0xb6, 0x45, + 0x9c, 0x09, 0x33, 0xf5, 0x53, 0x86, 0x59, 0xfd, 0x63, 0x0a, 0x2a, 0xc9, 0xbe, 0x70, 0x26, 0xbc, + 0x2b, 0x3f, 0x69, 0x78, 0xff, 0x48, 0xc3, 0x6a, 0xa2, 0x1b, 0x3c, 0x6f, 0x74, 0x5f, 0xc3, 0xba, + 0xa1, 0xd3, 0xb1, 0x63, 0xfb, 0xd4, 0xd2, 0xce, 0x54, 0x93, 0x3e, 0xa3, 0xa6, 0x54, 0xe5, 0x87, + 0xc6, 0xee, 0xab, 0xfb, 0xcd, 0x5a, 0x6b, 0x6a, 0xd7, 0x66, 0x66, 0xfb, 0x1b, 0xad, 0xa6, 0x7c, + 0xd4, 0xeb, 0x0e, 0xe4, 0x4e, 0xe3, 0xb1, 0x7a, 0xdc, 0xf9, 0x65, 0xa7, 0xfb, 0x65, 0x47, 0x41, + 0xc6, 0x0c, 0xec, 0x0d, 0x6e, 0xfb, 0x1e, 0xa0, 0xd9, 0xa0, 0xf0, 0x45, 0x58, 0x14, 0x16, 0x7a, + 0x0b, 0x6f, 0xc0, 0x5a, 0xa7, 0xab, 0xf6, 0x5b, 0x4d, 0x59, 0x95, 0x1f, 0x3c, 0x90, 0x1b, 0x83, + 0xbe, 0xb8, 0x80, 0x47, 0xe8, 0x41, 0x62, 0x83, 0x57, 0xff, 0x90, 0x81, 0x8d, 0x05, 0x91, 0xe0, + 0x7a, 0xd0, 0xfb, 0x8b, 0xeb, 0xc8, 0x8d, 0xf3, 0x44, 0x5f, 0x63, 0xdd, 0x45, 0x8f, 0xb8, 0x7e, + 0x70, 0x55, 0xf8, 0x04, 0x58, 0x96, 0x2c, 0xdf, 0x18, 0x1a, 0xd4, 0x0d, 0xde, 0x2b, 0xc4, 0x85, + 0x60, 0x6d, 0x2a, 0x17, 0x4f, 0x16, 0x3f, 0x03, 0xec, 0xd8, 0x9e, 0xe1, 0x1b, 0xcf, 0xa8, 0x6a, + 0x58, 0xe1, 0xe3, 0x06, 0xbb, 0x20, 0x64, 0x15, 0x14, 0x6a, 0x5a, 0x96, 0x1f, 0xa1, 0x2d, 0x3a, + 0x22, 0x33, 0x68, 0x76, 0x98, 0x67, 0x14, 0x14, 0x6a, 0x22, 0xf4, 0x15, 0x28, 0xeb, 0xf6, 0x84, + 0xb5, 0x5b, 0x02, 0xc7, 0x6a, 0x47, 0x4a, 0x29, 0x09, 0x59, 0x04, 0x09, 0xfa, 0xe1, 0xe9, 0xab, + 0x4a, 0x59, 0x29, 0x09, 0x99, 0x80, 0x5c, 0x85, 0x35, 0x32, 0x1a, 0xb9, 0xcc, 0x79, 0xe8, 0x48, + 0x74, 0xf8, 0x95, 0x48, 0xcc, 0x81, 0x5b, 0x0f, 0xa1, 0x10, 0xe6, 0x81, 0x95, 0x6a, 0x96, 0x09, + 0xd5, 0x11, 0x6f, 0x5b, 0xe9, 0x9d, 0xa2, 0x52, 0xb0, 0x42, 0xe5, 0x15, 0x28, 0x1b, 0x9e, 0x3a, + 0x7d, 0x64, 0x4d, 0x6f, 0xa7, 0x77, 0x0a, 0x4a, 0xc9, 0xf0, 0xa2, 0x57, 0xb5, 0xea, 0x77, 0x69, + 0xa8, 0x24, 0x1f, 0x89, 0x71, 0x13, 0x0a, 0xa6, 0xad, 0x11, 0x4e, 0x2d, 0xf1, 0x0b, 0xc5, 0xce, + 0x6b, 0xde, 0x95, 0x6b, 0xed, 0x00, 0xaf, 0x44, 0x96, 0x5b, 0x7f, 0x4b, 0x41, 0x21, 0x14, 0xe3, + 0x0b, 0x90, 0x75, 0x88, 0x7f, 0xca, 0xdd, 0xe5, 0x0e, 0xd2, 0x28, 0xa5, 0xf0, 0x31, 0x93, 0x7b, + 0x0e, 0xb1, 0x38, 0x05, 0x02, 0x39, 0x1b, 0xb3, 0x75, 0x35, 0x29, 0xd1, 0xf9, 0xf5, 0xc1, 0x1e, + 0x8f, 0xa9, 0xe5, 0x7b, 0xe1, 0xba, 0x06, 0xf2, 0x46, 0x20, 0xc6, 0xd7, 0x61, 0xdd, 0x77, 0x89, + 0x61, 0x26, 0xb0, 0x59, 0x8e, 0x45, 0xa1, 0x22, 0x02, 0xef, 0xc3, 0xa5, 0xd0, 0xaf, 0x4e, 0x7d, + 0xa2, 0x9d, 0x52, 0x7d, 0x6a, 0x94, 0xe7, 0x2f, 0x90, 0x17, 0x03, 0x40, 0x33, 0xd0, 0x87, 0xb6, + 0xd5, 0xef, 0x53, 0xb0, 0x1e, 0x5e, 0x78, 0xf4, 0x28, 0x59, 0x47, 0x00, 0xc4, 0xb2, 0x6c, 0x3f, + 0x9e, 0xae, 0x79, 0x2a, 0xcf, 0xd9, 0xd5, 0xea, 0x91, 0x91, 0x12, 0x73, 0xb0, 0x35, 0x06, 0x98, + 0x6a, 0x96, 0xa6, 0xed, 0x32, 0x94, 0x82, 0x5f, 0x00, 0xf8, 0xcf, 0x48, 0xe2, 0x8a, 0x0c, 0x42, + 0xc4, 0x6e, 0x46, 0x78, 0x13, 0x72, 0x27, 0x74, 0x64, 0x58, 0xc1, 0xbb, 0xa4, 0x18, 0x84, 0xaf, + 0x9d, 0xd9, 0xe8, 0xb5, 0xf3, 0xe0, 0x77, 0x29, 0xd8, 0xd0, 0xec, 0xf1, 0x6c, 0xbc, 0x07, 0x68, + 0xe6, 0x9e, 0xee, 0x7d, 0x91, 0xfa, 0xea, 0xfe, 0xc8, 0xf0, 0x4f, 0x27, 0x27, 0x35, 0xcd, 0x1e, + 0xef, 0x8e, 0x6c, 0x93, 0x58, 0xa3, 0xe9, 0xef, 0x60, 0xfc, 0x1f, 0xed, 0xc6, 0x88, 0x5a, 0x37, + 0x46, 0x76, 0xec, 0x57, 0xb1, 0x7b, 0xd3, 0x7f, 0xbf, 0x4d, 0x67, 0x0e, 0x7b, 0x07, 0x7f, 0x4e, + 0x6f, 0x1d, 0x8a, 0x6f, 0xf5, 0xc2, 0xdc, 0x28, 0x74, 0x68, 0x52, 0x8d, 0xcd, 0xf7, 0x7f, 0x01, + 0x00, 0x00, 0xff, 0xff, 0x8e, 0x54, 0xe7, 0xef, 0x60, 0x1b, 0x00, 0x00, +} diff --git a/vendor/gopkg.in/urfave/cli.v1/CHANGELOG.md b/vendor/gopkg.in/urfave/cli.v1/CHANGELOG.md index 07f75464b..401eae5a2 100644 --- a/vendor/gopkg.in/urfave/cli.v1/CHANGELOG.md +++ b/vendor/gopkg.in/urfave/cli.v1/CHANGELOG.md @@ -4,6 +4,49 @@ ## [Unreleased] +## 1.20.0 - 2017-08-10 + +### Fixed + +* `HandleExitCoder` is now correctly iterates over all errors in + a `MultiError`. The exit code is the exit code of the last error or `1` if + there are no `ExitCoder`s in the `MultiError`. +* Fixed YAML file loading on Windows (previously would fail validate the file path) +* Subcommand `Usage`, `Description`, `ArgsUsage`, `OnUsageError` correctly + propogated +* `ErrWriter` is now passed downwards through command structure to avoid the + need to redefine it +* Pass `Command` context into `OnUsageError` rather than parent context so that + all fields are avaiable +* Errors occuring in `Before` funcs are no longer double printed +* Use `UsageText` in the help templates for commands and subcommands if + defined; otherwise build the usage as before (was previously ignoring this + field) +* `IsSet` and `GlobalIsSet` now correctly return whether a flag is set if + a program calls `Set` or `GlobalSet` directly after flag parsing (would + previously only return `true` if the flag was set during parsing) + +### Changed + +* No longer exit the program on command/subcommand error if the error raised is + not an `OsExiter`. This exiting behavior was introduced in 1.19.0, but was + determined to be a regression in functionality. See [the + PR](https://github.com/urfave/cli/pull/595) for discussion. + +### Added + +* `CommandsByName` type was added to make it easy to sort `Command`s by name, + alphabetically +* `altsrc` now handles loading of string and int arrays from TOML +* Support for definition of custom help templates for `App` via + `CustomAppHelpTemplate` +* Support for arbitrary key/value fields on `App` to be used with + `CustomAppHelpTemplate` via `ExtraInfo` +* `HelpFlag`, `VersionFlag`, and `BashCompletionFlag` changed to explictly be + `cli.Flag`s allowing for the use of custom flags satisfying the `cli.Flag` + interface to be used. + + ## [1.19.1] - 2016-11-21 ### Fixed diff --git a/vendor/gopkg.in/urfave/cli.v1/README.md b/vendor/gopkg.in/urfave/cli.v1/README.md index bb5f61eaf..2bbbd8ea9 100644 --- a/vendor/gopkg.in/urfave/cli.v1/README.md +++ b/vendor/gopkg.in/urfave/cli.v1/README.md @@ -455,13 +455,13 @@ error. Flags for the application and commands are shown in the order they are defined. However, it's possible to sort them from outside this library by using `FlagsByName` -with `sort`. +or `CommandsByName` with `sort`. For example this: <!-- { "args": ["--help"], - "output": "Load configuration from FILE\n.*Language for the greeting.*" + "output": "add a task to the list\n.*complete a task on the list\n.*\n\n.*\n.*Load configuration from FILE\n.*Language for the greeting.*" } --> ``` go package main @@ -488,7 +488,27 @@ func main() { }, } + app.Commands = []cli.Command{ + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) error { + return nil + }, + }, + { + Name: "add", + Aliases: []string{"a"}, + Usage: "add a task to the list", + Action: func(c *cli.Context) error { + return nil + }, + }, + } + sort.Sort(cli.FlagsByName(app.Flags)) + sort.Sort(cli.CommandsByName(app.Commands)) app.Run(os.Args) } @@ -940,16 +960,13 @@ SUPPORT: support@awesometown.example.com cli.AppHelpTemplate = `NAME: {{.Name}} - {{.Usage}} USAGE: - {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command -[command options]{{end}} {{if -.ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} + {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} {{if len .Authors}} -AUTHOR(S): +AUTHOR: {{range .Authors}}{{ . }}{{end}} {{end}}{{if .Commands}} COMMANDS: -{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t" -}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}} +{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}} GLOBAL OPTIONS: {{range .VisibleFlags}}{{.}} {{end}}{{end}}{{if .Copyright }} diff --git a/vendor/gopkg.in/urfave/cli.v1/app.go b/vendor/gopkg.in/urfave/cli.v1/app.go index 95ffc0b97..51fc45d87 100644 --- a/vendor/gopkg.in/urfave/cli.v1/app.go +++ b/vendor/gopkg.in/urfave/cli.v1/app.go @@ -85,6 +85,12 @@ type App struct { ErrWriter io.Writer // Other custom info Metadata map[string]interface{} + // Carries a function which returns app specific info. + ExtraInfo func() map[string]string + // CustomAppHelpTemplate the text template for app help topic. + // cli.go uses text/template to render templates. You can + // render custom help text by setting this variable. + CustomAppHelpTemplate string didSetup bool } @@ -234,7 +240,6 @@ func (a *App) Run(arguments []string) (err error) { if a.Before != nil { beforeErr := a.Before(context) if beforeErr != nil { - fmt.Fprintf(a.Writer, "%v\n\n", beforeErr) ShowAppHelp(context) HandleExitCoder(beforeErr) err = beforeErr diff --git a/vendor/gopkg.in/urfave/cli.v1/appveyor.yml b/vendor/gopkg.in/urfave/cli.v1/appveyor.yml index 698b188e1..1e1489c36 100644 --- a/vendor/gopkg.in/urfave/cli.v1/appveyor.yml +++ b/vendor/gopkg.in/urfave/cli.v1/appveyor.yml @@ -1,14 +1,16 @@ version: "{build}" -os: Windows Server 2012 R2 +os: Windows Server 2016 + +image: Visual Studio 2017 clone_folder: c:\gopath\src\github.com\urfave\cli environment: GOPATH: C:\gopath - GOVERSION: 1.6 - PYTHON: C:\Python27-x64 - PYTHON_VERSION: 2.7.x + GOVERSION: 1.8.x + PYTHON: C:\Python36-x64 + PYTHON_VERSION: 3.6.x PYTHON_ARCH: 64 install: diff --git a/vendor/gopkg.in/urfave/cli.v1/cli.go b/vendor/gopkg.in/urfave/cli.v1/cli.go index 74fd101f4..90c07eb8e 100644 --- a/vendor/gopkg.in/urfave/cli.v1/cli.go +++ b/vendor/gopkg.in/urfave/cli.v1/cli.go @@ -12,6 +12,7 @@ // app.Usage = "say a greeting" // app.Action = func(c *cli.Context) error { // println("Greetings") +// return nil // } // // app.Run(os.Args) diff --git a/vendor/gopkg.in/urfave/cli.v1/command.go b/vendor/gopkg.in/urfave/cli.v1/command.go index 2628fbf48..23de2944b 100644 --- a/vendor/gopkg.in/urfave/cli.v1/command.go +++ b/vendor/gopkg.in/urfave/cli.v1/command.go @@ -59,6 +59,25 @@ type Command struct { // Full name of command for help, defaults to full command name, including parent commands. HelpName string commandNamePath []string + + // CustomHelpTemplate the text template for the command help topic. + // cli.go uses text/template to render templates. You can + // render custom help text by setting this variable. + CustomHelpTemplate string +} + +type CommandsByName []Command + +func (c CommandsByName) Len() int { + return len(c) +} + +func (c CommandsByName) Less(i, j int) bool { + return c[i].Name < c[j].Name +} + +func (c CommandsByName) Swap(i, j int) { + c[i], c[j] = c[j], c[i] } // FullName returns the full name of the command. @@ -140,19 +159,20 @@ func (c Command) Run(ctx *Context) (err error) { } context := NewContext(ctx.App, set, ctx) + context.Command = c if checkCommandCompletions(context, c.Name) { return nil } if err != nil { if c.OnUsageError != nil { - err := c.OnUsageError(ctx, err, false) + err := c.OnUsageError(context, err, false) HandleExitCoder(err) return err } - fmt.Fprintln(ctx.App.Writer, "Incorrect Usage:", err.Error()) - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) + fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) + fmt.Fprintln(context.App.Writer) + ShowCommandHelp(context, c.Name) return err } @@ -177,9 +197,7 @@ func (c Command) Run(ctx *Context) (err error) { if c.Before != nil { err = c.Before(context) if err != nil { - fmt.Fprintln(ctx.App.Writer, err) - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) + ShowCommandHelp(context, c.Name) HandleExitCoder(err) return err } @@ -189,7 +207,6 @@ func (c Command) Run(ctx *Context) (err error) { c.Action = helpSubcommand.Action } - context.Command = c err = HandleAction(c.Action, context) if err != nil { @@ -230,14 +247,13 @@ func (c Command) startApp(ctx *Context) error { app.HelpName = app.Name } - if c.Description != "" { - app.Usage = c.Description - } else { - app.Usage = c.Usage - } + app.Usage = c.Usage + app.Description = c.Description + app.ArgsUsage = c.ArgsUsage // set CommandNotFound app.CommandNotFound = ctx.App.CommandNotFound + app.CustomAppHelpTemplate = c.CustomHelpTemplate // set the flags and commands app.Commands = c.Subcommands @@ -250,6 +266,7 @@ func (c Command) startApp(ctx *Context) error { app.Author = ctx.App.Author app.Email = ctx.App.Email app.Writer = ctx.App.Writer + app.ErrWriter = ctx.App.ErrWriter app.categories = CommandCategories{} for _, command := range c.Subcommands { @@ -272,6 +289,7 @@ func (c Command) startApp(ctx *Context) error { } else { app.Action = helpSubcommand.Action } + app.OnUsageError = c.OnUsageError for index, cc := range app.Commands { app.Commands[index].commandNamePath = []string{c.Name, cc.Name} diff --git a/vendor/gopkg.in/urfave/cli.v1/context.go b/vendor/gopkg.in/urfave/cli.v1/context.go index cb89e92a0..db94191e2 100644 --- a/vendor/gopkg.in/urfave/cli.v1/context.go +++ b/vendor/gopkg.in/urfave/cli.v1/context.go @@ -39,11 +39,13 @@ func (c *Context) NumFlags() int { // Set sets a context flag to a value. func (c *Context) Set(name, value string) error { + c.setFlags = nil return c.flagSet.Set(name, value) } // GlobalSet sets a context flag to a value on the global flagset func (c *Context) GlobalSet(name, value string) error { + globalContext(c).setFlags = nil return globalContext(c).flagSet.Set(name, value) } diff --git a/vendor/gopkg.in/urfave/cli.v1/errors.go b/vendor/gopkg.in/urfave/cli.v1/errors.go index 0206ff491..562b2953c 100644 --- a/vendor/gopkg.in/urfave/cli.v1/errors.go +++ b/vendor/gopkg.in/urfave/cli.v1/errors.go @@ -74,7 +74,7 @@ func (ee *ExitError) ExitCode() int { // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if // so prints the error to stderr (if it is non-empty) and calls OsExiter with the // given exit code. If the given error is a MultiError, then this func is -// called on all members of the Errors slice. +// called on all members of the Errors slice and calls OsExiter with the last exit code. func HandleExitCoder(err error) { if err == nil { return @@ -93,18 +93,23 @@ func HandleExitCoder(err error) { } if multiErr, ok := err.(MultiError); ok { - for _, merr := range multiErr.Errors { - HandleExitCoder(merr) - } + code := handleMultiError(multiErr) + OsExiter(code) return } +} - if err.Error() != "" { - if _, ok := err.(ErrorFormatter); ok { - fmt.Fprintf(ErrWriter, "%+v\n", err) +func handleMultiError(multiErr MultiError) int { + code := 1 + for _, merr := range multiErr.Errors { + if multiErr2, ok := merr.(MultiError); ok { + code = handleMultiError(multiErr2) } else { - fmt.Fprintln(ErrWriter, err) + fmt.Fprintln(ErrWriter, merr) + if exitErr, ok := merr.(ExitCoder); ok { + code = exitErr.ExitCode() + } } } - OsExiter(1) + return code } diff --git a/vendor/gopkg.in/urfave/cli.v1/flag.go b/vendor/gopkg.in/urfave/cli.v1/flag.go index 7dd8a2c4a..877ff3523 100644 --- a/vendor/gopkg.in/urfave/cli.v1/flag.go +++ b/vendor/gopkg.in/urfave/cli.v1/flag.go @@ -14,13 +14,13 @@ import ( const defaultPlaceholder = "value" // BashCompletionFlag enables bash-completion for all commands and subcommands -var BashCompletionFlag = BoolFlag{ +var BashCompletionFlag Flag = BoolFlag{ Name: "generate-bash-completion", Hidden: true, } // VersionFlag prints the version for the application -var VersionFlag = BoolFlag{ +var VersionFlag Flag = BoolFlag{ Name: "version, v", Usage: "print the version", } @@ -28,7 +28,7 @@ var VersionFlag = BoolFlag{ // HelpFlag prints the help for all commands and subcommands // Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand // unless HideHelp is set to true) -var HelpFlag = BoolFlag{ +var HelpFlag Flag = BoolFlag{ Name: "help, h", Usage: "show help", } @@ -630,7 +630,8 @@ func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error { func visibleFlags(fl []Flag) []Flag { visible := []Flag{} for _, flag := range fl { - if !flagValue(flag).FieldByName("Hidden").Bool() { + field := flagValue(flag).FieldByName("Hidden") + if !field.IsValid() || !field.Bool() { visible = append(visible, flag) } } @@ -723,9 +724,8 @@ func stringifyFlag(f Flag) string { needsPlaceholder := false defaultValueString := "" - val := fv.FieldByName("Value") - if val.IsValid() { + if val := fv.FieldByName("Value"); val.IsValid() { needsPlaceholder = true defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) diff --git a/vendor/gopkg.in/urfave/cli.v1/help.go b/vendor/gopkg.in/urfave/cli.v1/help.go index c8c1aee05..57ec98d58 100644 --- a/vendor/gopkg.in/urfave/cli.v1/help.go +++ b/vendor/gopkg.in/urfave/cli.v1/help.go @@ -47,7 +47,7 @@ var CommandHelpTemplate = `NAME: {{.HelpName}} - {{.Usage}} USAGE: - {{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Category}} + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} CATEGORY: {{.Category}}{{end}}{{if .Description}} @@ -64,10 +64,10 @@ OPTIONS: // cli.go uses text/template to render templates. You can // render custom help text by setting this variable. var SubcommandHelpTemplate = `NAME: - {{.HelpName}} - {{.Usage}} + {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}} USAGE: - {{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} COMMANDS:{{range .VisibleCategories}}{{if .Name}} {{.Name}}:{{end}}{{range .VisibleCommands}} @@ -112,17 +112,42 @@ var helpSubcommand = Command{ // Prints help for the App or Command type helpPrinter func(w io.Writer, templ string, data interface{}) +// Prints help for the App or Command with custom template function. +type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{}) + // HelpPrinter is a function that writes the help output. If not set a default // is used. The function signature is: // func(w io.Writer, templ string, data interface{}) var HelpPrinter helpPrinter = printHelp +// HelpPrinterCustom is same as HelpPrinter but +// takes a custom function for template function map. +var HelpPrinterCustom helpPrinterCustom = printHelpCustom + // VersionPrinter prints the version for the App var VersionPrinter = printVersion +// ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code. +func ShowAppHelpAndExit(c *Context, exitCode int) { + ShowAppHelp(c) + os.Exit(exitCode) +} + // ShowAppHelp is an action that displays the help. -func ShowAppHelp(c *Context) error { - HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) +func ShowAppHelp(c *Context) (err error) { + if c.App.CustomAppHelpTemplate == "" { + HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) + return + } + customAppData := func() map[string]interface{} { + if c.App.ExtraInfo == nil { + return nil + } + return map[string]interface{}{ + "ExtraInfo": c.App.ExtraInfo, + } + } + HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData()) return nil } @@ -138,6 +163,12 @@ func DefaultAppComplete(c *Context) { } } +// ShowCommandHelpAndExit - exits with code after showing help +func ShowCommandHelpAndExit(c *Context, command string, code int) { + ShowCommandHelp(c, command) + os.Exit(code) +} + // ShowCommandHelp prints help for the given command func ShowCommandHelp(ctx *Context, command string) error { // show the subcommand help for a command with subcommands @@ -148,7 +179,11 @@ func ShowCommandHelp(ctx *Context, command string) error { for _, c := range ctx.App.Commands { if c.HasName(command) { - HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) + if c.CustomHelpTemplate != "" { + HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil) + } else { + HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) + } return nil } } @@ -191,10 +226,15 @@ func ShowCommandCompletions(ctx *Context, command string) { } } -func printHelp(out io.Writer, templ string, data interface{}) { +func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) { funcMap := template.FuncMap{ "join": strings.Join, } + if customFunc != nil { + for key, value := range customFunc { + funcMap[key] = value + } + } w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) @@ -210,10 +250,14 @@ func printHelp(out io.Writer, templ string, data interface{}) { w.Flush() } +func printHelp(out io.Writer, templ string, data interface{}) { + printHelpCustom(out, templ, data, nil) +} + func checkVersion(c *Context) bool { found := false - if VersionFlag.Name != "" { - eachName(VersionFlag.Name, func(name string) { + if VersionFlag.GetName() != "" { + eachName(VersionFlag.GetName(), func(name string) { if c.GlobalBool(name) || c.Bool(name) { found = true } @@ -224,8 +268,8 @@ func checkVersion(c *Context) bool { func checkHelp(c *Context) bool { found := false - if HelpFlag.Name != "" { - eachName(HelpFlag.Name, func(name string) { + if HelpFlag.GetName() != "" { + eachName(HelpFlag.GetName(), func(name string) { if c.GlobalBool(name) || c.Bool(name) { found = true } @@ -260,7 +304,7 @@ func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { pos := len(arguments) - 1 lastArg := arguments[pos] - if lastArg != "--"+BashCompletionFlag.Name { + if lastArg != "--"+BashCompletionFlag.GetName() { return false, arguments } diff --git a/vendor/vendor.json b/vendor/vendor.json index 1386de4a3..8be10b94f 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -105,6 +105,18 @@ "revisionTime": "2017-07-10T16:04:46Z" }, { + "checksumSHA1": "yqF125xVSkmfLpIVGrLlfE05IUk=", + "path": "github.com/golang/protobuf/proto", + "revision": "748d386b5c1ea99658fd69fe9f03991ce86a90c1", + "revisionTime": "2017-07-26T21:28:29Z" + }, + { + "checksumSHA1": "Z1gJ3PKzwBpOoPnTSEM5yd0zHYA=", + "path": "github.com/golang/protobuf/protoc-gen-go/descriptor", + "revision": "748d386b5c1ea99658fd69fe9f03991ce86a90c1", + "revisionTime": "2017-07-26T21:28:29Z" + }, + { "checksumSHA1": "p/8vSviYF91gFflhrt5vkyksroo=", "path": "github.com/golang/snappy", "revision": "553a641470496b2327abcac10b36396bd98e45c9", @@ -658,10 +670,10 @@ "revisionTime": "2017-02-13T14:20:43Z" }, { - "checksumSHA1": "brhONOPp4CSdTZf5uEtcH+FpFUI=", + "checksumSHA1": "Yx1MU40fyGe7hhqW9+dkv8kXa60=", "path": "gopkg.in/urfave/cli.v1", - "revision": "0bdeddeeb0f650497d603c4ad7b20cfe685682f6", - "revisionTime": "2016-11-22T04:36:10Z" + "revision": "cfb38830724cc34fedffe9a2a29fb54fa9169cd1", + "revisionTime": "2017-08-11T01:42:03Z" } ], "rootPath": "github.com/ethereum/go-ethereum" diff --git a/whisper/mailserver/mailserver.go b/whisper/mailserver/mailserver.go index 42a0671a3..0ec6ec570 100644 --- a/whisper/mailserver/mailserver.go +++ b/whisper/mailserver/mailserver.go @@ -104,7 +104,7 @@ func (s *WMailServer) Archive(env *whisper.Envelope) { func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) { if peer == nil { - log.Error(fmt.Sprint("Whisper peer is nil")) + log.Error("Whisper peer is nil") return } diff --git a/whisper/mailserver/server_test.go b/whisper/mailserver/server_test.go index 95bf2bb43..9155ee85a 100644 --- a/whisper/mailserver/server_test.go +++ b/whisper/mailserver/server_test.go @@ -168,7 +168,7 @@ func singleRequest(t *testing.T, server *WMailServer, env *whisper.Envelope, p * src[0]++ ok, lower, upper, topic = server.validateRequest(src, request) if ok { - t.Fatalf("request validation false positive, seed: %d.", seed) + t.Fatalf("request validation false positive, seed: %d (lower: %d, upper: %d).", seed, lower, upper) } } diff --git a/whisper/whisperv2/api.go b/whisper/whisperv2/api.go index 0509453ba..5c6d17095 100644 --- a/whisper/whisperv2/api.go +++ b/whisper/whisperv2/api.go @@ -377,15 +377,6 @@ func (w *whisperFilter) retrieve() (messages []WhisperMessage) { return } -// activity returns the last time instance when client requests were executed on -// the filter. -func (w *whisperFilter) activity() time.Time { - w.lock.RLock() - defer w.lock.RUnlock() - - return w.update -} - // newWhisperFilter creates a new serialized, poll based whisper topic filter. func newWhisperFilter(id hexutil.Uint, ref *Whisper) *whisperFilter { return &whisperFilter{ diff --git a/whisper/whisperv2/whisper.go b/whisper/whisperv2/whisper.go index 1d7c21bd1..61c36918d 100644 --- a/whisper/whisperv2/whisper.go +++ b/whisper/whisperv2/whisper.go @@ -173,7 +173,7 @@ func (self *Whisper) Send(envelope *Envelope) error { // Start implements node.Service, starting the background data propagation thread // of the Whisper protocol. func (self *Whisper) Start(*p2p.Server) error { - log.Info(fmt.Sprint("Whisper started")) + log.Info("Whisper started") go self.update() return nil } @@ -182,7 +182,7 @@ func (self *Whisper) Start(*p2p.Server) error { // of the Whisper protocol. func (self *Whisper) Stop() error { close(self.quit) - log.Info(fmt.Sprint("Whisper stopped")) + log.Info("Whisper stopped") return nil } diff --git a/whisper/whisperv5/gen_criteria_json.go b/whisper/whisperv5/gen_criteria_json.go index 8d3e9ee24..df0de85df 100644 --- a/whisper/whisperv5/gen_criteria_json.go +++ b/whisper/whisperv5/gen_criteria_json.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) +var _ = (*criteriaOverride)(nil) + func (c Criteria) MarshalJSON() ([]byte, error) { type Criteria struct { SymKeyID string `json:"symKeyID"` diff --git a/whisper/whisperv5/gen_message_json.go b/whisper/whisperv5/gen_message_json.go index 26168225c..185557331 100644 --- a/whisper/whisperv5/gen_message_json.go +++ b/whisper/whisperv5/gen_message_json.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) +var _ = (*messageOverride)(nil) + func (m Message) MarshalJSON() ([]byte, error) { type Message struct { Sig hexutil.Bytes `json:"sig,omitempty"` diff --git a/whisper/whisperv5/gen_newmessage_json.go b/whisper/whisperv5/gen_newmessage_json.go index 0231cd919..d0a47185e 100644 --- a/whisper/whisperv5/gen_newmessage_json.go +++ b/whisper/whisperv5/gen_newmessage_json.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) +var _ = (*newMessageOverride)(nil) + func (n NewMessage) MarshalJSON() ([]byte, error) { type NewMessage struct { SymKeyID string `json:"symKeyID"` diff --git a/whisper/whisperv5/message_test.go b/whisper/whisperv5/message_test.go index aa82a02f3..2edf945df 100644 --- a/whisper/whisperv5/message_test.go +++ b/whisper/whisperv5/message_test.go @@ -25,11 +25,6 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -func copyFromBuf(dst []byte, src []byte, beg int) int { - copy(dst, src[beg:]) - return beg + len(dst) -} - func generateMessageParams() (*MessageParams, error) { // set all the parameters except p.Dst and p.Padding @@ -158,7 +153,7 @@ func TestMessageWrap(t *testing.T) { params.TTL = 1000000 params.WorkTime = 1 params.PoW = 10000000.0 - env, err = msg2.Wrap(params) + _, err = msg2.Wrap(params) if err == nil { t.Fatalf("unexpectedly reached the PoW target with seed %d.", seed) } diff --git a/whisper/whisperv5/whisper_test.go b/whisper/whisperv5/whisper_test.go index 145143833..025be5b54 100644 --- a/whisper/whisperv5/whisper_test.go +++ b/whisper/whisperv5/whisper_test.go @@ -424,7 +424,7 @@ func TestWhisperSymKeyManagement(t *testing.T) { randomKey = make([]byte, aesKeyLength+1) mrand.Read(randomKey) - id1, err = w.AddSymKeyDirect(randomKey) + _, err = w.AddSymKeyDirect(randomKey) if err == nil { t.Fatalf("added the key with wrong size, seed %d.", seed) } @@ -541,6 +541,9 @@ func TestCustomization(t *testing.T) { const smallPoW = 0.00001 f, err := generateFilter(t, true) + if err != nil { + t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) + } params, err := generateMessageParams() if err != nil { t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) @@ -607,6 +610,9 @@ func TestCustomization(t *testing.T) { // check w.messages() id, err := w.Subscribe(f) + if err != nil { + t.Fatalf("failed subscribe with seed %d: %s.", seed, err) + } time.Sleep(5 * time.Millisecond) mail := f.Retrieve() if len(mail) > 0 { |