Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd58e6f0ac | ||
|
|
dda8e8da6a | ||
|
|
291cb8ab51 | ||
|
|
598c36bcea | ||
|
|
69fd672ded | ||
|
|
9ed95d826e | ||
|
|
be7ee9217f | ||
|
|
a27ece8d0a | ||
|
|
dc454a1ca7 | ||
|
|
f455263950 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,4 +1,18 @@
|
||||
# Changelog
|
||||
## v1.2.8
|
||||
FEATURE
|
||||
* [\#1626](https://github.com/bnb-chain/bsc/pull/1626) eth/filters, ethclient/gethclient: add fullTx option to pending tx filter
|
||||
* [\#1726](https://github.com/bnb-chain/bsc/pull/1726) feat: support password flag when handling bls keys
|
||||
|
||||
BUGFIX
|
||||
* [\#1734](https://github.com/bnb-chain/bsc/pull/1734) fix: avoid to block the chain when failed to send votes
|
||||
|
||||
## v1.2.7
|
||||
FEATURE
|
||||
* [\#1645](https://github.com/bnb-chain/bsc/pull/1645) lightclient: fix validator set change
|
||||
* [\#1717](https://github.com/bnb-chain/bsc/pull/1717) feat: support creating a bls keystore from a specified private key
|
||||
* [\#1720](https://github.com/bnb-chain/bsc/pull/1720) metrics: add counter for voting status of whole network
|
||||
|
||||
## v1.2.6
|
||||
FEATURE
|
||||
* [\#1697](https://github.com/bnb-chain/bsc/pull/1697) upgrade: block height of Hertz(London&Berlin) on testnet
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/signer/core"
|
||||
)
|
||||
|
||||
@@ -35,7 +36,20 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
au = aurora.NewAurora(true)
|
||||
au = aurora.NewAurora(true)
|
||||
privateKeyFlag = &cli.StringFlag{
|
||||
Name: "private-key",
|
||||
Usage: "Hex string for the BLS12-381 private key you wish encrypt into a keystore file",
|
||||
Value: "",
|
||||
}
|
||||
showPrivateKeyFlag = &cli.BoolFlag{
|
||||
Name: "show-private-key",
|
||||
Usage: "Show the BLS12-381 private key you will encrypt into a keystore file",
|
||||
}
|
||||
BLSAccountPasswordFileFlag = cli.StringFlag{
|
||||
Name: "blsaccountpassword",
|
||||
Usage: "File path for the BLS account password, which contains the password to encrypt private key into keystore file for managing votes in fast_finality feature",
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -77,6 +91,7 @@ or import a BLS account. The BLS wallet dir should be "<DATADIR>/bls/wallet".`,
|
||||
Category: "BLS ACCOUNT COMMANDS",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.BLSPasswordFileFlag,
|
||||
},
|
||||
Description: `
|
||||
geth bls wallet create
|
||||
@@ -116,6 +131,10 @@ Make sure you backup your BLS keys regularly.`,
|
||||
Category: "BLS ACCOUNT COMMANDS",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
privateKeyFlag,
|
||||
showPrivateKeyFlag,
|
||||
utils.BLSPasswordFileFlag,
|
||||
BLSAccountPasswordFileFlag,
|
||||
},
|
||||
Description: `
|
||||
geth bls account new
|
||||
@@ -135,6 +154,8 @@ You must remember this password to unlock your account in the future.`,
|
||||
Category: "BLS ACCOUNT COMMANDS",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.BLSPasswordFileFlag,
|
||||
BLSAccountPasswordFileFlag,
|
||||
},
|
||||
Description: `
|
||||
geth bls account import <keyFile>
|
||||
@@ -151,6 +172,7 @@ If the BLS wallet not created yet, it will try to create BLS wallet first.`,
|
||||
Category: "BLS ACCOUNT COMMANDS",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.BLSPasswordFileFlag,
|
||||
},
|
||||
Description: `
|
||||
geth bls account list
|
||||
@@ -165,6 +187,7 @@ Print summary of existing BLS accounts in the current BLS wallet.`,
|
||||
Category: "BLS ACCOUNT COMMANDS",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.BLSPasswordFileFlag,
|
||||
},
|
||||
Description: `
|
||||
geth bls account delete
|
||||
@@ -197,7 +220,7 @@ func blsWalletCreate(ctx *cli.Context) error {
|
||||
utils.Fatalf("BLS wallet already exists in <DATADIR>/bls/wallet.")
|
||||
}
|
||||
|
||||
password := utils.GetPassPhrase("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true)
|
||||
password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, GetBLSPassword(ctx))
|
||||
|
||||
opts := []accounts.Option{}
|
||||
opts = append(opts, accounts.WithWalletDir(dir))
|
||||
@@ -227,7 +250,7 @@ func openOrCreateBLSWallet(ctx *cli.Context, cfg *gethConfig) (*wallet.Wallet, e
|
||||
}
|
||||
if !dirExists {
|
||||
fmt.Println("BLS wallet not exists, creating BLS wallet...")
|
||||
password := utils.GetPassPhrase("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true)
|
||||
password := utils.GetPassPhraseWithList("Your new BLS wallet will be locked with a password. Please give a password. Do not forget this password.", true, 0, GetBLSPassword(ctx))
|
||||
|
||||
opts := []accounts.Option{}
|
||||
opts = append(opts, accounts.WithWalletDir(walletDir))
|
||||
@@ -247,7 +270,7 @@ func openOrCreateBLSWallet(ctx *cli.Context, cfg *gethConfig) (*wallet.Wallet, e
|
||||
return w, nil
|
||||
}
|
||||
|
||||
walletPassword := utils.GetPassPhrase("Enter the password for your BLS wallet.", false)
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx))
|
||||
w, err = wallet.OpenWallet(context.Background(), &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
@@ -287,16 +310,35 @@ func blsAccountCreate(ctx *cli.Context) error {
|
||||
if err := os.MkdirAll(keystoreDir, 0755); err != nil {
|
||||
utils.Fatalf("Could not access keystore dir: %v.", err)
|
||||
}
|
||||
accountPassword := utils.GetPassPhrase("Your new BLS account will be encrypted with a password. Please give a password. Do not forget this password.", true)
|
||||
accountPassword := utils.GetPassPhraseWithList("Your new BLS account will be encrypted with a password. Please give a password. Do not forget this password.", true, 0, GetBLSAccountPassword(ctx))
|
||||
if err := core.ValidatePasswordFormat(accountPassword); err != nil {
|
||||
utils.Fatalf("Password invalid: %v.", err)
|
||||
}
|
||||
|
||||
encryptor := keystorev4.New()
|
||||
secretKey, err := bls.RandKey()
|
||||
if err != nil {
|
||||
privateKeyString := ctx.String(privateKeyFlag.Name)
|
||||
if privateKeyString != "" {
|
||||
if len(privateKeyString) > 2 && strings.Contains(privateKeyString, "0x") {
|
||||
privateKeyString = privateKeyString[2:] // Strip the 0x prefix, if any.
|
||||
}
|
||||
bytesValue, err := hex.DecodeString(privateKeyString)
|
||||
if err != nil {
|
||||
utils.Fatalf("could not decode as hex string: %s", privateKeyString)
|
||||
}
|
||||
secretKey, err = bls.SecretKeyFromBytes(bytesValue)
|
||||
if err != nil {
|
||||
utils.Fatalf("not a valid BLS12-381 private key")
|
||||
}
|
||||
} else if err != nil {
|
||||
utils.Fatalf("Could not generate BLS secret key: %v.", err)
|
||||
}
|
||||
|
||||
showPrivateKey := ctx.Bool(showPrivateKeyFlag.Name)
|
||||
if showPrivateKey {
|
||||
fmt.Printf("private key used: 0x%s\n", common.Bytes2Hex(secretKey.Marshal()))
|
||||
}
|
||||
|
||||
pubKeyBytes := secretKey.PublicKey().Marshal()
|
||||
cryptoFields, err := encryptor.Encrypt(secretKey.Marshal(), accountPassword)
|
||||
if err != nil {
|
||||
@@ -380,7 +422,8 @@ func blsAccountImport(ctx *cli.Context) error {
|
||||
utils.Fatalf("The BLS keymanager cannot import keystores")
|
||||
}
|
||||
|
||||
password := utils.GetPassPhrase("Enter the password for your imported account.", false)
|
||||
password := utils.GetPassPhraseWithList("Enter the password for your imported account.", false, 0, GetBLSAccountPassword(ctx))
|
||||
|
||||
fmt.Println("Importing BLS account, this may take a while...")
|
||||
statuses, err := accounts.ImportAccounts(context.Background(), &accounts.ImportAccountsConfig{
|
||||
Importer: k,
|
||||
@@ -416,7 +459,7 @@ func blsAccountList(ctx *cli.Context) error {
|
||||
utils.Fatalf("BLS wallet not exists.")
|
||||
}
|
||||
|
||||
walletPassword := utils.GetPassPhrase("Enter the password for your BLS wallet.", false)
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx))
|
||||
w, err := wallet.OpenWallet(context.Background(), &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
@@ -495,7 +538,7 @@ func blsAccountDelete(ctx *cli.Context) error {
|
||||
utils.Fatalf("BLS wallet not exists.")
|
||||
}
|
||||
|
||||
walletPassword := utils.GetPassPhrase("Enter the password for your BLS wallet.", false)
|
||||
walletPassword := utils.GetPassPhraseWithList("Enter the password for your BLS wallet.", false, 0, GetBLSPassword(ctx))
|
||||
w, err := wallet.OpenWallet(context.Background(), &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
@@ -556,3 +599,27 @@ func blsAccountDelete(ctx *cli.Context) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetBLSPassword(ctx *cli.Context) []string {
|
||||
path := ctx.GlobalString(utils.BLSPasswordFileFlag.Name)
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
text, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read wallet password file: %v", err)
|
||||
}
|
||||
return []string{string(text)}
|
||||
}
|
||||
|
||||
func GetBLSAccountPassword(ctx *cli.Context) []string {
|
||||
path := ctx.String(BLSAccountPasswordFileFlag.Name)
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
text, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read account password file: %v", err)
|
||||
}
|
||||
return []string{string(text)}
|
||||
}
|
||||
|
||||
@@ -1249,6 +1249,7 @@ func (p *Parlia) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteE
|
||||
if addr == p.val {
|
||||
validVotesfromSelfCounter.Inc(1)
|
||||
}
|
||||
metrics.GetOrRegisterCounter(fmt.Sprintf("parlia/VerifyVote/%s", addr.String()), nil).Inc(1)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ var PrecompiledContractsHertz = map[common.Address]PrecompiledContract{
|
||||
common.BytesToAddress([]byte{100}): &tmHeaderValidate{},
|
||||
common.BytesToAddress([]byte{101}): &iavlMerkleProofValidatePlato{},
|
||||
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
|
||||
common.BytesToAddress([]byte{103}): &cometBFTLightBlockValidate{},
|
||||
common.BytesToAddress([]byte{103}): &cometBFTLightBlockValidateHertz{},
|
||||
}
|
||||
|
||||
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
|
||||
|
||||
@@ -360,7 +360,7 @@ func (c *cometBFTLightBlockValidate) RequiredGas(input []byte) uint64 {
|
||||
return params.CometBFTLightBlockValidateGas
|
||||
}
|
||||
|
||||
func (c *cometBFTLightBlockValidate) Run(input []byte) (result []byte, err error) {
|
||||
func (c *cometBFTLightBlockValidate) run(input []byte, isHertz bool) (result []byte, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("internal error: %v\n", r)
|
||||
@@ -372,7 +372,7 @@ func (c *cometBFTLightBlockValidate) Run(input []byte) (result []byte, err error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
validatorSetChanged, err := cs.ApplyLightBlock(block)
|
||||
validatorSetChanged, err := cs.ApplyLightBlock(block, isHertz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -385,3 +385,15 @@ func (c *cometBFTLightBlockValidate) Run(input []byte) (result []byte, err error
|
||||
result = v2.EncodeLightBlockValidationResult(validatorSetChanged, consensusStateBytes)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *cometBFTLightBlockValidate) Run(input []byte) (result []byte, err error) {
|
||||
return c.run(input, false)
|
||||
}
|
||||
|
||||
type cometBFTLightBlockValidateHertz struct {
|
||||
cometBFTLightBlockValidate
|
||||
}
|
||||
|
||||
func (c *cometBFTLightBlockValidateHertz) Run(input []byte) (result []byte, err error) {
|
||||
return c.run(input, true)
|
||||
}
|
||||
|
||||
@@ -360,3 +360,16 @@ func TestCometBFTLightBlockValidate(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectOutputStr, hex.EncodeToString(res))
|
||||
}
|
||||
|
||||
func TestCometBFTLightBlockValidateHertz(t *testing.T) {
|
||||
inputStr := "000000000000000000000000000000000000000000000000000000000000018c677265656e6669656c645f393030302d3132310000000000000000000000000000000000000000013c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb40e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e8423000000000098968015154514f68ce65a0d9eecc578c0ab12da0a2a28a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b0000000000989680432f6c4908a9aa5f3444421f466b11645235c99b831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b0a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a0000000000989680864cb9828254d712f8e59b164fc6a9402dc4e6c59065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca0aeb060adb030a02080b1213677265656e6669656c645f393030302d3132311802220c08b2d7f3a10610e8d2adb3032a480a20ec6ecb5db4ffb17fabe40c60ca7b8441e9c5d77585d0831186f3c37aa16e9c15122408011220a2ab9e1eb9ea52812f413526e424b326aff2f258a56e00d690db9f805b60fe7e32200f40aeff672e8309b7b0aefbb9a1ae3d4299b5c445b7d54e8ff398488467f0053a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85542203c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb404a203c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb405220294d8fbd0b94b767a7eba9840f299a3586da7fe6b5dead3b7eecba193c400f935a20bc50557c12d7392b0d07d75df0b61232d48f86a74fdea6d1485d9be6317d268c6220e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85572146699336aa109d1beab3946198c8e59f3b2cbd92f7a4065e3cd89e315ca39d87dee92835b98f8b8ec0861d6d9bb2c60156df5d375b3ceb1fbe71af6a244907d62548a694165caa660fec7a9b4e7b9198191361c71be0b128a0308021a480a20726abd0fdbfb6f779b0483e6e4b4b6f12241f6ea2bf374233ab1a316692b6415122408011220159f10ff15a8b58fc67a92ffd7f33c8cd407d4ce81b04ca79177dfd00ca19a67226808021214050cff76cc632760ba9db796c046004c900967361a0c08b3d7f3a10610808cadba03224080713027ffb776a702d78fd0406205c629ba473e1f8d6af646190f6eb9262cd67d69be90d10e597b91e06d7298eb6fa4b8f1eb7752ebf352a1f51560294548042268080212146699336aa109d1beab3946198c8e59f3b2cbd92f1a0c08b3d7f3a10610b087c1c00322405e2ddb70acfe4904438be3d9f4206c0ace905ac4fc306a42cfc9e86268950a0fbfd6ec5f526d3e41a3ef52bf9f9f358e3cb4c3feac76c762fa3651c1244fe004226808021214c55765fd2d0570e869f6ac22e7f2916a35ea300d1a0c08b3d7f3a10610f0b3d492032240ca17898bd22232fc9374e1188636ee321a396444a5b1a79f7628e4a11f265734b2ab50caf21e8092c55d701248e82b2f011426cb35ba22043b497a6b4661930612a0050aa8010a14050cff76cc632760ba9db796c046004c9009673612220a20e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e84231880ade2042080a6bbf6ffffffffff012a30a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86321415154514f68ce65a0d9eecc578c0ab12da0a2a283a14ee7a2a6a44d427f6949eeb8f12ea9fbb2501da880aa2010a146699336aa109d1beab3946198c8e59f3b2cbd92f12220a20451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b1880ade2042080ade2042a30831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b3214432f6c4908a9aa5f3444421f466b11645235c99b3a14a0a7769429468054e19059af4867da0a495567e50aa2010a14c55765fd2d0570e869f6ac22e7f2916a35ea300d12220a200a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a1880ade2042080ade2042a309065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca3214864cb9828254d712f8e59b164fc6a9402dc4e6c53a143139916d97df0c589312b89950b6ab9795f34d1a12a8010a14050cff76cc632760ba9db796c046004c9009673612220a20e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e84231880ade2042080a6bbf6ffffffffff012a30a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86321415154514f68ce65a0d9eecc578c0ab12da0a2a283a14ee7a2a6a44d427f6949eeb8f12ea9fbb2501da88"
|
||||
expectOutputStr := "000000000000000000000000000000000000000000000000000000000000018c677265656e6669656c645f393030302d3132310000000000000000000000000000000000000000023c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb40e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e8423000000000098968015154514f68ce65a0d9eecc578c0ab12da0a2a28a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b0000000000989680432f6c4908a9aa5f3444421f466b11645235c99b831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b0a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a0000000000989680864cb9828254d712f8e59b164fc6a9402dc4e6c59065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca"
|
||||
|
||||
input, err := hex.DecodeString(inputStr)
|
||||
require.NoError(t, err)
|
||||
|
||||
contract := &cometBFTLightBlockValidateHertz{}
|
||||
res, err := contract.Run(input)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectOutputStr, hex.EncodeToString(res))
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func (cs ConsensusState) EncodeConsensusState() ([]byte, error) {
|
||||
return encodingBytes, nil
|
||||
}
|
||||
|
||||
func (cs *ConsensusState) ApplyLightBlock(block *types.LightBlock) (bool, error) {
|
||||
func (cs *ConsensusState) ApplyLightBlock(block *types.LightBlock, isHertz bool) (bool, error) {
|
||||
if uint64(block.Height) <= cs.Height {
|
||||
return false, fmt.Errorf("block height <= consensus height (%d < %d)", block.Height, cs.Height)
|
||||
}
|
||||
@@ -118,12 +118,19 @@ func (cs *ConsensusState) ApplyLightBlock(block *types.LightBlock) (bool, error)
|
||||
}
|
||||
}
|
||||
|
||||
valSetChanged := !(bytes.Equal(cs.ValidatorSet.Hash(), block.ValidatorsHash))
|
||||
|
||||
// update consensus state
|
||||
cs.Height = uint64(block.Height)
|
||||
cs.NextValidatorSetHash = block.NextValidatorsHash
|
||||
cs.ValidatorSet = block.ValidatorSet
|
||||
|
||||
return !(bytes.Equal(cs.ValidatorSet.Hash(), block.ValidatorsHash)), nil
|
||||
if !isHertz {
|
||||
// This logic is wrong, fixed in hertz fork.
|
||||
return !(bytes.Equal(cs.ValidatorSet.Hash(), block.ValidatorsHash)), nil
|
||||
}
|
||||
|
||||
return valSetChanged, nil
|
||||
}
|
||||
|
||||
// input:
|
||||
|
||||
@@ -69,6 +69,26 @@ var testcases = []struct {
|
||||
},
|
||||
}
|
||||
|
||||
var applyBlocksTestcases = []struct {
|
||||
consensusStateBytes string
|
||||
lightBlockBytes string
|
||||
expectHeight uint64
|
||||
expectValSetChanged bool
|
||||
}{
|
||||
{
|
||||
consensusStateBytes: "677265656e6669656c645f393030302d3132310000000000000000000000000000000000000000013c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb40e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e8423000000000098968015154514f68ce65a0d9eecc578c0ab12da0a2a28a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b0000000000989680432f6c4908a9aa5f3444421f466b11645235c99b831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b0a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a0000000000989680864cb9828254d712f8e59b164fc6a9402dc4e6c59065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca",
|
||||
lightBlockBytes: "0aeb060adb030a02080b1213677265656e6669656c645f393030302d3132311802220c08b2d7f3a10610e8d2adb3032a480a20ec6ecb5db4ffb17fabe40c60ca7b8441e9c5d77585d0831186f3c37aa16e9c15122408011220a2ab9e1eb9ea52812f413526e424b326aff2f258a56e00d690db9f805b60fe7e32200f40aeff672e8309b7b0aefbb9a1ae3d4299b5c445b7d54e8ff398488467f0053a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85542203c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb404a203c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb405220294d8fbd0b94b767a7eba9840f299a3586da7fe6b5dead3b7eecba193c400f935a20bc50557c12d7392b0d07d75df0b61232d48f86a74fdea6d1485d9be6317d268c6220e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85572146699336aa109d1beab3946198c8e59f3b2cbd92f7a4065e3cd89e315ca39d87dee92835b98f8b8ec0861d6d9bb2c60156df5d375b3ceb1fbe71af6a244907d62548a694165caa660fec7a9b4e7b9198191361c71be0b128a0308021a480a20726abd0fdbfb6f779b0483e6e4b4b6f12241f6ea2bf374233ab1a316692b6415122408011220159f10ff15a8b58fc67a92ffd7f33c8cd407d4ce81b04ca79177dfd00ca19a67226808021214050cff76cc632760ba9db796c046004c900967361a0c08b3d7f3a10610808cadba03224080713027ffb776a702d78fd0406205c629ba473e1f8d6af646190f6eb9262cd67d69be90d10e597b91e06d7298eb6fa4b8f1eb7752ebf352a1f51560294548042268080212146699336aa109d1beab3946198c8e59f3b2cbd92f1a0c08b3d7f3a10610b087c1c00322405e2ddb70acfe4904438be3d9f4206c0ace905ac4fc306a42cfc9e86268950a0fbfd6ec5f526d3e41a3ef52bf9f9f358e3cb4c3feac76c762fa3651c1244fe004226808021214c55765fd2d0570e869f6ac22e7f2916a35ea300d1a0c08b3d7f3a10610f0b3d492032240ca17898bd22232fc9374e1188636ee321a396444a5b1a79f7628e4a11f265734b2ab50caf21e8092c55d701248e82b2f011426cb35ba22043b497a6b4661930612a0050aa8010a14050cff76cc632760ba9db796c046004c9009673612220a20e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e84231880ade2042080a6bbf6ffffffffff012a30a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86321415154514f68ce65a0d9eecc578c0ab12da0a2a283a14ee7a2a6a44d427f6949eeb8f12ea9fbb2501da880aa2010a146699336aa109d1beab3946198c8e59f3b2cbd92f12220a20451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b1880ade2042080ade2042a30831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b3214432f6c4908a9aa5f3444421f466b11645235c99b3a14a0a7769429468054e19059af4867da0a495567e50aa2010a14c55765fd2d0570e869f6ac22e7f2916a35ea300d12220a200a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a1880ade2042080ade2042a309065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca3214864cb9828254d712f8e59b164fc6a9402dc4e6c53a143139916d97df0c589312b89950b6ab9795f34d1a12a8010a14050cff76cc632760ba9db796c046004c9009673612220a20e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e84231880ade2042080a6bbf6ffffffffff012a30a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86321415154514f68ce65a0d9eecc578c0ab12da0a2a283a14ee7a2a6a44d427f6949eeb8f12ea9fbb2501da88",
|
||||
expectHeight: 2,
|
||||
expectValSetChanged: false,
|
||||
},
|
||||
{
|
||||
consensusStateBytes: "677265656e6669656c645f393030302d313734310000000000000000000000000000000000000001af6b801dda578dddfa4da1d5d67fd1b32510db24ec271346fc573e9242b01c9a112b51dda2d336246bdc0cc51407ba0cb0e5087be0db5f1cdc3285bbaa8e647500000000000003e84202722cf6a34d727be762b46825b0d26b6263a0a9355ebf3c24bedac5a357a56feeb2cd8b6fed9f14cca15c3091f523b9fb21183b4bb31eb482a0321885e3f57072156448e2b2f7d9a3e7b668757d9cc0bbd28cd674c34ed1c2ed75c5de3b6a8f8cad4600000000000003e8668a0acd8f6db5cae959a0e02132f4d6a672c4d7a4726b542012cc8023ee07b29ab3971cc999d8751bbd16f23413968afcdb070ed66ab47e6e1842bf875bef21dfc5b8af6813bfd82860d361e339bd1ae2f801b6d6ee46b8497a3d51c80b50b6160ea1cc00000000000003e80dfa99423d3084c596c5e3bd6bcb4f654516517b8d4786703c56b300b70f085c0d0482e5d6a3c7208883f0ec8abd2de893f71d18e8f919e7ab198499201d87f92c57ebce83ed2b763bb872e9bc148fb216fd5c93b18819670d9a946ae4b3075672d726b800000000000003e824aab6f85470ff73e3048c64083a09e980d4cb7f8146d231a7b2051c5f7a9c07ab6e6bfe277bd5f4a94f901fe6ee7a6b6bd8479e9e5e448de4b1b33d5ddd74194c86b3852cc140a3f08a9c4149efd45643202f8bef2ad7eecf53e58951c6df6fd932004b00000000000003e84998f6ef8d999a0f36a851bfa29dbcf0364dd65695c286deb3f1657664859d59876bf1ec5a288f6e66e18b37b8a2a1e6ee4a3ef8fa50784d8b758d0c3e70a7cdfe65ab5d",
|
||||
lightBlockBytes: "0aeb070ade030a02080b1214677265656e6669656c645f393030302d3137343118e9d810220c08f2f2b6a30610af9fcc8e022a480a20315130cf3a10f78c5f7633e3941f605151a6901910713c84da0d7929898e9b9e122408011220f09b2290e56b59a7286c2144a811c780f0fd5f631614a9f7ec2dec43f14ac5d63220d15354fdbcc6c7d3e8c5ede34f4f71e896599ba67773605eb6579e10e09254773a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8554220311b22582926e7833b72904605441ed602896e8aeb093bca5f2e8170cea5ed6a4a20311b22582926e7833b72904605441ed602896e8aeb093bca5f2e8170cea5ed6a5220048091bc7ddc283f77bfbf91d73c44da58c3df8a9cbc867405d8b7f3daada22f5a20ee2da802b95c55e551291d96fe6ee4fe8074ddfa2df110042d6809acb665628a6220e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8557214793cee4b478e537592c40ecfb2148ebe32b8f6057a4034248b04af30e0d302cf8cedff585d5e1c6ff8db526bcf298d665cf301ca938a874c76ba9a1fd9fae302b2ec49a335930cf0242762c92843d7f9f7963d60580a12870408e9d8101a480a20452e1984f64c79550ac23db0c408b3eb021675d678ad94f9206ad7a2dec83a181224080112205224c29260b6c220685b29f593bac728e522e3e3675ec7edd92c12251acfe4b4226808021214d742fa5318dc3986e075e2b050529a22c6fa3b8b1a0c08f4f2b6a306109898f6a70322409762b7abd4dd63bb8858673dffd5795b1a87532d3719458d12fbbd1fd2443ca76bd36c4c09fa8952a440de4904f1b6b9270037a147431892c8ace96ad43bf90b2268080212145fa8b3f3fcd4a3ea2495e11dd5dbd399b3d8d4f81a0c08f4f2b6a30610f8f2fd9e03224093f2fc21a41492a34ed3b31ff2eba571ca752ae989f2e47728740bb1eec0f20eb59f59d390ce3d67734ab49a72bc2e97e185d21a4b00f3288ea50b0f1383220a226808021214793cee4b478e537592c40ecfb2148ebe32b8f6051a0c08f4f2b6a306108e8ed7a7032240a4a3c047ca75aeb6e9a21fbc3742f4339c64ead15d117675a2757f7db965aae3e6901f81a3707a67d91c61d6c842b95009e132e7fab187965dc04861d7faa902226808021214f0f07dc2f5e159a35b9662553c6b4e51868502f71a0c08f4f2b6a30610bfed829f032240e23ddc98b0bf7cc6cd494fd8ec96d440d29193910a6eca3dc7e41cdb14efa32471feb1ea2d613bb5acdd8623e8372ed3a36e1838bc75646bdfe9d2ef96647400220f08011a0b088092b8c398feffffff0112d0060a90010a14d742fa5318dc3986e075e2b050529a22c6fa3b8b12220a2083ed2b763bb872e9bc148fb216fd5c93b18819670d9a946ae4b3075672d726b818880820abe8ffffffffffffff012a308146d231a7b2051c5f7a9c07ab6e6bfe277bd5f4a94f901fe6ee7a6b6bd8479e9e5e448de4b1b33d5ddd74194c86b385321424aab6f85470ff73e3048c64083a09e980d4cb7f0a88010a145fa8b3f3fcd4a3ea2495e11dd5dbd399b3d8d4f812220a2048e2b2f7d9a3e7b668757d9cc0bbd28cd674c34ed1c2ed75c5de3b6a8f8cad4618fc0720fc072a30a4726b542012cc8023ee07b29ab3971cc999d8751bbd16f23413968afcdb070ed66ab47e6e1842bf875bef21dfc5b8af3214668a0acd8f6db5cae959a0e02132f4d6a672c4d70a88010a14793cee4b478e537592c40ecfb2148ebe32b8f60512220a206813bfd82860d361e339bd1ae2f801b6d6ee46b8497a3d51c80b50b6160ea1cc18ec0720ec072a308d4786703c56b300b70f085c0d0482e5d6a3c7208883f0ec8abd2de893f71d18e8f919e7ab198499201d87f92c57ebce32140dfa99423d3084c596c5e3bd6bcb4f654516517b0a88010a14f0f07dc2f5e159a35b9662553c6b4e51868502f712220a202cc140a3f08a9c4149efd45643202f8bef2ad7eecf53e58951c6df6fd932004b18ec0720ec072a3095c286deb3f1657664859d59876bf1ec5a288f6e66e18b37b8a2a1e6ee4a3ef8fa50784d8b758d0c3e70a7cdfe65ab5d32144998f6ef8d999a0f36a851bfa29dbcf0364dd6560a86010a1468478c1a37bc01c3acb7470cc6a78f1009a14f7012220a20de83e10566b038855254800b5b0ebf7c21aede9883c11e5cf289979e233b3efe180120012a3089063607696a9e6dbddbe6c23b4634a7c02b80212afc7ec65fb0d379d55d2d0cb25df19c0252356ffa2e2252eedd8f57321400000000000000000000000000000000000000001290010a14d742fa5318dc3986e075e2b050529a22c6fa3b8b12220a2083ed2b763bb872e9bc148fb216fd5c93b18819670d9a946ae4b3075672d726b818880820abe8ffffffffffffff012a308146d231a7b2051c5f7a9c07ab6e6bfe277bd5f4a94f901fe6ee7a6b6bd8479e9e5e448de4b1b33d5ddd74194c86b385321424aab6f85470ff73e3048c64083a09e980d4cb7f",
|
||||
expectHeight: 273513,
|
||||
expectValSetChanged: true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestEncodeConsensusState(t *testing.T) {
|
||||
for i := 0; i < len(testcases); i++ {
|
||||
testcase := testcases[i]
|
||||
@@ -147,28 +167,32 @@ func TestDecodeConsensusState(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConsensusStateApplyLightBlock(t *testing.T) {
|
||||
csBytes, err := hex.DecodeString("677265656e6669656c645f393030302d3132310000000000000000000000000000000000000000013c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb40e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e8423000000000098968015154514f68ce65a0d9eecc578c0ab12da0a2a28a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b0000000000989680432f6c4908a9aa5f3444421f466b11645235c99b831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b0a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a0000000000989680864cb9828254d712f8e59b164fc6a9402dc4e6c59065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca")
|
||||
require.NoError(t, err)
|
||||
t.Logf("cs length: %d\n", len(csBytes))
|
||||
blockBytes, err := hex.DecodeString("0aeb060adb030a02080b1213677265656e6669656c645f393030302d3132311802220c08b2d7f3a10610e8d2adb3032a480a20ec6ecb5db4ffb17fabe40c60ca7b8441e9c5d77585d0831186f3c37aa16e9c15122408011220a2ab9e1eb9ea52812f413526e424b326aff2f258a56e00d690db9f805b60fe7e32200f40aeff672e8309b7b0aefbb9a1ae3d4299b5c445b7d54e8ff398488467f0053a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85542203c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb404a203c350cd55b99dc6c2b7da9bef5410fbfb869fede858e7b95bf7ca294e228bb405220294d8fbd0b94b767a7eba9840f299a3586da7fe6b5dead3b7eecba193c400f935a20bc50557c12d7392b0d07d75df0b61232d48f86a74fdea6d1485d9be6317d268c6220e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8556a20e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85572146699336aa109d1beab3946198c8e59f3b2cbd92f7a4065e3cd89e315ca39d87dee92835b98f8b8ec0861d6d9bb2c60156df5d375b3ceb1fbe71af6a244907d62548a694165caa660fec7a9b4e7b9198191361c71be0b128a0308021a480a20726abd0fdbfb6f779b0483e6e4b4b6f12241f6ea2bf374233ab1a316692b6415122408011220159f10ff15a8b58fc67a92ffd7f33c8cd407d4ce81b04ca79177dfd00ca19a67226808021214050cff76cc632760ba9db796c046004c900967361a0c08b3d7f3a10610808cadba03224080713027ffb776a702d78fd0406205c629ba473e1f8d6af646190f6eb9262cd67d69be90d10e597b91e06d7298eb6fa4b8f1eb7752ebf352a1f51560294548042268080212146699336aa109d1beab3946198c8e59f3b2cbd92f1a0c08b3d7f3a10610b087c1c00322405e2ddb70acfe4904438be3d9f4206c0ace905ac4fc306a42cfc9e86268950a0fbfd6ec5f526d3e41a3ef52bf9f9f358e3cb4c3feac76c762fa3651c1244fe004226808021214c55765fd2d0570e869f6ac22e7f2916a35ea300d1a0c08b3d7f3a10610f0b3d492032240ca17898bd22232fc9374e1188636ee321a396444a5b1a79f7628e4a11f265734b2ab50caf21e8092c55d701248e82b2f011426cb35ba22043b497a6b4661930612a0050aa8010a14050cff76cc632760ba9db796c046004c9009673612220a20e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e84231880ade2042080a6bbf6ffffffffff012a30a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86321415154514f68ce65a0d9eecc578c0ab12da0a2a283a14ee7a2a6a44d427f6949eeb8f12ea9fbb2501da880aa2010a146699336aa109d1beab3946198c8e59f3b2cbd92f12220a20451c5363d89052fde8351895eeea166ce5373c36e31b518ed191d0c599aa0f5b1880ade2042080ade2042a30831b2a2de9e504d7ea299e52a202ce529808618eb3bfc0addf13d8c5f2df821d81e18f9bc61583510b322d067d46323b3214432f6c4908a9aa5f3444421f466b11645235c99b3a14a0a7769429468054e19059af4867da0a495567e50aa2010a14c55765fd2d0570e869f6ac22e7f2916a35ea300d12220a200a572635c06a049c0a2a929e3c8184a50cf6a8b95708c25834ade456f399015a1880ade2042080ade2042a309065e38cff24f5323c8c5da888a0f97e5ee4ba1e11b0674b0a0d06204c1dfa247c370cd4be3e799fc4f6f48d977ac7ca3214864cb9828254d712f8e59b164fc6a9402dc4e6c53a143139916d97df0c589312b89950b6ab9795f34d1a12a8010a14050cff76cc632760ba9db796c046004c9009673612220a20e33f6e876d63791ebd05ff617a1b4f4ad1aa2ce65e3c3a9cdfb33e0ffa7e84231880ade2042080a6bbf6ffffffffff012a30a0805521b5b7ae56eb3fb24555efbfe59e1622bfe9f7be8c9022e9b3f2442739c1ce870b9adee169afe60f674edd7c86321415154514f68ce65a0d9eecc578c0ab12da0a2a283a14ee7a2a6a44d427f6949eeb8f12ea9fbb2501da88")
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(applyBlocksTestcases); i++ {
|
||||
testcase := applyBlocksTestcases[i]
|
||||
|
||||
var lbpb tmproto.LightBlock
|
||||
err = lbpb.Unmarshal(blockBytes)
|
||||
require.NoError(t, err)
|
||||
block, err := types.LightBlockFromProto(&lbpb)
|
||||
require.NoError(t, err)
|
||||
csBytes, err := hex.DecodeString(testcase.consensusStateBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
cs, err := DecodeConsensusState(csBytes)
|
||||
require.NoError(t, err)
|
||||
validatorSetChanged, err := cs.ApplyLightBlock(block)
|
||||
require.NoError(t, err)
|
||||
blockBytes, err := hex.DecodeString(testcase.lightBlockBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
if cs.Height != 2 {
|
||||
t.Fatalf("Height is unexpected, expected: 2, actual: %d\n", cs.Height)
|
||||
}
|
||||
var lbpb tmproto.LightBlock
|
||||
err = lbpb.Unmarshal(blockBytes)
|
||||
require.NoError(t, err)
|
||||
block, err := types.LightBlockFromProto(&lbpb)
|
||||
require.NoError(t, err)
|
||||
|
||||
if validatorSetChanged {
|
||||
t.Fatalf("Validator set has exchanaged which is not expected.\n")
|
||||
cs, err := DecodeConsensusState(csBytes)
|
||||
require.NoError(t, err)
|
||||
validatorSetChanged, err := cs.ApplyLightBlock(block, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
if cs.Height != testcase.expectHeight {
|
||||
t.Fatalf("Height is unexpected, expected: %d, actual: %d\n", testcase.expectHeight, cs.Height)
|
||||
}
|
||||
|
||||
if validatorSetChanged != testcase.expectValSetChanged {
|
||||
t.Fatalf("Validator set changed is unexpected, expected: %v, actual: %v\n", testcase.expectValSetChanged, validatorSetChanged)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ type filter struct {
|
||||
typ Type
|
||||
deadline *time.Timer // filter is inactiv when deadline triggers
|
||||
hashes []common.Hash
|
||||
txs []*types.Transaction
|
||||
crit FilterCriteria
|
||||
logs []*types.Log
|
||||
s *Subscription // associated subscription in event system
|
||||
@@ -99,7 +100,7 @@ func (api *PublicFilterAPI) timeoutLoop(timeout time.Duration) {
|
||||
}
|
||||
}
|
||||
|
||||
// NewPendingTransactionFilter creates a filter that fetches pending transaction hashes
|
||||
// NewPendingTransactionFilter creates a filter that fetches pending transactions
|
||||
// as transactions enter the pending state.
|
||||
//
|
||||
// It is part of the filter package because this filter can be used through the
|
||||
@@ -108,20 +109,20 @@ func (api *PublicFilterAPI) timeoutLoop(timeout time.Duration) {
|
||||
// https://eth.wiki/json-rpc/API#eth_newpendingtransactionfilter
|
||||
func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID {
|
||||
var (
|
||||
pendingTxs = make(chan []common.Hash)
|
||||
pendingTxs = make(chan []*types.Transaction)
|
||||
pendingTxSub = api.events.SubscribePendingTxs(pendingTxs)
|
||||
)
|
||||
api.filtersMu.Lock()
|
||||
api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(api.timeout), hashes: make([]common.Hash, 0), s: pendingTxSub}
|
||||
api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(api.timeout), txs: make([]*types.Transaction, 0), s: pendingTxSub}
|
||||
api.filtersMu.Unlock()
|
||||
|
||||
gopool.Submit(func() {
|
||||
for {
|
||||
select {
|
||||
case ph := <-pendingTxs:
|
||||
case pTx := <-pendingTxs:
|
||||
api.filtersMu.Lock()
|
||||
if f, found := api.filters[pendingTxSub.ID]; found {
|
||||
f.hashes = append(f.hashes, ph...)
|
||||
f.txs = append(f.txs, pTx...)
|
||||
}
|
||||
api.filtersMu.Unlock()
|
||||
case <-pendingTxSub.Err():
|
||||
@@ -136,9 +137,10 @@ func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID {
|
||||
return pendingTxSub.ID
|
||||
}
|
||||
|
||||
// NewPendingTransactions creates a subscription that is triggered each time a transaction
|
||||
// enters the transaction pool and was signed from one of the transactions this nodes manages.
|
||||
func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Subscription, error) {
|
||||
// NewPendingTransactions creates a subscription that is triggered each time a
|
||||
// transaction enters the transaction pool. If fullTx is true the full tx is
|
||||
// sent to the client, otherwise the hash is sent.
|
||||
func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool) (*rpc.Subscription, error) {
|
||||
notifier, supported := rpc.NotifierFromContext(ctx)
|
||||
if !supported {
|
||||
return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
|
||||
@@ -147,16 +149,20 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su
|
||||
rpcSub := notifier.CreateSubscription()
|
||||
|
||||
gopool.Submit(func() {
|
||||
txHashes := make(chan []common.Hash, 128)
|
||||
pendingTxSub := api.events.SubscribePendingTxs(txHashes)
|
||||
txs := make(chan []*types.Transaction, 128)
|
||||
pendingTxSub := api.events.SubscribePendingTxs(txs)
|
||||
|
||||
for {
|
||||
select {
|
||||
case hashes := <-txHashes:
|
||||
case txs := <-txs:
|
||||
// To keep the original behaviour, send a single tx hash in one notification.
|
||||
// TODO(rjl493456442) Send a batch of tx hashes in one notification
|
||||
for _, h := range hashes {
|
||||
notifier.Notify(rpcSub.ID, h)
|
||||
for _, tx := range txs {
|
||||
if fullTx != nil && *fullTx {
|
||||
notifier.Notify(rpcSub.ID, tx)
|
||||
} else {
|
||||
notifier.Notify(rpcSub.ID, tx.Hash())
|
||||
}
|
||||
}
|
||||
case <-rpcSub.Err():
|
||||
pendingTxSub.Unsubscribe()
|
||||
@@ -551,10 +557,14 @@ func (api *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
|
||||
f.deadline.Reset(api.timeout)
|
||||
|
||||
switch f.typ {
|
||||
case PendingTransactionsSubscription, BlocksSubscription, FinalizedHeadersSubscription, VotesSubscription:
|
||||
case BlocksSubscription, FinalizedHeadersSubscription, VotesSubscription:
|
||||
hashes := f.hashes
|
||||
f.hashes = nil
|
||||
return returnHashes(hashes), nil
|
||||
case PendingTransactionsSubscription:
|
||||
txs := f.txs
|
||||
f.txs = nil
|
||||
return txs, nil
|
||||
case LogsSubscription, MinedAndPendingLogsSubscription:
|
||||
logs := f.logs
|
||||
f.logs = nil
|
||||
|
||||
@@ -47,8 +47,8 @@ const (
|
||||
PendingLogsSubscription
|
||||
// MinedAndPendingLogsSubscription queries for logs in mined and pending blocks.
|
||||
MinedAndPendingLogsSubscription
|
||||
// PendingTransactionsSubscription queries tx hashes for pending
|
||||
// transactions entering the pending state
|
||||
// PendingTransactionsSubscription queries for pending transactions entering
|
||||
// the pending state
|
||||
PendingTransactionsSubscription
|
||||
// BlocksSubscription queries hashes for blocks that are imported
|
||||
BlocksSubscription
|
||||
@@ -83,7 +83,7 @@ type subscription struct {
|
||||
created time.Time
|
||||
logsCrit ethereum.FilterQuery
|
||||
logs chan []*types.Log
|
||||
hashes chan []common.Hash
|
||||
txs chan []*types.Transaction
|
||||
headers chan *types.Header
|
||||
finalizedHeaders chan *types.Header
|
||||
votes chan *types.VoteEnvelope
|
||||
@@ -187,7 +187,7 @@ func (sub *Subscription) Unsubscribe() {
|
||||
case sub.es.uninstall <- sub.f:
|
||||
break uninstallLoop
|
||||
case <-sub.f.logs:
|
||||
case <-sub.f.hashes:
|
||||
case <-sub.f.txs:
|
||||
case <-sub.f.headers:
|
||||
case <-sub.f.votes:
|
||||
}
|
||||
@@ -255,7 +255,7 @@ func (es *EventSystem) subscribeMinedPendingLogs(crit ethereum.FilterQuery, logs
|
||||
logsCrit: crit,
|
||||
created: time.Now(),
|
||||
logs: logs,
|
||||
hashes: make(chan []common.Hash),
|
||||
txs: make(chan []*types.Transaction),
|
||||
headers: make(chan *types.Header),
|
||||
votes: make(chan *types.VoteEnvelope),
|
||||
installed: make(chan struct{}),
|
||||
@@ -273,7 +273,7 @@ func (es *EventSystem) subscribeLogs(crit ethereum.FilterQuery, logs chan []*typ
|
||||
logsCrit: crit,
|
||||
created: time.Now(),
|
||||
logs: logs,
|
||||
hashes: make(chan []common.Hash),
|
||||
txs: make(chan []*types.Transaction),
|
||||
headers: make(chan *types.Header),
|
||||
votes: make(chan *types.VoteEnvelope),
|
||||
installed: make(chan struct{}),
|
||||
@@ -291,7 +291,7 @@ func (es *EventSystem) subscribePendingLogs(crit ethereum.FilterQuery, logs chan
|
||||
logsCrit: crit,
|
||||
created: time.Now(),
|
||||
logs: logs,
|
||||
hashes: make(chan []common.Hash),
|
||||
txs: make(chan []*types.Transaction),
|
||||
headers: make(chan *types.Header),
|
||||
votes: make(chan *types.VoteEnvelope),
|
||||
installed: make(chan struct{}),
|
||||
@@ -308,7 +308,7 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti
|
||||
typ: BlocksSubscription,
|
||||
created: time.Now(),
|
||||
logs: make(chan []*types.Log),
|
||||
hashes: make(chan []common.Hash),
|
||||
txs: make(chan []*types.Transaction),
|
||||
headers: headers,
|
||||
votes: make(chan *types.VoteEnvelope),
|
||||
installed: make(chan struct{}),
|
||||
@@ -325,7 +325,7 @@ func (es *EventSystem) SubscribeNewFinalizedHeaders(headers chan *types.Header)
|
||||
typ: FinalizedHeadersSubscription,
|
||||
created: time.Now(),
|
||||
logs: make(chan []*types.Log),
|
||||
hashes: make(chan []common.Hash),
|
||||
txs: make(chan []*types.Transaction),
|
||||
headers: headers,
|
||||
votes: make(chan *types.VoteEnvelope),
|
||||
installed: make(chan struct{}),
|
||||
@@ -334,15 +334,15 @@ func (es *EventSystem) SubscribeNewFinalizedHeaders(headers chan *types.Header)
|
||||
return es.subscribe(sub)
|
||||
}
|
||||
|
||||
// SubscribePendingTxs creates a subscription that writes transaction hashes for
|
||||
// SubscribePendingTxs creates a subscription that writes transactions for
|
||||
// transactions that enter the transaction pool.
|
||||
func (es *EventSystem) SubscribePendingTxs(hashes chan []common.Hash) *Subscription {
|
||||
func (es *EventSystem) SubscribePendingTxs(txs chan []*types.Transaction) *Subscription {
|
||||
sub := &subscription{
|
||||
id: rpc.NewID(),
|
||||
typ: PendingTransactionsSubscription,
|
||||
created: time.Now(),
|
||||
logs: make(chan []*types.Log),
|
||||
hashes: hashes,
|
||||
txs: txs,
|
||||
headers: make(chan *types.Header),
|
||||
votes: make(chan *types.VoteEnvelope),
|
||||
installed: make(chan struct{}),
|
||||
@@ -359,7 +359,7 @@ func (es *EventSystem) SubscribeNewVotes(votes chan *types.VoteEnvelope) *Subscr
|
||||
typ: VotesSubscription,
|
||||
created: time.Now(),
|
||||
logs: make(chan []*types.Log),
|
||||
hashes: make(chan []common.Hash),
|
||||
txs: make(chan []*types.Transaction),
|
||||
headers: make(chan *types.Header),
|
||||
votes: votes,
|
||||
installed: make(chan struct{}),
|
||||
@@ -404,12 +404,8 @@ func (es *EventSystem) handleRemovedLogs(filters filterIndex, ev core.RemovedLog
|
||||
}
|
||||
|
||||
func (es *EventSystem) handleTxsEvent(filters filterIndex, ev core.NewTxsEvent) {
|
||||
hashes := make([]common.Hash, 0, len(ev.Txs))
|
||||
for _, tx := range ev.Txs {
|
||||
hashes = append(hashes, tx.Hash())
|
||||
}
|
||||
for _, f := range filters[PendingTransactionsSubscription] {
|
||||
f.hashes <- hashes
|
||||
f.txs <- ev.Txs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ func TestPendingTxFilter(t *testing.T) {
|
||||
types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
|
||||
}
|
||||
|
||||
hashes []common.Hash
|
||||
txs []*types.Transaction
|
||||
)
|
||||
|
||||
fid0 := api.NewPendingTransactionFilter()
|
||||
@@ -265,9 +265,9 @@ func TestPendingTxFilter(t *testing.T) {
|
||||
t.Fatalf("Unable to retrieve logs: %v", err)
|
||||
}
|
||||
|
||||
h := results.([]common.Hash)
|
||||
hashes = append(hashes, h...)
|
||||
if len(hashes) >= len(transactions) {
|
||||
tx := results.([]*types.Transaction)
|
||||
txs = append(txs, tx...)
|
||||
if len(txs) >= len(transactions) {
|
||||
break
|
||||
}
|
||||
// check timeout
|
||||
@@ -278,13 +278,13 @@ func TestPendingTxFilter(t *testing.T) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
if len(hashes) != len(transactions) {
|
||||
t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes))
|
||||
if len(txs) != len(transactions) {
|
||||
t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(txs))
|
||||
return
|
||||
}
|
||||
for i := range hashes {
|
||||
if hashes[i] != transactions[i].Hash() {
|
||||
t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i])
|
||||
for i := range txs {
|
||||
if txs[i].Hash() != transactions[i].Hash() {
|
||||
t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), txs[i].Hash())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -715,11 +715,11 @@ func TestPendingTxFilterDeadlock(t *testing.T) {
|
||||
fids[i] = fid
|
||||
// Wait for at least one tx to arrive in filter
|
||||
for {
|
||||
hashes, err := api.GetFilterChanges(fid)
|
||||
txs, err := api.GetFilterChanges(fid)
|
||||
if err != nil {
|
||||
t.Fatalf("Filter should exist: %v\n", err)
|
||||
}
|
||||
if len(hashes.([]common.Hash)) > 0 {
|
||||
if len(txs.([]*types.Transaction)) > 0 {
|
||||
break
|
||||
}
|
||||
runtime.Gosched()
|
||||
|
||||
@@ -13,6 +13,9 @@ const (
|
||||
// maxKnownVotes is the maximum vote hashes to keep in the known list
|
||||
// before starting to randomly evict them.
|
||||
maxKnownVotes = 5376
|
||||
|
||||
// voteBufferSize is the maximum number of batch votes can be hold before sending
|
||||
voteBufferSize = 21 * 2
|
||||
)
|
||||
|
||||
// max is a helper function which returns the larger of the two given integers.
|
||||
@@ -43,7 +46,7 @@ func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) *Peer {
|
||||
peer := &Peer{
|
||||
id: id,
|
||||
knownVotes: newKnownCache(maxKnownVotes),
|
||||
voteBroadcast: make(chan []*types.VoteEnvelope),
|
||||
voteBroadcast: make(chan []*types.VoteEnvelope, voteBufferSize),
|
||||
Peer: p,
|
||||
rw: rw,
|
||||
version: version,
|
||||
@@ -105,7 +108,9 @@ func (p *Peer) AsyncSendVotes(votes []*types.VoteEnvelope) {
|
||||
select {
|
||||
case p.voteBroadcast <- votes:
|
||||
case <-p.term:
|
||||
p.Log().Debug("Dropping vote propagation", "count", len(votes))
|
||||
p.Log().Debug("Dropping vote propagation for closed peer", "count", len(votes))
|
||||
default:
|
||||
p.Log().Debug("Dropping vote propagation for abnormal peer", "count", len(votes))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,12 @@ func (ec *Client) GetNodeInfo(ctx context.Context) (*p2p.NodeInfo, error) {
|
||||
return &result, err
|
||||
}
|
||||
|
||||
// SubscribePendingTransactions subscribes to new pending transactions.
|
||||
// SubscribeFullPendingTransactions subscribes to new pending transactions.
|
||||
func (ec *Client) SubscribeFullPendingTransactions(ctx context.Context, ch chan<- *types.Transaction) (*rpc.ClientSubscription, error) {
|
||||
return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions", true)
|
||||
}
|
||||
|
||||
// SubscribePendingTransactions subscribes to new pending transaction hashes.
|
||||
func (ec *Client) SubscribePendingTransactions(ctx context.Context, ch chan<- common.Hash) (*rpc.ClientSubscription, error) {
|
||||
return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions")
|
||||
}
|
||||
|
||||
@@ -123,8 +123,11 @@ func TestGethClient(t *testing.T) {
|
||||
"TestSetHead",
|
||||
func(t *testing.T) { testSetHead(t, client) },
|
||||
}, {
|
||||
"TestSubscribePendingTxs",
|
||||
"TestSubscribePendingTxHashes",
|
||||
func(t *testing.T) { testSubscribePendingTransactions(t, client) },
|
||||
}, {
|
||||
"TestSubscribePendingTxs",
|
||||
func(t *testing.T) { testSubscribeFullPendingTransactions(t, client) },
|
||||
}, {
|
||||
"TestCallContract",
|
||||
func(t *testing.T) { testCallContract(t, client) },
|
||||
@@ -298,6 +301,40 @@ func testSubscribePendingTransactions(t *testing.T, client *rpc.Client) {
|
||||
}
|
||||
}
|
||||
|
||||
func testSubscribeFullPendingTransactions(t *testing.T, client *rpc.Client) {
|
||||
ec := New(client)
|
||||
ethcl := ethclient.NewClient(client)
|
||||
// Subscribe to Transactions
|
||||
ch := make(chan *types.Transaction)
|
||||
ec.SubscribeFullPendingTransactions(context.Background(), ch)
|
||||
// Send a transaction
|
||||
chainID, err := ethcl.ChainID(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Create transaction
|
||||
tx := types.NewTransaction(1, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
|
||||
signer := types.LatestSignerForChainID(chainID)
|
||||
signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
signedTx, err := tx.WithSignature(signer, signature)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Send transaction
|
||||
err = ethcl.SendTransaction(context.Background(), signedTx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Check that the transaction was send over the channel
|
||||
tx = <-ch
|
||||
if tx.Hash() != signedTx.Hash() {
|
||||
t.Fatalf("Invalid tx hash received, got %v, want %v", tx.Hash(), signedTx.Hash())
|
||||
}
|
||||
}
|
||||
|
||||
func testCallContract(t *testing.T, client *rpc.Client) {
|
||||
ec := New(client)
|
||||
msg := ethereum.CallMsg{
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
const (
|
||||
VersionMajor = 1 // Major version component of the current release
|
||||
VersionMinor = 2 // Minor version component of the current release
|
||||
VersionPatch = 6 // Patch version component of the current release
|
||||
VersionPatch = 8 // Patch version component of the current release
|
||||
VersionMeta = "" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user