mining: drop getwork support.
Since the Midstate is no longer needed, switch to using crypto/sha256.
This commit is contained in:
parent
7c44b6472f
commit
ab0f30c00d
14 changed files with 48 additions and 509 deletions
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013-2014 The btcsuite developers
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -9,12 +9,11 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"math/big"
|
||||
|
||||
"github.com/btcsuite/fastsha256"
|
||||
)
|
||||
|
||||
// Errors returned by canonicalPadding.
|
||||
|
@ -455,7 +454,7 @@ func nonceRFC6979(privkey *big.Int, hash []byte) *big.Int {
|
|||
curve := S256()
|
||||
q := curve.Params().N
|
||||
x := privkey
|
||||
alg := fastsha256.New
|
||||
alg := sha256.New
|
||||
|
||||
qlen := q.BitLen()
|
||||
holen := alg().Size()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -7,12 +7,11 @@ package btcec
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/fastsha256"
|
||||
)
|
||||
|
||||
type signatureTest struct {
|
||||
|
@ -558,7 +557,7 @@ func TestRFC6979(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
privKey, _ := PrivKeyFromBytes(S256(), decodeHex(test.key))
|
||||
hash := fastsha256.Sum256([]byte(test.msg))
|
||||
hash := sha256.Sum256([]byte(test.msg))
|
||||
|
||||
// Ensure deterministically generated nonce is the expected value.
|
||||
gotNonce := nonceRFC6979(privKey.D, hash[:]).Bytes()
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
// Copyright (c) 2015 The Decred developers
|
||||
// Copyright (c) 2016 The btcsuite developers
|
||||
// Copyright (c) 2016-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chainhash
|
||||
|
||||
import "github.com/btcsuite/fastsha256"
|
||||
import "crypto/sha256"
|
||||
|
||||
// HashB calculates hash(b) and returns the resulting bytes.
|
||||
func HashB(b []byte) []byte {
|
||||
hash := fastsha256.Sum256(b)
|
||||
hash := sha256.Sum256(b)
|
||||
return hash[:]
|
||||
}
|
||||
|
||||
// HashH calculates hash(b) and returns the resulting bytes as a Hash.
|
||||
func HashH(b []byte) Hash {
|
||||
return Hash(fastsha256.Sum256(b))
|
||||
return Hash(sha256.Sum256(b))
|
||||
}
|
||||
|
||||
// DoubleHashB calculates hash(hash(b)) and returns the resulting bytes.
|
||||
func DoubleHashB(b []byte) []byte {
|
||||
first := fastsha256.Sum256(b)
|
||||
second := fastsha256.Sum256(first[:])
|
||||
first := sha256.Sum256(b)
|
||||
second := sha256.Sum256(first[:])
|
||||
return second[:]
|
||||
}
|
||||
|
||||
// DoubleHashH calculates hash(hash(b)) and returns the resulting bytes as a
|
||||
// Hash.
|
||||
func DoubleHashH(b []byte) Hash {
|
||||
first := fastsha256.Sum256(b)
|
||||
return Hash(fastsha256.Sum256(first[:]))
|
||||
first := sha256.Sum256(b)
|
||||
return Hash(sha256.Sum256(first[:]))
|
||||
}
|
||||
|
|
27
config.go
27
config.go
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -137,7 +137,6 @@ type config struct {
|
|||
BlockMinSize uint32 `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"`
|
||||
BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"`
|
||||
BlockPrioritySize uint32 `long:"blockprioritysize" description:"Size in bytes for high-priority/low-fee transactions when creating a block"`
|
||||
GetWorkKeys []string `long:"getworkkey" description:"DEPRECATED -- Use the --miningaddr option instead"`
|
||||
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
|
||||
SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"`
|
||||
BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."`
|
||||
|
@ -717,30 +716,8 @@ func loadConfig() (*config, []string, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Check getwork keys are valid and saved parsed versions.
|
||||
cfg.miningAddrs = make([]btcutil.Address, 0, len(cfg.GetWorkKeys)+
|
||||
len(cfg.MiningAddrs))
|
||||
for _, strAddr := range cfg.GetWorkKeys {
|
||||
addr, err := btcutil.DecodeAddress(strAddr,
|
||||
activeNetParams.Params)
|
||||
if err != nil {
|
||||
str := "%s: getworkkey '%s' failed to decode: %v"
|
||||
err := fmt.Errorf(str, funcName, strAddr, err)
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
fmt.Fprintln(os.Stderr, usageMessage)
|
||||
return nil, nil, err
|
||||
}
|
||||
if !addr.IsForNet(activeNetParams.Params) {
|
||||
str := "%s: getworkkey '%s' is on the wrong network"
|
||||
err := fmt.Errorf(str, funcName, strAddr)
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
fmt.Fprintln(os.Stderr, usageMessage)
|
||||
return nil, nil, err
|
||||
}
|
||||
cfg.miningAddrs = append(cfg.miningAddrs, addr)
|
||||
}
|
||||
|
||||
// Check mining addresses are valid and saved parsed versions.
|
||||
cfg.miningAddrs = make([]btcutil.Address, 0, len(cfg.MiningAddrs))
|
||||
for _, strAddr := range cfg.MiningAddrs {
|
||||
addr, err := btcutil.DecodeAddress(strAddr, activeNetParams.Params)
|
||||
if err != nil {
|
||||
|
|
3
doc.go
3
doc.go
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -106,7 +106,6 @@ Application Options:
|
|||
a block (750000)
|
||||
--blockprioritysize= Size in bytes for high-priority/low-fee transactions
|
||||
when creating a block (50000)
|
||||
--getworkkey= DEPRECATED -- Use the --miningaddr option instead
|
||||
--nopeerbloomfilters Disable bloom filtering support.
|
||||
--sigcachemaxsize= The maximum number of entries in the signature
|
||||
verification cache.
|
||||
|
|
|
@ -155,9 +155,8 @@ For a list of available options, run: `$ btcctl --help`
|
|||
|
||||
<a name="Mining" />
|
||||
**2.4 Mining**<br />
|
||||
btcd supports both the `getwork` and `getblocktemplate` RPCs although the
|
||||
`getwork` RPC is deprecated and will likely be removed in a future release.
|
||||
The limited user cannot access these RPCs.<br />
|
||||
btcd supports the `getblocktemplate` RPC.
|
||||
The limited user cannot access this RPC.<br />
|
||||
|
||||
**1. Add the payment addresses with the `miningaddr` option.**<br />
|
||||
|
||||
|
|
|
@ -170,15 +170,14 @@ the method name for further details such as parameter and return information.
|
|||
|20|[getpeerinfo](#getpeerinfo)|N|Returns information about each connected network peer as an array of json objects.|
|
||||
|21|[getrawmempool](#getrawmempool)|Y|Returns an array of hashes for all of the transactions currently in the memory pool.|
|
||||
|22|[getrawtransaction](#getrawtransaction)|Y|Returns information about a transaction given its hash.|
|
||||
|23|[getwork](#getwork)|N|Returns formatted hash data to work on or checks and submits solved data.<br /><font color="orange">NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.</font>|
|
||||
|24|[help](#help)|Y|Returns a list of all commands or help for a specified command.|
|
||||
|25|[ping](#ping)|N|Queues a ping to be sent to each connected peer.|
|
||||
|26|[sendrawtransaction](#sendrawtransaction)|Y|Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.<br /><font color="orange">btcd does not yet implement the `allowhighfees` parameter, so it has no effect</font>|
|
||||
|27|[setgenerate](#setgenerate) |N|Set the server to generate coins (mine) or not.<br/>NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.|
|
||||
|28|[stop](#stop)|N|Shutdown btcd.|
|
||||
|29|[submitblock](#submitblock)|Y|Attempts to submit a new serialized, hex-encoded block to the network.|
|
||||
|30|[validateaddress](#validateaddress)|Y|Verifies the given address is valid. NOTE: Since btcd does not have a wallet integrated, btcd will only return whether the address is valid or not.|
|
||||
|31|[verifychain](#verifychain)|N|Verifies the block chain database.|
|
||||
|23|[help](#help)|Y|Returns a list of all commands or help for a specified command.|
|
||||
|24|[ping](#ping)|N|Queues a ping to be sent to each connected peer.|
|
||||
|25|[sendrawtransaction](#sendrawtransaction)|Y|Submits the serialized, hex-encoded transaction to the local peer and relays it to the network.<br /><font color="orange">btcd does not yet implement the `allowhighfees` parameter, so it has no effect</font>|
|
||||
|26|[setgenerate](#setgenerate) |N|Set the server to generate coins (mine) or not.<br/>NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.|
|
||||
|27|[stop](#stop)|N|Shutdown btcd.|
|
||||
|28|[submitblock](#submitblock)|Y|Attempts to submit a new serialized, hex-encoded block to the network.|
|
||||
|29|[validateaddress](#validateaddress)|Y|Verifies the given address is valid. NOTE: Since btcd does not have a wallet integrated, btcd will only return whether the address is valid or not.|
|
||||
|30|[verifychain](#verifychain)|N|Verifies the block chain database.|
|
||||
|
||||
<a name="MethodDetails" />
|
||||
**5.2 Method Details**<br />
|
||||
|
@ -442,21 +441,6 @@ Example Return|`{`<br /> `"bytes": 310768,`<br /> `"size":
|
|||
|Example Return (verbose=1)|`{`<br /> `"hex": "01000000010000000000000000000000000000000000000000000000000000000000000000f...",`<br /> `"txid": "90743aad855880e517270550d2a881627d84db5265142fd1e7fb7add38b08be9",`<br /> `"version": 1,`<br /> `"locktime": 0,`<br /> `"vin": [`<br /> <font color="orange">For coinbase transactions:</font><br /> `{ (json object)`<br /> `"coinbase": "03708203062f503253482f04066d605108f800080100000ea2122f6f7a636f696e4065757374726174756d2f",`<br /> `"sequence": 0,`<br /> `}`<br /> <font color="orange">For non-coinbase transactions:</font><br /> `{`<br /> `"txid": "60ac4b057247b3d0b9a8173de56b5e1be8c1d1da970511c626ef53706c66be04",`<br /> `"vout": 0,`<br /> `"scriptSig": {`<br /> `"asm": "3046022100cb42f8df44eca83dd0a727988dcde9384953e830b1f8004d57485e2ede1b9c8f0...",`<br /> `"hex": "493046022100cb42f8df44eca83dd0a727988dcde9384953e830b1f8004d57485e2ede1b9c8...",`<br /> `}`<br /> `"sequence": 4294967295,`<br /> `}`<br /> `]`<br /> `"vout": [`<br /> `{`<br /> `"value": 25.1394,`<br /> `"n": 0,`<br /> `"scriptPubKey": {`<br /> `"asm": "OP_DUP OP_HASH160 ea132286328cfc819457b9dec386c4b5c84faa5c OP_EQUALVERIFY OP_CHECKSIG",`<br /> `"hex": "76a914ea132286328cfc819457b9dec386c4b5c84faa5c88ac",`<br /> `"reqSigs": 1,`<br /> `"type": "pubkeyhash"`<br /> `"addresses": [`<br /> `"1NLg3QJMsMQGM5KEUaEu5ADDmKQSLHwmyh",`<br /> `]`<br /> `}`<br /> `}`<br /> `]`<br />`}`|
|
||||
[Return to Overview](#MethodOverview)<br />
|
||||
|
||||
***
|
||||
<a name="getwork"/>
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
|Method|getwork|
|
||||
|Parameters|1. data (string, optional) - The hex|
|
||||
|Description|Returns information about a transaction given its hash.|
|
||||
|Notes|<font color="orange">NOTE: Since btcd does not have the wallet integrated to provide payment addresses, btcd must be configured via the `--miningaddr` option to provide which payment addresses to pay created blocks to for this RPC to function.</font>
|
||||
|Returns (data not specified)|`{ (json object)`<br /> `"data": "hex", (string) hex-encoded block data`<br /> `"hash1": "hex", (string) (DEPRECATED) hex-encoded formatted hash buffer`<br /> `"midstate": "hex", (string) (DEPRECATED) hex-encoded precomputed hash state after hashing first half of the data`<br /> `"target": "hex", (string) the hex-encoded little-endian hash target`<br />`}`|
|
||||
|Returns (data specified)|`true` or `false` (boolean)|
|
||||
|Example Return (data not specified)|`{`<br /> `"data": "00000002c39b5d2b7a1e8f7356a1efce26b24bd15d7d906e85341ef9cec99b6a000000006474f...",`<br /> `"hash1": "00000000000000000000000000000000000000000000000000000000000000000000008000000...",`<br /> `"midstate": "ae4a80fc51476e452de855b4e20d5f33418c50fc7cae3b1ecd5badb819b8a584",`<br /> `"target": "0000000000000000000000000000000000000000000000008c96010000000000",`<br />`}`|
|
||||
|Example Return (data specified)|`true`|
|
||||
[Return to Overview](#MethodOverview)<br />
|
||||
|
||||
***
|
||||
<a name="help"/>
|
||||
|
||||
|
|
12
glide.lock
generated
12
glide.lock
generated
|
@ -1,21 +1,19 @@
|
|||
hash: ebeea81fdd8ab49cce0e295ae834f8fbb0fb6e1b8e618a5059aceff477ef6596
|
||||
updated: 2016-12-09T12:53:49.172263045-05:00
|
||||
hash: 3483e97fe9cd4e2c998f05ca648ce21767e1a4b955919aeffbc6bfe87d9b0648
|
||||
updated: 2017-01-11T09:52:36.894361964-05:00
|
||||
imports:
|
||||
- name: github.com/btcsuite/btclog
|
||||
version: 73889fb79bd687870312b6e40effcecffbd57d30
|
||||
- name: github.com/btcsuite/btcrpcclient
|
||||
version: 7903290fd9956021ed7b65463f8667df345b365e
|
||||
version: 5ce0ed600997eafaed25ad4936c1d84ec6ad2b5a
|
||||
- name: github.com/btcsuite/btcutil
|
||||
version: 96e858f48ed95f9245e765d98be0ee01176409c7
|
||||
version: bca6409ade96981b0e77a2a7d358be53b340a1a7
|
||||
subpackages:
|
||||
- .
|
||||
- base58
|
||||
- bloom
|
||||
- hdkeychain
|
||||
- name: github.com/btcsuite/fastsha256
|
||||
version: 637e656429416087660c84436a2a035d69d54e2e
|
||||
- name: github.com/btcsuite/go-socks
|
||||
version: cfe8b59e565c1a5bd4e2005d77cd9aa8b2e14524
|
||||
version: 4720035b7bfd2a9bb130b1c184f8bbe41b6f0d0f
|
||||
subpackages:
|
||||
- socks
|
||||
- name: github.com/btcsuite/golangcrypto
|
||||
|
|
|
@ -8,7 +8,6 @@ import:
|
|||
- base58
|
||||
- hdkeychain
|
||||
- package: github.com/btcsuite/btcrpcclient
|
||||
- package: github.com/btcsuite/fastsha256
|
||||
- package: github.com/btcsuite/go-socks
|
||||
subpackages:
|
||||
- socks
|
||||
|
|
415
rpcserver.go
415
rpcserver.go
|
@ -7,10 +7,10 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
@ -39,7 +39,6 @@ import (
|
|||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/fastsha256"
|
||||
"github.com/btcsuite/websocket"
|
||||
)
|
||||
|
||||
|
@ -61,23 +60,6 @@ const (
|
|||
// 256-bit integer.
|
||||
uint256Size = 32
|
||||
|
||||
// getworkDataLen is the length of the data field of the getwork RPC.
|
||||
// It consists of the serialized block header plus the internal sha256
|
||||
// padding. The internal sha256 padding consists of a single 1 bit
|
||||
// followed by enough zeros to pad the message out to 56 bytes followed
|
||||
// by length of the message in bits encoded as a big-endian uint64
|
||||
// (8 bytes). Thus, the resulting length is a multiple of the sha256
|
||||
// block size (64 bytes).
|
||||
getworkDataLen = (1 + ((wire.MaxBlockHeaderPayload + 8) /
|
||||
fastsha256.BlockSize)) * fastsha256.BlockSize
|
||||
|
||||
// hash1Len is the length of the hash1 field of the getwork RPC. It
|
||||
// consists of a zero hash plus the internal sha256 padding. See
|
||||
// the getworkDataLen comment for details about the internal sha256
|
||||
// padding format.
|
||||
hash1Len = (1 + ((chainhash.HashSize + 8) / fastsha256.BlockSize)) *
|
||||
fastsha256.BlockSize
|
||||
|
||||
// gbtNonceRange is two 32-bit big-endian hexadecimal integers which
|
||||
// represent the valid ranges of nonces returned by the getblocktemplate
|
||||
// RPC.
|
||||
|
@ -173,7 +155,6 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
|
|||
"getrawmempool": handleGetRawMempool,
|
||||
"getrawtransaction": handleGetRawTransaction,
|
||||
"gettxout": handleGetTxOut,
|
||||
"getwork": handleGetWork,
|
||||
"help": handleHelp,
|
||||
"node": handleNode,
|
||||
"ping": handlePing,
|
||||
|
@ -242,6 +223,7 @@ var rpcUnimplemented = map[string]struct{}{
|
|||
"estimatepriority": {},
|
||||
"getchaintips": {},
|
||||
"getnetworkinfo": {},
|
||||
"getwork": {},
|
||||
"invalidateblock": {},
|
||||
"preciousblock": {},
|
||||
"reconsiderblock": {},
|
||||
|
@ -329,33 +311,6 @@ func rpcNoTxInfoError(txHash *chainhash.Hash) *btcjson.RPCError {
|
|||
txHash))
|
||||
}
|
||||
|
||||
// workStateBlockInfo houses information about how to reconstruct a block given
|
||||
// its template and signature script.
|
||||
type workStateBlockInfo struct {
|
||||
msgBlock *wire.MsgBlock
|
||||
signatureScript []byte
|
||||
}
|
||||
|
||||
// workState houses state that is used in between multiple RPC invocations to
|
||||
// getwork.
|
||||
type workState struct {
|
||||
sync.Mutex
|
||||
lastTxUpdate time.Time
|
||||
lastGenerated time.Time
|
||||
prevHash *chainhash.Hash
|
||||
msgBlock *wire.MsgBlock
|
||||
extraNonce uint64
|
||||
blockInfo map[chainhash.Hash]*workStateBlockInfo
|
||||
}
|
||||
|
||||
// newWorkState returns a new instance of a workState with all internal fields
|
||||
// initialized and ready to use.
|
||||
func newWorkState() *workState {
|
||||
return &workState{
|
||||
blockInfo: make(map[chainhash.Hash]*workStateBlockInfo),
|
||||
}
|
||||
}
|
||||
|
||||
// gbtWorkState houses state that is used in between multiple RPC invocations to
|
||||
// getblocktemplate.
|
||||
type gbtWorkState struct {
|
||||
|
@ -2590,41 +2545,6 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str
|
|||
return *rawTxn, nil
|
||||
}
|
||||
|
||||
// bigToLEUint256 returns the passed big integer as an unsigned 256-bit integer
|
||||
// encoded as little-endian bytes. Numbers which are larger than the max
|
||||
// unsigned 256-bit integer are truncated.
|
||||
func bigToLEUint256(n *big.Int) [uint256Size]byte {
|
||||
// Pad or truncate the big-endian big int to correct number of bytes.
|
||||
nBytes := n.Bytes()
|
||||
nlen := len(nBytes)
|
||||
pad := 0
|
||||
start := 0
|
||||
if nlen <= uint256Size {
|
||||
pad = uint256Size - nlen
|
||||
} else {
|
||||
start = nlen - uint256Size
|
||||
}
|
||||
var buf [uint256Size]byte
|
||||
copy(buf[pad:], nBytes[start:])
|
||||
|
||||
// Reverse the bytes to little endian and return them.
|
||||
for i := 0; i < uint256Size/2; i++ {
|
||||
buf[i], buf[uint256Size-1-i] = buf[uint256Size-1-i], buf[i]
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// reverseUint32Array treats the passed bytes as a series of uint32s and
|
||||
// reverses the byte order of each uint32. The passed byte slice must be a
|
||||
// multiple of 4 for a correct result. The passed bytes slice is modified.
|
||||
func reverseUint32Array(b []byte) {
|
||||
blen := len(b)
|
||||
for i := 0; i < blen; i += 4 {
|
||||
b[i], b[i+3] = b[i+3], b[i]
|
||||
b[i+1], b[i+2] = b[i+2], b[i+1]
|
||||
}
|
||||
}
|
||||
|
||||
// handleGetTxOut handles gettxout commands.
|
||||
func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||
c := cmd.(*btcjson.GetTxOutCmd)
|
||||
|
@ -2734,325 +2654,6 @@ func handleGetTxOut(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i
|
|||
return txOutReply, nil
|
||||
}
|
||||
|
||||
// handleGetWorkRequest is a helper for handleGetWork which deals with
|
||||
// generating and returning work to the caller.
|
||||
//
|
||||
// This function MUST be called with the RPC workstate locked.
|
||||
func handleGetWorkRequest(s *rpcServer) (interface{}, error) {
|
||||
state := s.workState
|
||||
|
||||
// Generate a new block template when the current best block has
|
||||
// changed or the transactions in the memory pool have been updated
|
||||
// and it has been at least one minute since the last template was
|
||||
// generated.
|
||||
lastTxUpdate := s.server.txMemPool.LastUpdated()
|
||||
best := s.server.blockManager.chain.BestSnapshot()
|
||||
latestHash, latestHeight := best.Hash, best.Height
|
||||
msgBlock := state.msgBlock
|
||||
if msgBlock == nil || state.prevHash == nil ||
|
||||
!state.prevHash.IsEqual(latestHash) ||
|
||||
(state.lastTxUpdate != lastTxUpdate &&
|
||||
time.Now().After(state.lastGenerated.Add(time.Minute))) {
|
||||
|
||||
// Reset the extra nonce and clear all cached template
|
||||
// variations if the best block changed.
|
||||
if state.prevHash != nil && !state.prevHash.IsEqual(latestHash) {
|
||||
state.extraNonce = 0
|
||||
state.blockInfo = make(map[chainhash.Hash]*workStateBlockInfo)
|
||||
}
|
||||
|
||||
// Reset the previous best hash the block template was generated
|
||||
// against so any errors below cause the next invocation to try
|
||||
// again.
|
||||
state.prevHash = nil
|
||||
|
||||
// Choose a payment address at random.
|
||||
payToAddr := cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))]
|
||||
template, err := s.generator.NewBlockTemplate(payToAddr)
|
||||
if err != nil {
|
||||
context := "Failed to create new block template"
|
||||
return nil, internalRPCError(err.Error(), context)
|
||||
}
|
||||
msgBlock = template.Block
|
||||
|
||||
// Update work state to ensure another block template isn't
|
||||
// generated until needed.
|
||||
state.msgBlock = msgBlock
|
||||
state.lastGenerated = time.Now()
|
||||
state.lastTxUpdate = lastTxUpdate
|
||||
state.prevHash = latestHash
|
||||
|
||||
rpcsLog.Debugf("Generated block template (timestamp %v, extra "+
|
||||
"nonce %d, target %064x, merkle root %s, signature "+
|
||||
"script %x)", msgBlock.Header.Timestamp,
|
||||
state.extraNonce,
|
||||
blockchain.CompactToBig(msgBlock.Header.Bits),
|
||||
msgBlock.Header.MerkleRoot,
|
||||
msgBlock.Transactions[0].TxIn[0].SignatureScript)
|
||||
} else {
|
||||
// At this point, there is a saved block template and a new
|
||||
// request for work was made, but either the available
|
||||
// transactions haven't change or it hasn't been long enough to
|
||||
// trigger a new block template to be generated. So, update the
|
||||
// existing block template and track the variations so each
|
||||
// variation can be regenerated if a caller finds an answer and
|
||||
// makes a submission against it.
|
||||
|
||||
// Update the time of the block template to the current time
|
||||
// while accounting for the median time of the past several
|
||||
// blocks per the chain consensus rules.
|
||||
s.generator.UpdateBlockTime(msgBlock)
|
||||
|
||||
// Increment the extra nonce and update the block template
|
||||
// with the new value by regenerating the coinbase script and
|
||||
// setting the merkle root to the new value.
|
||||
state.extraNonce++
|
||||
err := s.generator.UpdateExtraNonce(msgBlock, latestHeight+1,
|
||||
state.extraNonce)
|
||||
if err != nil {
|
||||
errStr := fmt.Sprintf("Failed to update extra nonce: "+
|
||||
"%v", err)
|
||||
return nil, internalRPCError(errStr, "")
|
||||
}
|
||||
|
||||
rpcsLog.Debugf("Updated block template (timestamp %v, extra "+
|
||||
"nonce %d, target %064x, merkle root %s, signature "+
|
||||
"script %x)", msgBlock.Header.Timestamp,
|
||||
state.extraNonce,
|
||||
blockchain.CompactToBig(msgBlock.Header.Bits),
|
||||
msgBlock.Header.MerkleRoot,
|
||||
msgBlock.Transactions[0].TxIn[0].SignatureScript)
|
||||
}
|
||||
|
||||
// In order to efficiently store the variations of block templates that
|
||||
// have been provided to callers, save a pointer to the block as well as
|
||||
// the modified signature script keyed by the merkle root. This
|
||||
// information, along with the data that is included in a work
|
||||
// submission, is used to rebuild the block before checking the
|
||||
// submitted solution.
|
||||
coinbaseTx := msgBlock.Transactions[0]
|
||||
state.blockInfo[msgBlock.Header.MerkleRoot] = &workStateBlockInfo{
|
||||
msgBlock: msgBlock,
|
||||
signatureScript: coinbaseTx.TxIn[0].SignatureScript,
|
||||
}
|
||||
|
||||
// Serialize the block header into a buffer large enough to hold the
|
||||
// the block header and the internal sha256 padding that is added and
|
||||
// retuned as part of the data below.
|
||||
data := make([]byte, 0, getworkDataLen)
|
||||
buf := bytes.NewBuffer(data)
|
||||
err := msgBlock.Header.Serialize(buf)
|
||||
if err != nil {
|
||||
errStr := fmt.Sprintf("Failed to serialize data: %v", err)
|
||||
return nil, internalRPCError(errStr, "")
|
||||
}
|
||||
|
||||
// Calculate the midstate for the block header. The midstate here is
|
||||
// the internal state of the sha256 algorithm for the first chunk of the
|
||||
// block header (sha256 operates on 64-byte chunks) which is before the
|
||||
// nonce. This allows sophisticated callers to avoid hashing the first
|
||||
// chunk over and over while iterating the nonce range.
|
||||
data = data[:buf.Len()]
|
||||
midstate := fastsha256.MidState256(data)
|
||||
|
||||
// Expand the data slice to include the full data buffer and apply the
|
||||
// internal sha256 padding which consists of a single 1 bit followed
|
||||
// by enough zeros to pad the message out to 56 bytes followed by the
|
||||
// length of the message in bits encoded as a big-endian uint64
|
||||
// (8 bytes). Thus, the resulting length is a multiple of the sha256
|
||||
// block size (64 bytes). This makes the data ready for sophisticated
|
||||
// caller to make use of only the second chunk along with the midstate
|
||||
// for the first chunk.
|
||||
data = data[:getworkDataLen]
|
||||
data[wire.MaxBlockHeaderPayload] = 0x80
|
||||
binary.BigEndian.PutUint64(data[len(data)-8:],
|
||||
wire.MaxBlockHeaderPayload*8)
|
||||
|
||||
// Create the hash1 field which is a zero hash along with the internal
|
||||
// sha256 padding as described above. This field is really quite
|
||||
// useless, but it is required for compatibility with the reference
|
||||
// implementation.
|
||||
var hash1 [hash1Len]byte
|
||||
hash1[chainhash.HashSize] = 0x80
|
||||
binary.BigEndian.PutUint64(hash1[len(hash1)-8:], chainhash.HashSize*8)
|
||||
|
||||
// The final result reverses each of the fields to little endian.
|
||||
// In particular, the data, hash1, and midstate fields are treated as
|
||||
// arrays of uint32s (per the internal sha256 hashing state) which are
|
||||
// in big endian, and thus each 4 bytes is byte swapped. The target is
|
||||
// also in big endian, but it is treated as a uint256 and byte swapped
|
||||
// to little endian accordingly.
|
||||
//
|
||||
// The fact the fields are reversed in this way is rather odd and likey
|
||||
// an artifact of some legacy internal state in the reference
|
||||
// implementation, but it is required for compatibility.
|
||||
reverseUint32Array(data)
|
||||
reverseUint32Array(hash1[:])
|
||||
reverseUint32Array(midstate[:])
|
||||
target := bigToLEUint256(blockchain.CompactToBig(msgBlock.Header.Bits))
|
||||
reply := &btcjson.GetWorkResult{
|
||||
Data: hex.EncodeToString(data),
|
||||
Hash1: hex.EncodeToString(hash1[:]),
|
||||
Midstate: hex.EncodeToString(midstate[:]),
|
||||
Target: hex.EncodeToString(target[:]),
|
||||
}
|
||||
return reply, nil
|
||||
}
|
||||
|
||||
// handleGetWorkSubmission is a helper for handleGetWork which deals with
|
||||
// the calling submitting work to be verified and processed.
|
||||
//
|
||||
// This function MUST be called with the RPC workstate locked.
|
||||
func handleGetWorkSubmission(s *rpcServer, hexData string) (interface{}, error) {
|
||||
// Ensure the provided data is sane.
|
||||
if len(hexData)%2 != 0 {
|
||||
hexData = "0" + hexData
|
||||
}
|
||||
data, err := hex.DecodeString(hexData)
|
||||
if err != nil {
|
||||
return false, rpcDecodeHexError(hexData)
|
||||
}
|
||||
if len(data) != getworkDataLen {
|
||||
return false, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInvalidParameter,
|
||||
Message: fmt.Sprintf("Argument must be "+
|
||||
"%d bytes (not %d)", getworkDataLen,
|
||||
len(data)),
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the data as if it were an array of 32-bit unsigned integers.
|
||||
// The fact the getwork request and submission data is reversed in this
|
||||
// way is rather odd and likey an artifact of some legacy internal state
|
||||
// in the reference implementation, but it is required for
|
||||
// compatibility.
|
||||
reverseUint32Array(data)
|
||||
|
||||
// Deserialize the block header from the data.
|
||||
var submittedHeader wire.BlockHeader
|
||||
bhBuf := bytes.NewReader(data[0:wire.MaxBlockHeaderPayload])
|
||||
err = submittedHeader.Deserialize(bhBuf)
|
||||
if err != nil {
|
||||
return false, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInvalidParameter,
|
||||
Message: fmt.Sprintf("Argument does not "+
|
||||
"contain a valid block header: %v", err),
|
||||
}
|
||||
}
|
||||
|
||||
// Look up the full block for the provided data based on the
|
||||
// merkle root. Return false to indicate the solve failed if
|
||||
// it's not available.
|
||||
state := s.workState
|
||||
blockInfo, ok := state.blockInfo[submittedHeader.MerkleRoot]
|
||||
if !ok {
|
||||
rpcsLog.Debugf("Block submitted via getwork has no matching "+
|
||||
"template for merkle root %s",
|
||||
submittedHeader.MerkleRoot)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Reconstruct the block using the submitted header stored block info.
|
||||
msgBlock := blockInfo.msgBlock
|
||||
block := btcutil.NewBlock(msgBlock)
|
||||
msgBlock.Header.Timestamp = submittedHeader.Timestamp
|
||||
msgBlock.Header.Nonce = submittedHeader.Nonce
|
||||
msgBlock.Transactions[0].TxIn[0].SignatureScript = blockInfo.signatureScript
|
||||
merkles := blockchain.BuildMerkleTreeStore(block.Transactions())
|
||||
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
|
||||
|
||||
// Ensure the submitted block hash is less than the target difficulty.
|
||||
err = blockchain.CheckProofOfWork(block, activeNetParams.PowLimit)
|
||||
if err != nil {
|
||||
// Anything other than a rule violation is an unexpected error,
|
||||
// so return that error as an internal error.
|
||||
if _, ok := err.(blockchain.RuleError); !ok {
|
||||
return false, internalRPCError("Unexpected error "+
|
||||
"while checking proof of work: "+err.Error(),
|
||||
"")
|
||||
}
|
||||
|
||||
rpcsLog.Debugf("Block submitted via getwork does not meet "+
|
||||
"the required proof of work: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
latestHash := s.server.blockManager.chain.BestSnapshot().Hash
|
||||
if !msgBlock.Header.PrevBlock.IsEqual(latestHash) {
|
||||
rpcsLog.Debugf("Block submitted via getwork with previous "+
|
||||
"block %s is stale", msgBlock.Header.PrevBlock)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Process this block using the same rules as blocks coming from other
|
||||
// nodes. This will in turn relay it to the network like normal.
|
||||
isOrphan, err := s.server.blockManager.ProcessBlock(block, blockchain.BFNone)
|
||||
if err != nil || isOrphan {
|
||||
// Anything other than a rule violation is an unexpected error,
|
||||
// so return that error as an internal error.
|
||||
if _, ok := err.(blockchain.RuleError); !ok {
|
||||
return false, internalRPCError("Unexpected error "+
|
||||
"while processing block: "+err.Error(), "")
|
||||
}
|
||||
|
||||
rpcsLog.Infof("Block submitted via getwork rejected: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// The block was accepted.
|
||||
rpcsLog.Infof("Block submitted via getwork accepted: %s", block.Hash())
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// handleGetWork implements the getwork command.
|
||||
func handleGetWork(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||
c := cmd.(*btcjson.GetWorkCmd)
|
||||
|
||||
// Respond with an error if there are no addresses to pay the created
|
||||
// blocks to.
|
||||
if len(cfg.miningAddrs) == 0 {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInternal.Code,
|
||||
Message: "No payment addresses specified via --miningaddr",
|
||||
}
|
||||
}
|
||||
|
||||
// Return an error if there are no peers connected since there is no
|
||||
// way to relay a found block or receive transactions to work on.
|
||||
// However, allow this state when running in the regression test or
|
||||
// simulation test mode.
|
||||
if !(cfg.RegressionTest || cfg.SimNet) && s.server.ConnectedCount() == 0 {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCClientNotConnected,
|
||||
Message: "Bitcoin is not connected",
|
||||
}
|
||||
}
|
||||
|
||||
// No point in generating or accepting work before the chain is synced.
|
||||
currentHeight := s.server.blockManager.chain.BestSnapshot().Height
|
||||
if currentHeight != 0 && !s.server.blockManager.IsCurrent() {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCClientInInitialDownload,
|
||||
Message: "Bitcoin is downloading blocks...",
|
||||
}
|
||||
}
|
||||
|
||||
// Protect concurrent access from multiple RPC invocations for work
|
||||
// requests and submission.
|
||||
s.workState.Lock()
|
||||
defer s.workState.Unlock()
|
||||
|
||||
// When the caller provides data, it is a submission of a supposedly
|
||||
// solved block that needs to be checked and submitted to the network
|
||||
// if valid.
|
||||
if c.Data != nil && *c.Data != "" {
|
||||
return handleGetWorkSubmission(s, *c.Data)
|
||||
}
|
||||
|
||||
// No data was provided, so the caller is requesting work.
|
||||
return handleGetWorkRequest(s)
|
||||
}
|
||||
|
||||
// handleHelp implements the help command.
|
||||
func handleHelp(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||
c := cmd.(*btcjson.HelpCmd)
|
||||
|
@ -3885,15 +3486,14 @@ type rpcServer struct {
|
|||
generator *mining.BlkTmplGenerator
|
||||
server *server
|
||||
chain *blockchain.BlockChain
|
||||
authsha [fastsha256.Size]byte
|
||||
limitauthsha [fastsha256.Size]byte
|
||||
authsha [sha256.Size]byte
|
||||
limitauthsha [sha256.Size]byte
|
||||
ntfnMgr *wsNotificationManager
|
||||
numClients int32
|
||||
statusLines map[int]string
|
||||
statusLock sync.RWMutex
|
||||
wg sync.WaitGroup
|
||||
listeners []net.Listener
|
||||
workState *workState
|
||||
gbtWorkState *gbtWorkState
|
||||
helpCacher *helpCacher
|
||||
requestProcessShutdown chan struct{}
|
||||
|
@ -4041,7 +3641,7 @@ func (s *rpcServer) checkAuth(r *http.Request, require bool) (bool, bool, error)
|
|||
return false, false, nil
|
||||
}
|
||||
|
||||
authsha := fastsha256.Sum256([]byte(authhdr[0]))
|
||||
authsha := sha256.Sum256([]byte(authhdr[0]))
|
||||
|
||||
// Check for limited auth first as in environments with limited users, those
|
||||
// are probably expected to have a higher volume of calls
|
||||
|
@ -4387,7 +3987,6 @@ func newRPCServer(listenAddrs []string, generator *mining.BlkTmplGenerator, s *s
|
|||
generator: generator,
|
||||
chain: s.blockManager.chain,
|
||||
statusLines: make(map[int]string),
|
||||
workState: newWorkState(),
|
||||
gbtWorkState: newGbtWorkState(s.timeSource),
|
||||
helpCacher: newHelpCacher(),
|
||||
requestProcessShutdown: make(chan struct{}),
|
||||
|
@ -4396,12 +3995,12 @@ func newRPCServer(listenAddrs []string, generator *mining.BlkTmplGenerator, s *s
|
|||
if cfg.RPCUser != "" && cfg.RPCPass != "" {
|
||||
login := cfg.RPCUser + ":" + cfg.RPCPass
|
||||
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login))
|
||||
rpc.authsha = fastsha256.Sum256([]byte(auth))
|
||||
rpc.authsha = sha256.Sum256([]byte(auth))
|
||||
}
|
||||
if cfg.RPCLimitUser != "" && cfg.RPCLimitPass != "" {
|
||||
login := cfg.RPCLimitUser + ":" + cfg.RPCLimitPass
|
||||
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login))
|
||||
rpc.limitauthsha = fastsha256.Sum256([]byte(auth))
|
||||
rpc.limitauthsha = sha256.Sum256([]byte(auth))
|
||||
}
|
||||
rpc.ntfnMgr = newWsNotificationManager(&rpc)
|
||||
|
||||
|
|
|
@ -470,19 +470,6 @@ var helpDescsEnUS = map[string]string{
|
|||
"gettxout-vout": "The index of the output",
|
||||
"gettxout-includemempool": "Include the mempool when true",
|
||||
|
||||
// GetWorkResult help.
|
||||
"getworkresult-data": "Hex-encoded block data",
|
||||
"getworkresult-hash1": "(DEPRECATED) Hex-encoded formatted hash buffer",
|
||||
"getworkresult-midstate": "(DEPRECATED) Hex-encoded precomputed hash state after hashing first half of the data",
|
||||
"getworkresult-target": "Hex-encoded little-endian hash target",
|
||||
|
||||
// GetWorkCmd help.
|
||||
"getwork--synopsis": "(DEPRECATED - Use getblocktemplate instead) Returns formatted hash data to work on or checks and submits solved data.",
|
||||
"getwork-data": "Hex-encoded data to check",
|
||||
"getwork--condition0": "no data provided",
|
||||
"getwork--condition1": "data provided",
|
||||
"getwork--result1": "Whether or not the solved data is valid and was added to the chain",
|
||||
|
||||
// HelpCmd help.
|
||||
"help--synopsis": "Returns a list of all commands or help for a specified command.",
|
||||
"help-command": "The command to retrieve help for",
|
||||
|
@ -662,7 +649,6 @@ var rpcResultTypes = map[string][]interface{}{
|
|||
"getrawmempool": {(*[]string)(nil), (*btcjson.GetRawMempoolVerboseResult)(nil)},
|
||||
"getrawtransaction": {(*string)(nil), (*btcjson.TxRawResult)(nil)},
|
||||
"gettxout": {(*btcjson.GetTxOutResult)(nil)},
|
||||
"getwork": {(*btcjson.GetWorkResult)(nil), (*bool)(nil)},
|
||||
"node": nil,
|
||||
"help": {(*string)(nil), (*string)(nil)},
|
||||
"ping": nil,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -7,6 +7,7 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
|
@ -25,7 +26,6 @@ import (
|
|||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/fastsha256"
|
||||
"github.com/btcsuite/golangcrypto/ripemd160"
|
||||
"github.com/btcsuite/websocket"
|
||||
)
|
||||
|
@ -1010,7 +1010,7 @@ out:
|
|||
// Check credentials.
|
||||
login := authCmd.Username + ":" + authCmd.Passphrase
|
||||
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login))
|
||||
authSha := fastsha256.Sum256([]byte(auth))
|
||||
authSha := sha256.Sum256([]byte(auth))
|
||||
cmp := subtle.ConstantTimeCompare(authSha[:], c.server.authsha[:])
|
||||
limitcmp := subtle.ConstantTimeCompare(authSha[:], c.server.limitauthsha[:])
|
||||
if cmp != 1 && limitcmp != 1 {
|
||||
|
|
|
@ -293,8 +293,8 @@
|
|||
; worth your while.
|
||||
; generate=false
|
||||
|
||||
; Add addresses to pay mined blocks to for CPU mining and the block templates
|
||||
; generated for the getwork RPC as desired. One address per line.
|
||||
; Add addresses to pay mined blocks to for CPU mining and potentially in the
|
||||
; block templates generated for the getblocktemplate RPC. One address per line.
|
||||
; miningaddr=1yourbitcoinaddress
|
||||
; miningaddr=1yourbitcoinaddress2
|
||||
; miningaddr=1yourbitcoinaddress3
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -7,6 +7,7 @@ package txscript
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -15,7 +16,6 @@ import (
|
|||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/fastsha256"
|
||||
"github.com/btcsuite/golangcrypto/ripemd160"
|
||||
)
|
||||
|
||||
|
@ -1890,7 +1890,7 @@ func opcodeSha256(op *parsedOpcode, vm *Engine) error {
|
|||
return err
|
||||
}
|
||||
|
||||
hash := fastsha256.Sum256(buf)
|
||||
hash := sha256.Sum256(buf)
|
||||
vm.dstack.PushByteArray(hash[:])
|
||||
return nil
|
||||
}
|
||||
|
@ -1905,7 +1905,7 @@ func opcodeHash160(op *parsedOpcode, vm *Engine) error {
|
|||
return err
|
||||
}
|
||||
|
||||
hash := fastsha256.Sum256(buf)
|
||||
hash := sha256.Sum256(buf)
|
||||
vm.dstack.PushByteArray(calcHash(hash[:], ripemd160.New()))
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue