diff --git a/contracts/tomo.go b/contracts/tomo.go deleted file mode 100644 index 7e1007e79b..0000000000 --- a/contracts/tomo.go +++ /dev/null @@ -1,43 +0,0 @@ -package contracts - -import ( - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" - "math/big" -) - -const ( - HexSignMethod = "2fb1b25f" -) - -// Send tx sign for block number to smart contract blockSigner. -func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, manager *accounts.Manager, block *types.Block) { - // Find active account. - account := accounts.Account{} - var wallet accounts.Wallet - if wallets := manager.Wallets(); len(wallets) > 0 { - wallet = wallets[0] - if accts := wallets[0].Accounts(); len(accts) > 0 { - account = accts[0] - } - } - - // Create and send tx to smart contract for sign validate block. - blockHex := common.LeftPadBytes(block.Number().Bytes(), 32) - data := common.Hex2Bytes(HexSignMethod) - inputData := append(data, blockHex...) - nonce := pool.State().GetNonce(account.Address) - tx := types.NewTransaction(nonce, common.HexToAddress(common.BlockSigners), big.NewInt(0), 100000, big.NewInt(0), inputData) - txSigned, err := wallet.SignTx(account, tx, chainConfig.ChainId) - if err != nil { - log.Error("Fail to create tx sign", "error", err) - return - } - - // Add tx signed to local tx pool. - pool.AddLocal(txSigned) -} diff --git a/contracts/utils.go b/contracts/utils.go new file mode 100644 index 0000000000..74dbacb5d7 --- /dev/null +++ b/contracts/utils.go @@ -0,0 +1,86 @@ +package contracts + +import ( + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/blocksigner/contract" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" + "math/big" +) + +const ( + HexSignMethod = "2fb1b25f" +) + +// Get ethClient over IPC of current node. +func GetEthClient(ctx *node.ServiceContext) (*ethclient.Client, error) { + conf := ctx.GetConfig() + client, err := ethclient.Dial(conf.IPCEndpoint()) + if err != nil { + log.Error("Fail to connect RPC", "error", err) + return nil, err + } + + return client, nil +} + +// Send tx sign for block number to smart contract blockSigner. +func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, manager *accounts.Manager, block *types.Block) error { + // Find active account. + account := accounts.Account{} + var wallet accounts.Wallet + if wallets := manager.Wallets(); len(wallets) > 0 { + wallet = wallets[0] + if accts := wallets[0].Accounts(); len(accts) > 0 { + account = accts[0] + } + } + + // Create and send tx to smart contract for sign validate block. + nonce := pool.State().GetNonce(account.Address) + tx := CreateTxSign(block.Number(), nonce, common.HexToAddress(common.BlockSigners)) + txSigned, err := wallet.SignTx(account, tx, chainConfig.ChainId) + if err != nil { + log.Error("Fail to create tx sign", "error", err) + return err + } + + // Add tx signed to local tx pool. + pool.AddLocal(txSigned) + + return nil +} + +// Create tx sign. +func CreateTxSign(blockNumber *big.Int, nonce uint64, blockSigner common.Address) *types.Transaction { + blockHex := common.LeftPadBytes(blockNumber.Bytes(), 32) + data := common.Hex2Bytes(HexSignMethod) + inputData := append(data, blockHex...) + tx := types.NewTransaction(nonce, blockSigner, big.NewInt(0), 100000, big.NewInt(0), inputData) + + return tx +} + +// Get signers signed for blockNumber from blockSigner contract. +func GetSignersFromContract(client bind.ContractBackend, blockNumber uint64) ([]common.Address, error) { + addr := common.HexToAddress(common.BlockSigners) + blockSigner, err := contract.NewBlockSigner(addr, client) + if err != nil { + log.Error("Fail get instance of blockSigner", "error", err) + return nil, err + } + opts := new(bind.CallOpts) + addrs, err := blockSigner.GetSigners(opts, new(big.Int).SetUint64(blockNumber)) + if err != nil { + log.Error("Fail get block signers", "error", err) + return nil, err + } + + return addrs, nil +} diff --git a/contracts/utils_test.go b/contracts/utils_test.go new file mode 100644 index 0000000000..c5bca88b09 --- /dev/null +++ b/contracts/utils_test.go @@ -0,0 +1,80 @@ +package contracts + +import ( + "context" + "crypto/ecdsa" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/blocksigner" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "math/big" + "math/rand" + "testing" +) + +func TestSendTxSign(t *testing.T) { + acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") + acc3Key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) + acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) + acc3Addr := crypto.PubkeyToAddress(acc3Key.PublicKey) + accounts := []common.Address{acc2Addr, acc3Addr} + keys := []*ecdsa.PrivateKey{acc2Key, acc3Key} + + signer := types.HomesteadSigner{} + genesis := core.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000)}} + backend := backends.NewSimulatedBackend(genesis) + backend.Commit() + ctx := context.Background() + + transactOpts := bind.NewKeyedTransactor(acc1Key) + blockSignerAddr, blockSigner, err := blocksigner.DeployBlockSigner(transactOpts, backend) + if err != nil { + t.Fatalf("Can't get block signer: %v", err) + } + backend.Commit() + + nonces := make(map[*ecdsa.PrivateKey]int) + oldBlock := make([]common.Address, 100) + + signTx := func(ctx context.Context, backend *backends.SimulatedBackend, signer types.HomesteadSigner, nonces map[*ecdsa.PrivateKey]int, accKey *ecdsa.PrivateKey, i uint64) { + tx, _ := types.SignTx(CreateTxSign(new(big.Int).SetUint64(i), uint64(nonces[accKey]), blockSignerAddr), signer, accKey) + backend.SendTransaction(ctx, tx) + backend.Commit() + nonces[accKey]++ + } + + // Tx sign for signer. + for i := uint64(0); i < 100; i++ { + randIndex := rand.Intn(len(keys)) + accKey := keys[randIndex] + signTx(ctx, backend, signer, nonces, accKey, i) + oldBlock[i] = accounts[randIndex] + + // Tx sign for validators. + for _, key := range keys { + if key != accKey { + signTx(ctx, backend, signer, nonces, key, i) + } + } + } + + for i := uint64(0); i < 100; i++ { + signers, err := blockSigner.GetSigners(new(big.Int).SetUint64(i)) + if err != nil { + t.Fatalf("Can't get signers: %v", err) + } + + if signers[0].String() != oldBlock[i].String() { + t.Errorf("Tx sign for block signer not match %v - %v", signers[0].String(), oldBlock[i].String()) + } + + if len(signers) != len(keys) { + t.Error("Tx sign for block validators not match") + } + } +} diff --git a/eth/backend.go b/eth/backend.go index 2a5a9b2dc9..dc75742048 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -27,13 +27,12 @@ import ( "encoding/json" "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/contracts/blocksigner/contract" + "github.com/ethereum/go-ethereum/contracts" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/state" @@ -42,7 +41,6 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" - "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -199,21 +197,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { number := header.Number.Uint64() rCheckpoint := chain.Config().Clique.RewardCheckpoint - - // Call to smart contract signer. - config := ctx.GetConfig() - client, err := ethclient.Dial(config.IPCEndpoint()) - if err != nil { - log.Error("Fail to connect RPC", "error", err) - return err - } - addr := common.HexToAddress(common.BlockSigners) - blockSigner, err := contract.NewBlockSigner(addr, client) - if err != nil { - log.Error("Fail get block signer", "error", err) - return err - } - opts := new(bind.CallOpts) prevCheckpoint := number - rCheckpoint if number > 0 && prevCheckpoint > 0 { @@ -225,9 +208,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { for i := startBlockNumber; i <= endBlockNumber; i++ { // Get signers in blockSigner smartcontract. - addrs, err := blockSigner.GetSigners(opts, new(big.Int).SetUint64(i)) + client, err := contracts.GetEthClient(ctx) if err != nil { - log.Error("Fail to get signers from smartcontract.", "error", err) + log.Error("Fail to connect IPC from blockSigner", "error", err) + return err + } + addrs, err := contracts.GetSignersFromContract(client, i) + if err != nil { + log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) return err } // Filter duplicate address. diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index d546a43250..732705abde 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -742,6 +742,8 @@ func (f *Fetcher) forgetBlock(hash common.Hash) { // Create tx for sign to smartcontract after import block into chain. func (f *Fetcher) HookCreateTxSign(chainConfig *params.ChainConfig, pool *core.TxPool, manager *accounts.Manager) { f.importedHook = func(block *types.Block) { - contracts.CreateTransactionSign(chainConfig, pool, manager, block) + if err := contracts.CreateTransactionSign(chainConfig, pool, manager, block); err != nil { + log.Error("Fail to create tx sign for imported block", "error", err) + } } } diff --git a/miner/worker.go b/miner/worker.go index 9588252538..b9c588054b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -342,7 +342,9 @@ func (self *worker) wait() { if self.config.Clique != nil { // Send tx sign to smart contract blockSigners. - contracts.CreateTransactionSign(self.config, self.eth.TxPool(), self.eth.AccountManager(), block) + if err := contracts.CreateTransactionSign(self.config, self.eth.TxPool(), self.eth.AccountManager(), block); err != nil { + log.Error("Fail to create tx sign for signer", "error", "err") + } } } }