Skip to content

EthStorage Mining #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: tm_w3q
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1858463
add miner
ping-ke Feb 21, 2023
4a46884
update
ping-ke Feb 23, 2023
17b4172
Merge branch 'tm_w3q' of https://github.com/QuarkChain/go-ethereum in…
ping-ke Feb 24, 2023
8ec4674
add sstorage miner
ping-ke Mar 22, 2023
8417baa
merge tm_w3q
ping-ke Mar 22, 2023
b542236
remove test case
ping-ke Mar 22, 2023
bbb3a9e
fix bug and add storage miner contract param
ping-ke Mar 23, 2023
4ea96ee
update comments
ping-ke Mar 23, 2023
18d57ca
fix bug and resolve comments
ping-ke Mar 27, 2023
268d56d
fix test
ping-ke Mar 27, 2023
f0485b2
add task to sstorage sync to fill up empty KV and change create/verif…
ping-ke Mar 30, 2023
d1010ed
resolve comment: using keystore instead of using nodekey file
ping-ke Mar 30, 2023
9f3d457
merge
ping-ke Mar 31, 2023
6f9cb48
resolve build
ping-ke Mar 31, 2023
80c2bda
resolve
ping-ke Apr 3, 2023
9f5b46c
Merge branch 'tm_w3q' of https://github.com/QuarkChain/go-ethereum in…
ping-ke Apr 3, 2023
78f4e97
update kv size to 128k
ping-ke Apr 5, 2023
6d3f9a7
resolve comments and fix bugs
ping-ke Apr 10, 2023
bf3b5b0
fix bugs
ping-ke Apr 11, 2023
9201fee
Merge branch 'tm_w3q' of https://github.com/QuarkChain/go-ethereum in…
ping-ke Apr 16, 2023
ed2d30b
bug fix
ping-ke Apr 16, 2023
e746402
fix test
ping-ke Apr 16, 2023
53aaf00
bug fix
ping-ke Apr 17, 2023
5bdbcff
fix bug and resolve comments
ping-ke Apr 24, 2023
43e0209
update contract bytecode
ping-ke Apr 24, 2023
5a6ede9
add check fill empty func to sstorage console
ping-ke May 2, 2023
5262933
bug fix
ping-ke May 2, 2023
29c335b
bug fix
ping-ke May 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ var (
utils.MinerNoVerifyFlag,
utils.SstorageShardFlag,
utils.SstorageFileFlag,
utils.SstorageMineFlag,
utils.SstorageNodeKeyFlag,
utils.SstorageMinerContractFlag,
utils.NATFlag,
utils.NoDiscoverFlag,
utils.DiscoveryV5Flag,
Expand Down
21 changes: 21 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,18 @@ var (
Usage: "Add sharded storage data file",
Value: nil,
}
SstorageMineFlag = cli.BoolFlag{
Name: "sstorage.mine",
Usage: "Enable sstorage mining",
}
SstorageNodeKeyFlag = cli.StringFlag{
Name: "sstorage.nodekey",
Usage: "Sstorage miner node key file",
}
SstorageMinerContractFlag = cli.StringFlag{
Name: "sstorage.minercontract",
Usage: "Sstorage miner contract",
}
// Logging and debug settings
EthStatsURLFlag = cli.StringFlag{
Name: "ethstats",
Expand Down Expand Up @@ -1125,6 +1137,15 @@ func setSstorage(ctx *cli.Context, cfg *ethconfig.Config) {
if ctx.GlobalIsSet(SstorageFileFlag.Name) {
cfg.SstorageFiles = ctx.GlobalStringSlice(SstorageFileFlag.Name)
}
if ctx.GlobalIsSet(SstorageMineFlag.Name) {
cfg.SstorageMine = ctx.GlobalBool(SstorageMineFlag.Name)
}
if ctx.GlobalIsSet(SstorageNodeKeyFlag.Name) {
cfg.SstorageNodeKey = ctx.GlobalString(SstorageNodeKeyFlag.Name)
}
if ctx.GlobalIsSet(SstorageMinerContractFlag.Name) {
cfg.SstorageMinerContract = ctx.GlobalString(SstorageMinerContractFlag.Name)
}

sstorage.InitializeConfig()
for _, s := range cfg.SstorageShards {
Expand Down
126 changes: 112 additions & 14 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package core

import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -48,7 +49,6 @@ import (
"github.com/ethereum/go-ethereum/trie"
lru "github.com/hashicorp/golang-lru"
"github.com/holiman/uint256"
"golang.org/x/crypto/sha3"
)

var (
Expand Down Expand Up @@ -2352,7 +2352,10 @@ func (bc *BlockChain) PreExecuteBlock(block *types.Block) (err error) {
return
}

var emptyHash = common.Hash{}
var (
emptyHash = common.Hash{}
defaultHashBytes = crypto.Keccak256Hash().Bytes()
)

type SstorageMetadata struct {
KVIdx uint64
Expand All @@ -2379,13 +2382,7 @@ func getSlotHash(slotIdx uint64, key common.Hash) common.Hash {
slotdata := slot[:]
data := append(keydata, slotdata...)

hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState)
hasher.Write(data)

hashRes := common.Hash{}
hasher.Read(hashRes[:])

return hashRes
return crypto.Keccak256Hash(data)
}

// GetSstorageMetadata get sstorage metadata for a given kv (specified by contract address and index)
Expand All @@ -2395,19 +2392,20 @@ func GetSstorageMetadata(s *state.StateDB, contract common.Address, index uint64
// then get SstorageMetadata from kvMap (slot 1) using skey. the SstorageMetadata struct is as following
// struct PhyAddr {
// uint40 KVIdx;
// uint24 KVSize;
// uint24 kvSize;
// bytes24 hash;
// }
defaultHash, defaultMeta := GetDefaultMetadata(index)
position := getSlotHash(2, uint256.NewInt(index).Bytes32())
skey := s.GetState(contract, position)
if skey == emptyHash {
return emptyHash, nil, fmt.Errorf("fail to get skey for index %d", index)
return defaultHash, defaultMeta, fmt.Errorf("fail to get skey for index %d", index)
}

position = getSlotHash(1, skey)
meta := s.GetState(contract, position)
if meta == emptyHash {
return emptyHash, nil, fmt.Errorf("fail to get SstorageMetadata for skey %s", skey.Hex())
return defaultHash, defaultMeta, fmt.Errorf("fail to get SstorageMetadata for skey %s", skey.Hex())
}

return meta, &SstorageMetadata{
Expand All @@ -2417,6 +2415,18 @@ func GetSstorageMetadata(s *state.StateDB, contract common.Address, index uint64
nil
}

func GetDefaultMetadata(index uint64) (common.Hash, *SstorageMetadata) {
meta := &SstorageMetadata{
KVIdx: index,
KVSize: uint64(0),
HashInMeta: defaultHashBytes[:24],
}
hashBytes := make([]byte, 32)
copy(hashBytes[:24], meta.HashInMeta)
binary.BigEndian.PutUint32(hashBytes[27:], uint32(index))
return common.BytesToHash(hashBytes), meta
}

// VerifyKV verify kv using SstorageMetadata
func VerifyKV(sm *sstorage.ShardManager, idx uint64, val []byte, meta *SstorageMetadata, isEncoded bool, providerAddr common.Address) ([]byte, error) {
if idx != meta.KVIdx {
Expand All @@ -2434,7 +2444,7 @@ func VerifyKV(sm *sstorage.ShardManager, idx uint64, val []byte, meta *SstorageM
}

if meta.KVSize != uint64(len(data)) {
return nil, fmt.Errorf("verifyKV fail: size error; Data size: %d; MetaHash KVSize: %d", len(val), meta.KVSize)
return nil, fmt.Errorf("verifyKV fail: size error; Data size: %d; MetaHash kvSize: %d", len(val), meta.KVSize)
}
data = d
}
Expand Down Expand Up @@ -2508,7 +2518,7 @@ func (bc *BlockChain) VerifyAndWriteKV(contract common.Address, data map[uint64]
continue
}

success, err := sm.TryWrite(vkv.Idx, vkv.Data, vkv.MetaHash)
success, err := sm.TryWrite(vkv.Idx, vkv.Data, common.BytesToHash(meta.HashInMeta))
if err != nil {
log.Warn("write kv fail", "error", err)
}
Expand All @@ -2519,6 +2529,42 @@ func (bc *BlockChain) VerifyAndWriteKV(contract common.Address, data map[uint64]
return synced, syncedBytes, inserted, nil
}

// ReadKVsByIndexList Read the KVs by a list of KV index.
func (bc *BlockChain) ReadKVsByIndexList(contract common.Address, indexes []uint64, useMaxKVsize bool) ([]*KV, error) {
stateDB, err := bc.StateAt(bc.CurrentBlock().Root())
if err != nil {
return nil, err
}

return bc.ReadKVsByIndexListWithState(stateDB, contract, indexes, useMaxKVsize)
}

func (bc *BlockChain) ReadKVsByIndexListWithState(stateDB *state.StateDB, contract common.Address, indexes []uint64, useMaxKVsize bool) ([]*KV, error) {
sm := sstorage.ContractToShardManager[contract]
if sm == nil {
return nil, fmt.Errorf("shard manager for contract %s is not support", contract.Hex())
}

res := make([]*KV, 0)
for _, idx := range indexes {
_, meta, err := GetSstorageMetadata(stateDB, contract, idx)
if err != nil {
continue
}
l := int(meta.KVSize)
if useMaxKVsize {
l = int(sm.MaxKvSize())
}
data, ok, err := sm.TryRead(idx, l, common.BytesToHash(meta.HashInMeta))
if ok && err == nil {
kv := KV{idx, data}
res = append(res, &kv)
}
}

return res, nil
}

// ReadEncodedKVsByIndexList Read the masked KVs by a list of KV index.
func (bc *BlockChain) ReadEncodedKVsByIndexList(contract common.Address, shardId uint64, indexes []uint64) (common.Address, []*KV, error) {
sm := sstorage.ContractToShardManager[contract]
Expand Down Expand Up @@ -2599,3 +2645,55 @@ func (bc *BlockChain) GetSstorageLastKvIdx(contract common.Address) (uint64, err
log.Warn("GetSstorageLastKvIdx", "val", common.Bytes2Hex(val.Bytes()))
return new(big.Int).SetBytes(val.Bytes()).Uint64(), nil
}

type MiningInfo struct {
MiningHash common.Hash
LastMineTime uint64
Difficulty *big.Int
BlockMined *big.Int
}

func (a *MiningInfo) Equal(b *MiningInfo) bool {
if b == nil {
return false
}
if a.LastMineTime != b.LastMineTime {
return false
}
if !bytes.Equal(a.MiningHash.Bytes(), b.MiningHash.Bytes()) {
return false
}
if a.BlockMined.Cmp(b.BlockMined) != 0 {
return false
}
if a.Difficulty.Cmp(b.Difficulty) != 0 {
return false
}
return true
}

func (bc *BlockChain) GetSstorageMiningInfo(root common.Hash, contract common.Address, shardId uint64) (*MiningInfo, error) {
stateDB, err := bc.StateAt(root)
if err != nil {
return nil, err
}

return bc.GetSstorageMiningInfoWithStateDB(stateDB, contract, shardId)
}

func (bc *BlockChain) GetSstorageMiningInfoWithStateDB(stateDB *state.StateDB, contract common.Address, shardId uint64) (*MiningInfo, error) {
info := new(MiningInfo)
position := getSlotHash(0, uint256.NewInt(shardId).Bytes32())
info.MiningHash = stateDB.GetState(contract, position)
if info.MiningHash == emptyHash {
return nil, fmt.Errorf("fail to get mining info for shard %d", shardId)
}
info.LastMineTime = stateDB.GetState(contract, hashAdd(position, 1)).Big().Uint64()
info.Difficulty = stateDB.GetState(contract, hashAdd(position, 2)).Big()
info.BlockMined = stateDB.GetState(contract, hashAdd(position, 3)).Big()
return info, nil
}

func hashAdd(hash common.Hash, i uint64) common.Hash {
return common.BytesToHash(new(big.Int).Add(hash.Big(), new(big.Int).SetUint64(i)).Bytes())
}
15 changes: 15 additions & 0 deletions eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,21 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI {
return &PrivateMinerAPI{e: e}
}

// StartSstorMining starts the Sstorage miner. If mining is already running, this method just return.
func (api *PrivateMinerAPI) StartSstorMining() {
api.e.StartSstorMining()
}

// StopSstorMining terminates the Sstorage miner.
func (api *PrivateMinerAPI) StopSstorMining() {
api.e.StopSstorMining()
}

// SetSstorRecommitInterval updates the interval for sstorage miner sealing work recommitting.
func (api *PrivateMinerAPI) SetSstorRecommitInterval(interval int) {
api.e.SstorMiner().SetRecommitInterval(time.Duration(interval) * time.Millisecond)
}

// Start starts the miner with the given number of threads. If threads is nil,
// the number of workers started is equal to the number of logical CPUs that are
// usable by this process. If mining is already running, this method adjust the
Expand Down
44 changes: 41 additions & 3 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/ethereum/go-ethereum/core/state/pruner"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/filters"
Expand All @@ -60,6 +61,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/sstorage"
"github.com/ethereum/go-ethereum/sstorminer"
)

// Config contains the configuration options of the ETH protocol.
Expand Down Expand Up @@ -92,9 +94,10 @@ type Ethereum struct {

APIBackend *EthAPIBackend

miner *miner.Miner
gasPrice *big.Int
etherbase common.Address
miner *miner.Miner
sstorMiner *sstorminer.Miner
gasPrice *big.Int
etherbase common.Address

networkID uint64
netRPCService *ethapi.PublicNetAPI
Expand Down Expand Up @@ -273,6 +276,21 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))

if config.SstorageMine {
privKey, err := crypto.LoadECDSA(config.SstorageNodeKey)
if err != nil {
return nil, err
}
if len(sstorage.Shards()) == 0 {
return nil, fmt.Errorf("no shards is exist")
}
if config.SstorageMinerContract == "" {
return nil, fmt.Errorf("miner contract is needed when the sstorage mine is enabled.")
}
minerContract := common.HexToAddress(config.SstorageMinerContract)
eth.sstorMiner = sstorminer.New(eth, &config.SStorMiner, chainConfig, eth.EventMux(), privKey, minerContract)
}

eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil}
if eth.APIBackend.allowUnprotectedTxs {
log.Info("Unprotected transactions allowed")
Expand Down Expand Up @@ -476,6 +494,26 @@ func (s *Ethereum) SetEtherbase(etherbase common.Address) {
s.miner.SetEtherbase(etherbase)
}

// todo add start / stop mining for special shard

// StartSstorMining starts the sstorage miner. If mining
// is already running, this method just return.
func (s *Ethereum) StartSstorMining() {
// If the miner was not running, initialize it
if !s.IsSstorMining() {
go s.sstorMiner.Start()
}
}

// StopSstorMining terminates the sstorage miner.
func (s *Ethereum) StopSstorMining() {
s.sstorMiner.Stop()
}

func (s *Ethereum) IsSstorMining() bool { return s.sstorMiner.Mining() }

func (s *Ethereum) SstorMiner() *sstorminer.Miner { return s.sstorMiner }

// StartMining starts the miner with the given number of CPU threads. If mining
// is already running, this method adjust the number of threads allowed to use
// and updates the minimum price required by the transaction pool.
Expand Down
19 changes: 17 additions & 2 deletions eth/ethconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/sstorminer"
)

// FullNodeGPO contains default gasprice oracle settings for full node.
Expand Down Expand Up @@ -89,6 +90,14 @@ var Defaults = Config{
GasPrice: big.NewInt(params.GWei),
Recommit: 3 * time.Second,
},
SStorMiner: sstorminer.Config{
RandomChecks: 16,
MinimumDiff: new(big.Int).SetUint64(1),
TargetIntervalSec: new(big.Int).SetUint64(60),
Cutoff: new(big.Int).SetUint64(40),
DiffAdjDivisor: new(big.Int).SetUint64(1024),
Recommit: 15 * time.Second,
},
TxPool: core.DefaultTxPoolConfig,
RPCGasCap: 50000000,
RPCEVMTimeout: 5 * time.Second,
Expand Down Expand Up @@ -174,6 +183,9 @@ type Config struct {
// Mining options
Miner miner.Config

// Sstorage Mining options
SStorMiner sstorminer.Config

// Ethash options
Ethash ethash.Config

Expand Down Expand Up @@ -220,8 +232,11 @@ type Config struct {
ValidatorChangeEpochId uint64

// Sstorage config
SstorageFiles []string `toml:",omitempty"`
SstorageShards []string `toml:",omitempty"`
SstorageFiles []string `toml:",omitempty"`
SstorageShards []string `toml:",omitempty"`
SstorageMine bool
SstorageNodeKey string
SstorageMinerContract string
}

// CreateConsensusEngine creates a consensus engine for the given chain configuration.
Expand Down
Loading