mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 11:20:45 +00:00
Add XDC APIs, contracts, and header fields
- Add XDPoS header fields (Validators, Validator, Penalties) to block.go - Add XDC constants and contract addresses to common/types.go - Add consensus/XDPoS/utils package with types and utilities - Add contracts/randomize contract binding - Add contracts/utils.go for contract utilities - Add core/state/statedb_utils.go for XDPoS state access - Add core/state/state_reader.go for slot reading utilities - Add core/types/consensus_v2.go for XDPoS 2.0 types - Add internal/ethapi/api_xdc.go with XDC-specific RPC methods - GetBlockSignersByHash/Number - GetBlockFinalityByHash/Number - GetMasternodes - GetCandidateStatus - GetCandidates - Add BlockChain() method to ethapi.Backend interface
This commit is contained in:
parent
0dc883e299
commit
64defd91ef
14 changed files with 1780 additions and 1 deletions
|
|
@ -41,6 +41,44 @@ const (
|
|||
AddressLength = 20
|
||||
)
|
||||
|
||||
// XDC-specific constants
|
||||
const (
|
||||
BlockSigners = "xdc0000000000000000000000000000000000000089"
|
||||
MasternodeVotingSMC = "xdc0000000000000000000000000000000000000088"
|
||||
RandomizeSMC = "xdc0000000000000000000000000000000000000090"
|
||||
FoudationAddr = "xdc0000000000000000000000000000000000000068"
|
||||
TeamAddr = "xdc0000000000000000000000000000000000000099"
|
||||
XDCXAddr = "xdc0000000000000000000000000000000000000091"
|
||||
TradingStateAddr = "xdc0000000000000000000000000000000000000092"
|
||||
XDCXLendingAddress = "xdc0000000000000000000000000000000000000093"
|
||||
XDCXLendingFinalizedTradeAddress = "xdc0000000000000000000000000000000000000094"
|
||||
XDCNativeAddress = "xdc0000000000000000000000000000000000000001"
|
||||
LendingLockAddress = "xdc0000000000000000000000000000000000000011"
|
||||
|
||||
// Method signatures for XDPoS contracts
|
||||
VoteMethod = "0x6dd7d8ea"
|
||||
UnvoteMethod = "0x02aa9be2"
|
||||
ProposeMethod = "0x01267951"
|
||||
ResignMethod = "0xae6e43f5"
|
||||
SignMethod = "0xe341eaa4"
|
||||
XDCXApplyMethod = "0xc6b32f34"
|
||||
XDCZApplyMethod = "0xc6b32f34"
|
||||
HexSignMethod = "e341eaa4"
|
||||
HexSetSecret = "34d38600"
|
||||
HexSetOpening = "e11f5ba2"
|
||||
|
||||
// Reward percentages
|
||||
RewardMasterPercent = 40
|
||||
RewardVoterPercent = 50
|
||||
RewardFoundationPercent = 10
|
||||
|
||||
// Epoch block constants
|
||||
MergeSignRange = 15
|
||||
EpocBlockSecret = 800
|
||||
EpocBlockOpening = 850
|
||||
EpocBlockRandomize = 900
|
||||
)
|
||||
|
||||
var (
|
||||
hashT = reflect.TypeFor[Hash]()
|
||||
addressT = reflect.TypeFor[Address]()
|
||||
|
|
@ -50,11 +88,34 @@ var (
|
|||
|
||||
// MaxHash represents the maximum possible hash value.
|
||||
MaxHash = HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
|
||||
|
||||
// XDC contract addresses (binary form)
|
||||
BlockSignersBinary = HexToAddress("0x0000000000000000000000000000000000000089")
|
||||
MasternodeVotingSMCBinary = HexToAddress("0x0000000000000000000000000000000000000088")
|
||||
RandomizeSMCBinary = HexToAddress("0x0000000000000000000000000000000000000090")
|
||||
FoudationAddrBinary = HexToAddress("0x0000000000000000000000000000000000000068")
|
||||
TeamAddrBinary = HexToAddress("0x0000000000000000000000000000000000000099")
|
||||
XDCXAddrBinary = HexToAddress("0x0000000000000000000000000000000000000091")
|
||||
TradingStateAddrBinary = HexToAddress("0x0000000000000000000000000000000000000092")
|
||||
XDCXLendingAddressBinary = HexToAddress("0x0000000000000000000000000000000000000093")
|
||||
XDCXLendingFinalizedTradeAddressBinary = HexToAddress("0x0000000000000000000000000000000000000094")
|
||||
XDCNativeAddressBinary = HexToAddress("0x0000000000000000000000000000000000000001")
|
||||
LendingLockAddressBinary = HexToAddress("0x0000000000000000000000000000000000000011")
|
||||
MintedRecordAddressBinary = HexToAddress("0x000000000000000000000000000000000000009a")
|
||||
|
||||
// TIP2019 block number for XDPoS reward updates
|
||||
TIP2019Block = big.NewInt(0)
|
||||
)
|
||||
|
||||
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
||||
type Hash [HashLength]byte
|
||||
|
||||
// Vote represents a masternode vote from a voter
|
||||
type Vote struct {
|
||||
Masternode Address
|
||||
Voter Address
|
||||
}
|
||||
|
||||
// BytesToHash sets b to hash.
|
||||
// If b is larger than len(h), b will be cropped from the left.
|
||||
func BytesToHash(b []byte) Hash {
|
||||
|
|
|
|||
35
consensus/XDPoS/utils/constants.go
Normal file
35
consensus/XDPoS/utils/constants.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
// XDPoS delegated-proof-of-stake protocol constants.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
var (
|
||||
EpochLength = uint64(900) // Default number of blocks after which to checkpoint and reset the pending votes
|
||||
|
||||
ExtraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||
ExtraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
|
||||
NonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new signer
|
||||
NonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a signer.
|
||||
|
||||
UncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
|
||||
InmemoryEpochs = 5 * EpochLength // Number of mapping from block to epoch switch infos to keep in memory
|
||||
|
||||
InmemoryRound2Epochs = 65536 // Number of mapping of epoch switch blocks for quickly locating epoch switch block.
|
||||
)
|
||||
|
||||
const (
|
||||
InmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
|
||||
BlockSignersCacheLimit = 9000
|
||||
M2ByteLength = 4
|
||||
)
|
||||
|
||||
const (
|
||||
PeriodicJobPeriod = 60
|
||||
PoolHygieneRound = 10
|
||||
)
|
||||
49
consensus/XDPoS/utils/types.go
Normal file
49
consensus/XDPoS/utils/types.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
// XDPoS types and interfaces
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
type Masternode struct {
|
||||
Address common.Address
|
||||
Stake *big.Int
|
||||
}
|
||||
|
||||
type PublicApiSnapshot struct {
|
||||
Number uint64 `json:"number"` // Block number where the snapshot was created
|
||||
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
|
||||
Signers map[common.Address]struct{} `json:"signers"` // Set of authorized signers at this moment
|
||||
Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections
|
||||
}
|
||||
|
||||
type MissedRoundInfo struct {
|
||||
Round types.Round
|
||||
Miner common.Address
|
||||
CurrentBlockHash common.Hash
|
||||
CurrentBlockNum *big.Int
|
||||
ParentBlockHash common.Hash
|
||||
ParentBlockNum *big.Int
|
||||
}
|
||||
|
||||
type PublicApiMissedRoundsMetadata struct {
|
||||
EpochRound types.Round
|
||||
EpochBlockNumber *big.Int
|
||||
MissedRounds []MissedRoundInfo
|
||||
}
|
||||
|
||||
// Given an epoch number, this struct records the epoch switch block (first block in epoch) infos such as block number
|
||||
type EpochNumInfo struct {
|
||||
EpochBlockHash common.Hash `json:"hash"`
|
||||
EpochRound types.Round `json:"round"`
|
||||
EpochFirstBlockNumber *big.Int `json:"firstBlock"`
|
||||
EpochLastBlockNumber *big.Int `json:"lastBlock"`
|
||||
}
|
||||
|
||||
type SigLRU = lru.Cache[common.Hash, common.Address]
|
||||
104
consensus/XDPoS/utils/utils.go
Normal file
104
consensus/XDPoS/utils/utils.go
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
// XDPoS utility functions
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
func Position(list []common.Address, x common.Address) int {
|
||||
for i, item := range list {
|
||||
if item == x {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func Hop(len, pre, cur int) int {
|
||||
switch {
|
||||
case pre < cur:
|
||||
return cur - (pre + 1)
|
||||
case pre > cur:
|
||||
return (len - pre) + (cur - 1)
|
||||
default:
|
||||
return len - 1
|
||||
}
|
||||
}
|
||||
|
||||
// Extract validators from byte array.
|
||||
func ExtractValidatorsFromBytes(byteValidators []byte) []int64 {
|
||||
lenValidator := len(byteValidators) / M2ByteLength
|
||||
var validators []int64
|
||||
for i := 0; i < lenValidator; i++ {
|
||||
trimByte := bytes.Trim(byteValidators[i*M2ByteLength:(i+1)*M2ByteLength], "\x00")
|
||||
intNumber, err := strconv.Atoi(string(trimByte))
|
||||
if err != nil {
|
||||
log.Error("Can not convert string to integer", "error", err)
|
||||
return []int64{}
|
||||
}
|
||||
validators = append(validators, int64(intNumber))
|
||||
}
|
||||
|
||||
return validators
|
||||
}
|
||||
|
||||
// compare 2 signers lists
|
||||
// return true if they are same elements, otherwise return false
|
||||
func CompareSignersLists(list1 []common.Address, list2 []common.Address) bool {
|
||||
l1 := make([]common.Address, len(list1))
|
||||
l2 := make([]common.Address, len(list2))
|
||||
|
||||
copy(l1, list1)
|
||||
copy(l2, list2)
|
||||
|
||||
if len(l1) == 0 && len(l2) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(l1) != len(l2) {
|
||||
return false
|
||||
}
|
||||
|
||||
sort.Slice(l1, func(i, j int) bool {
|
||||
return bytes.Compare(l1[i][:], l1[j][:]) == -1
|
||||
})
|
||||
sort.Slice(l2, func(i, j int) bool {
|
||||
return bytes.Compare(l2[i][:], l2[j][:]) == -1
|
||||
})
|
||||
return reflect.DeepEqual(l1, l2)
|
||||
}
|
||||
|
||||
// Decode extra fields for consensus version >= 2 (XDPoS 2.0 and future versions)
|
||||
func DecodeBytesExtraFields(b []byte, val interface{}) error {
|
||||
if len(b) == 0 {
|
||||
return errors.New("extra field is 0 length")
|
||||
}
|
||||
switch b[0] {
|
||||
case 2:
|
||||
return rlp.DecodeBytes(b[1:], val)
|
||||
default:
|
||||
return fmt.Errorf("consensus version %d is not defined, or this block is v1 block", b[0])
|
||||
}
|
||||
}
|
||||
|
||||
func RlpHash(x interface{}) (h common.Hash) {
|
||||
hw := sha3.NewLegacyKeccak256()
|
||||
err := rlp.Encode(hw, x)
|
||||
if err != nil {
|
||||
log.Error("[rlpHash] Fail to hash item", "Error", err)
|
||||
}
|
||||
hw.Sum(h[:0])
|
||||
return h
|
||||
}
|
||||
433
contracts/randomize/contract/randomize.go
Normal file
433
contracts/randomize/contract/randomize.go
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
// Code generated - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package contract
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// SafeMathABI is the input ABI used to generate the binding from.
|
||||
const SafeMathABI = "[]"
|
||||
|
||||
// SafeMathBin is the compiled bytecode used for deploying new contracts.
|
||||
const SafeMathBin = `0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146060604052600080fd00a165627a7a72305820b9407d48ebc7efee5c9f08b3b3a957df2939281f5913225e8c1291f069b900490029`
|
||||
|
||||
// DeploySafeMath deploys a new Ethereum contract, binding an instance of SafeMath to it.
|
||||
func DeploySafeMath(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SafeMath, error) {
|
||||
parsed, err := abi.JSON(strings.NewReader(SafeMathABI))
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(SafeMathBin), backend)
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
return address, tx, &SafeMath{SafeMathCaller: SafeMathCaller{contract: contract}, SafeMathTransactor: SafeMathTransactor{contract: contract}, SafeMathFilterer: SafeMathFilterer{contract: contract}}, nil
|
||||
}
|
||||
|
||||
// SafeMath is an auto generated Go binding around an Ethereum contract.
|
||||
type SafeMath struct {
|
||||
SafeMathCaller // Read-only binding to the contract
|
||||
SafeMathTransactor // Write-only binding to the contract
|
||||
SafeMathFilterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// SafeMathCaller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type SafeMathCaller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// SafeMathTransactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type SafeMathTransactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// SafeMathFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type SafeMathFilterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// SafeMathSession is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type SafeMathSession struct {
|
||||
Contract *SafeMath // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// SafeMathCallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type SafeMathCallerSession struct {
|
||||
Contract *SafeMathCaller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// SafeMathTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type SafeMathTransactorSession struct {
|
||||
Contract *SafeMathTransactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// SafeMathRaw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type SafeMathRaw struct {
|
||||
Contract *SafeMath // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// SafeMathCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type SafeMathCallerRaw struct {
|
||||
Contract *SafeMathCaller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// SafeMathTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type SafeMathTransactorRaw struct {
|
||||
Contract *SafeMathTransactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// NewSafeMath creates a new instance of SafeMath, bound to a specific deployed contract.
|
||||
func NewSafeMath(address common.Address, backend bind.ContractBackend) (*SafeMath, error) {
|
||||
contract, err := bindSafeMath(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SafeMath{SafeMathCaller: SafeMathCaller{contract: contract}, SafeMathTransactor: SafeMathTransactor{contract: contract}, SafeMathFilterer: SafeMathFilterer{contract: contract}}, nil
|
||||
}
|
||||
|
||||
// NewSafeMathCaller creates a new read-only instance of SafeMath, bound to a specific deployed contract.
|
||||
func NewSafeMathCaller(address common.Address, caller bind.ContractCaller) (*SafeMathCaller, error) {
|
||||
contract, err := bindSafeMath(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SafeMathCaller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewSafeMathTransactor creates a new write-only instance of SafeMath, bound to a specific deployed contract.
|
||||
func NewSafeMathTransactor(address common.Address, transactor bind.ContractTransactor) (*SafeMathTransactor, error) {
|
||||
contract, err := bindSafeMath(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SafeMathTransactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewSafeMathFilterer creates a new log filterer instance of SafeMath, bound to a specific deployed contract.
|
||||
func NewSafeMathFilterer(address common.Address, filterer bind.ContractFilterer) (*SafeMathFilterer, error) {
|
||||
contract, err := bindSafeMath(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SafeMathFilterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bindSafeMath binds a generic wrapper to an already deployed contract.
|
||||
func bindSafeMath(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := abi.JSON(strings.NewReader(SafeMathABI))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_SafeMath *SafeMathRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _SafeMath.Contract.SafeMathCaller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_SafeMath *SafeMathRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _SafeMath.Contract.SafeMathTransactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_SafeMath *SafeMathRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _SafeMath.Contract.SafeMathTransactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_SafeMath *SafeMathCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _SafeMath.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_SafeMath *SafeMathTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _SafeMath.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_SafeMath *SafeMathTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _SafeMath.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// XDCRandomizeABI is the input ABI used to generate the binding from.
|
||||
const XDCRandomizeABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"_validator\",\"type\":\"address\"}],\"name\":\"getSecret\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_secret\",\"type\":\"bytes32[]\"}],\"name\":\"setSecret\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_validator\",\"type\":\"address\"}],\"name\":\"getOpening\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_opening\",\"type\":\"bytes32\"}],\"name\":\"setOpening\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]"
|
||||
|
||||
// XDCRandomizeBin is the compiled bytecode used for deploying new contracts.
|
||||
const XDCRandomizeBin = `0x6060604052341561000f57600080fd5b6103368061001e6000396000f3006060604052600436106100615763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663284180fc811461006657806334d38600146100d8578063d442d6cc14610129578063e11f5ba21461015a575b600080fd5b341561007157600080fd5b610085600160a060020a0360043516610170565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156100c45780820151838201526020016100ac565b505050509050019250505060405180910390f35b34156100e357600080fd5b61012760046024813581810190830135806020818102016040519081016040528093929190818152602001838360200280828437509496506101f395505050505050565b005b341561013457600080fd5b610148600160a060020a0360043516610243565b60405190815260200160405180910390f35b341561016557600080fd5b61012760043561025e565b61017861028e565b60008083600160a060020a0316600160a060020a031681526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156101e757602002820191906000526020600020905b815481526001909101906020018083116101d2575b50505050509050919050565b610384430661032081101561020757600080fd5b610352811061021557600080fd5b600160a060020a033316600090815260208190526040902082805161023e9291602001906102a0565b505050565b600160a060020a031660009081526001602052604090205490565b610384430661035281101561027257600080fd5b50600160a060020a033316600090815260016020526040902055565b60206040519081016040526000815290565b8280548282559060005260206000209081019282156102dd579160200282015b828111156102dd57825182556020909201916001909101906102c0565b506102e99291506102ed565b5090565b61030791905b808211156102e957600081556001016102f3565b905600a165627a7a7230582034991c8dc4001fc254f3ba2811c05d2e7d29bee3908946ca56d1545b2c852de20029`
|
||||
|
||||
// DeployXDCRandomize deploys a new Ethereum contract, binding an instance of XDCRandomize to it.
|
||||
func DeployXDCRandomize(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *XDCRandomize, error) {
|
||||
parsed, err := abi.JSON(strings.NewReader(XDCRandomizeABI))
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(XDCRandomizeBin), backend)
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
return address, tx, &XDCRandomize{XDCRandomizeCaller: XDCRandomizeCaller{contract: contract}, XDCRandomizeTransactor: XDCRandomizeTransactor{contract: contract}, XDCRandomizeFilterer: XDCRandomizeFilterer{contract: contract}}, nil
|
||||
}
|
||||
|
||||
// XDCRandomize is an auto generated Go binding around an Ethereum contract.
|
||||
type XDCRandomize struct {
|
||||
XDCRandomizeCaller // Read-only binding to the contract
|
||||
XDCRandomizeTransactor // Write-only binding to the contract
|
||||
XDCRandomizeFilterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// XDCRandomizeCaller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type XDCRandomizeCaller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// XDCRandomizeTransactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type XDCRandomizeTransactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// XDCRandomizeFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type XDCRandomizeFilterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// XDCRandomizeSession is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type XDCRandomizeSession struct {
|
||||
Contract *XDCRandomize // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// XDCRandomizeCallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type XDCRandomizeCallerSession struct {
|
||||
Contract *XDCRandomizeCaller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// XDCRandomizeTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type XDCRandomizeTransactorSession struct {
|
||||
Contract *XDCRandomizeTransactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// XDCRandomizeRaw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type XDCRandomizeRaw struct {
|
||||
Contract *XDCRandomize // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// XDCRandomizeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type XDCRandomizeCallerRaw struct {
|
||||
Contract *XDCRandomizeCaller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// XDCRandomizeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type XDCRandomizeTransactorRaw struct {
|
||||
Contract *XDCRandomizeTransactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// NewXDCRandomize creates a new instance of XDCRandomize, bound to a specific deployed contract.
|
||||
func NewXDCRandomize(address common.Address, backend bind.ContractBackend) (*XDCRandomize, error) {
|
||||
contract, err := bindXDCRandomize(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &XDCRandomize{XDCRandomizeCaller: XDCRandomizeCaller{contract: contract}, XDCRandomizeTransactor: XDCRandomizeTransactor{contract: contract}, XDCRandomizeFilterer: XDCRandomizeFilterer{contract: contract}}, nil
|
||||
}
|
||||
|
||||
// NewXDCRandomizeCaller creates a new read-only instance of XDCRandomize, bound to a specific deployed contract.
|
||||
func NewXDCRandomizeCaller(address common.Address, caller bind.ContractCaller) (*XDCRandomizeCaller, error) {
|
||||
contract, err := bindXDCRandomize(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &XDCRandomizeCaller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewXDCRandomizeTransactor creates a new write-only instance of XDCRandomize, bound to a specific deployed contract.
|
||||
func NewXDCRandomizeTransactor(address common.Address, transactor bind.ContractTransactor) (*XDCRandomizeTransactor, error) {
|
||||
contract, err := bindXDCRandomize(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &XDCRandomizeTransactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewXDCRandomizeFilterer creates a new log filterer instance of XDCRandomize, bound to a specific deployed contract.
|
||||
func NewXDCRandomizeFilterer(address common.Address, filterer bind.ContractFilterer) (*XDCRandomizeFilterer, error) {
|
||||
contract, err := bindXDCRandomize(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &XDCRandomizeFilterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bindXDCRandomize binds a generic wrapper to an already deployed contract.
|
||||
func bindXDCRandomize(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := abi.JSON(strings.NewReader(XDCRandomizeABI))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_XDCRandomize *XDCRandomizeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _XDCRandomize.Contract.XDCRandomizeCaller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_XDCRandomize *XDCRandomizeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _XDCRandomize.Contract.XDCRandomizeTransactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_XDCRandomize *XDCRandomizeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _XDCRandomize.Contract.XDCRandomizeTransactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_XDCRandomize *XDCRandomizeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _XDCRandomize.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_XDCRandomize *XDCRandomizeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _XDCRandomize.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_XDCRandomize *XDCRandomizeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _XDCRandomize.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// GetOpening is a free data retrieval call binding the contract method 0xd442d6cc.
|
||||
//
|
||||
// Solidity: function getOpening(_validator address) constant returns(bytes32)
|
||||
func (_XDCRandomize *XDCRandomizeCaller) GetOpening(opts *bind.CallOpts, _validator common.Address) ([32]byte, error) {
|
||||
var (
|
||||
ret0 = new([32]byte)
|
||||
)
|
||||
out := &[]interface{}{
|
||||
ret0,
|
||||
}
|
||||
err := _XDCRandomize.contract.Call(opts, out, "getOpening", _validator)
|
||||
return *ret0, err
|
||||
}
|
||||
|
||||
// GetOpening is a free data retrieval call binding the contract method 0xd442d6cc.
|
||||
//
|
||||
// Solidity: function getOpening(_validator address) constant returns(bytes32)
|
||||
func (_XDCRandomize *XDCRandomizeSession) GetOpening(_validator common.Address) ([32]byte, error) {
|
||||
return _XDCRandomize.Contract.GetOpening(&_XDCRandomize.CallOpts, _validator)
|
||||
}
|
||||
|
||||
// GetOpening is a free data retrieval call binding the contract method 0xd442d6cc.
|
||||
//
|
||||
// Solidity: function getOpening(_validator address) constant returns(bytes32)
|
||||
func (_XDCRandomize *XDCRandomizeCallerSession) GetOpening(_validator common.Address) ([32]byte, error) {
|
||||
return _XDCRandomize.Contract.GetOpening(&_XDCRandomize.CallOpts, _validator)
|
||||
}
|
||||
|
||||
// GetSecret is a free data retrieval call binding the contract method 0x284180fc.
|
||||
//
|
||||
// Solidity: function getSecret(_validator address) constant returns(bytes32[])
|
||||
func (_XDCRandomize *XDCRandomizeCaller) GetSecret(opts *bind.CallOpts, _validator common.Address) ([][32]byte, error) {
|
||||
var (
|
||||
ret0 = new([][32]byte)
|
||||
)
|
||||
out := &[]interface{}{
|
||||
ret0,
|
||||
}
|
||||
err := _XDCRandomize.contract.Call(opts, out, "getSecret", _validator)
|
||||
return *ret0, err
|
||||
}
|
||||
|
||||
// GetSecret is a free data retrieval call binding the contract method 0x284180fc.
|
||||
//
|
||||
// Solidity: function getSecret(_validator address) constant returns(bytes32[])
|
||||
func (_XDCRandomize *XDCRandomizeSession) GetSecret(_validator common.Address) ([][32]byte, error) {
|
||||
return _XDCRandomize.Contract.GetSecret(&_XDCRandomize.CallOpts, _validator)
|
||||
}
|
||||
|
||||
// GetSecret is a free data retrieval call binding the contract method 0x284180fc.
|
||||
//
|
||||
// Solidity: function getSecret(_validator address) constant returns(bytes32[])
|
||||
func (_XDCRandomize *XDCRandomizeCallerSession) GetSecret(_validator common.Address) ([][32]byte, error) {
|
||||
return _XDCRandomize.Contract.GetSecret(&_XDCRandomize.CallOpts, _validator)
|
||||
}
|
||||
|
||||
// SetOpening is a paid mutator transaction binding the contract method 0xe11f5ba2.
|
||||
//
|
||||
// Solidity: function setOpening(_opening bytes32) returns()
|
||||
func (_XDCRandomize *XDCRandomizeTransactor) SetOpening(opts *bind.TransactOpts, _opening [32]byte) (*types.Transaction, error) {
|
||||
return _XDCRandomize.contract.Transact(opts, "setOpening", _opening)
|
||||
}
|
||||
|
||||
// SetOpening is a paid mutator transaction binding the contract method 0xe11f5ba2.
|
||||
//
|
||||
// Solidity: function setOpening(_opening bytes32) returns()
|
||||
func (_XDCRandomize *XDCRandomizeSession) SetOpening(_opening [32]byte) (*types.Transaction, error) {
|
||||
return _XDCRandomize.Contract.SetOpening(&_XDCRandomize.TransactOpts, _opening)
|
||||
}
|
||||
|
||||
// SetOpening is a paid mutator transaction binding the contract method 0xe11f5ba2.
|
||||
//
|
||||
// Solidity: function setOpening(_opening bytes32) returns()
|
||||
func (_XDCRandomize *XDCRandomizeTransactorSession) SetOpening(_opening [32]byte) (*types.Transaction, error) {
|
||||
return _XDCRandomize.Contract.SetOpening(&_XDCRandomize.TransactOpts, _opening)
|
||||
}
|
||||
|
||||
// SetSecret is a paid mutator transaction binding the contract method 0x34d38600.
|
||||
//
|
||||
// Solidity: function setSecret(_secret bytes32[]) returns()
|
||||
func (_XDCRandomize *XDCRandomizeTransactor) SetSecret(opts *bind.TransactOpts, _secret [][32]byte) (*types.Transaction, error) {
|
||||
return _XDCRandomize.contract.Transact(opts, "setSecret", _secret)
|
||||
}
|
||||
|
||||
// SetSecret is a paid mutator transaction binding the contract method 0x34d38600.
|
||||
//
|
||||
// Solidity: function setSecret(_secret bytes32[]) returns()
|
||||
func (_XDCRandomize *XDCRandomizeSession) SetSecret(_secret [][32]byte) (*types.Transaction, error) {
|
||||
return _XDCRandomize.Contract.SetSecret(&_XDCRandomize.TransactOpts, _secret)
|
||||
}
|
||||
|
||||
// SetSecret is a paid mutator transaction binding the contract method 0x34d38600.
|
||||
//
|
||||
// Solidity: function setSecret(_secret bytes32[]) returns()
|
||||
func (_XDCRandomize *XDCRandomizeTransactorSession) SetSecret(_secret [][32]byte) (*types.Transaction, error) {
|
||||
return _XDCRandomize.Contract.SetSecret(&_XDCRandomize.TransactOpts, _secret)
|
||||
}
|
||||
56
contracts/randomize/randomize.go
Normal file
56
contracts/randomize/randomize.go
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package randomize
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/contracts/randomize/contract"
|
||||
)
|
||||
|
||||
type Randomize struct {
|
||||
*contract.XDCRandomizeSession
|
||||
contractBackend bind.ContractBackend
|
||||
}
|
||||
|
||||
func NewRandomize(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*Randomize, error) {
|
||||
randomize, err := contract.NewXDCRandomize(contractAddr, contractBackend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Randomize{
|
||||
&contract.XDCRandomizeSession{
|
||||
Contract: randomize,
|
||||
TransactOpts: *transactOpts,
|
||||
},
|
||||
contractBackend,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DeployRandomize(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend) (common.Address, *Randomize, error) {
|
||||
randomizeAddr, _, _, err := contract.DeployXDCRandomize(transactOpts, contractBackend)
|
||||
if err != nil {
|
||||
return randomizeAddr, nil, err
|
||||
}
|
||||
|
||||
randomize, err := NewRandomize(transactOpts, randomizeAddr, contractBackend)
|
||||
if err != nil {
|
||||
return randomizeAddr, nil, err
|
||||
}
|
||||
|
||||
return randomizeAddr, randomize, nil
|
||||
}
|
||||
279
contracts/utils.go
Normal file
279
contracts/utils.go
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package contracts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
cryptoRand "crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"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/XDPoS/utils"
|
||||
randomizeContract "github.com/ethereum/go-ethereum/contracts/randomize/contract"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
const (
|
||||
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
)
|
||||
|
||||
type RewardLog struct {
|
||||
Sign uint64 `json:"sign"`
|
||||
Reward *big.Int `json:"reward"`
|
||||
}
|
||||
|
||||
// Create tx sign.
|
||||
func CreateTxSign(blockNumber *big.Int, blockHash common.Hash, nonce uint64, blockSigner common.Address) *types.Transaction {
|
||||
data := common.Hex2Bytes(common.HexSignMethod)
|
||||
inputData := append(data, common.LeftPadBytes(blockNumber.Bytes(), 32)...)
|
||||
inputData = append(inputData, common.LeftPadBytes(blockHash.Bytes(), 32)...)
|
||||
tx := types.NewTransaction(nonce, blockSigner, big.NewInt(0), 200000, big.NewInt(0), inputData)
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
// Send secret key into randomize smartcontract.
|
||||
func BuildTxSecretRandomize(nonce uint64, randomizeAddr common.Address, epocNumber uint64, randomizeKey []byte) (*types.Transaction, error) {
|
||||
data := common.Hex2Bytes(common.HexSetSecret)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
secretNumb := rand.Intn(int(epocNumber))
|
||||
|
||||
// Append randomize suffix in -1, 0, 1.
|
||||
secrets := []int64{int64(secretNumb)}
|
||||
sizeOfArray := int64(32)
|
||||
|
||||
// Build extra data for tx with first position is size of array byte and second position are length of array byte.
|
||||
arrSizeOfSecrets := common.LeftPadBytes(new(big.Int).SetInt64(sizeOfArray).Bytes(), 32)
|
||||
arrLengthOfSecrets := common.LeftPadBytes(new(big.Int).SetInt64(int64(len(secrets))).Bytes(), 32)
|
||||
inputData := append(data, arrSizeOfSecrets...)
|
||||
inputData = append(inputData, arrLengthOfSecrets...)
|
||||
for _, secret := range secrets {
|
||||
encryptSecret := Encrypt(randomizeKey, new(big.Int).SetInt64(secret).String())
|
||||
inputData = append(inputData, common.LeftPadBytes([]byte(encryptSecret), int(sizeOfArray))...)
|
||||
}
|
||||
tx := types.NewTransaction(nonce, randomizeAddr, big.NewInt(0), 200000, big.NewInt(0), inputData)
|
||||
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// Send opening to randomize SMC.
|
||||
func BuildTxOpeningRandomize(nonce uint64, randomizeAddr common.Address, randomizeKey []byte) (*types.Transaction, error) {
|
||||
data := common.Hex2Bytes(common.HexSetOpening)
|
||||
inputData := append(data, randomizeKey...)
|
||||
tx := types.NewTransaction(nonce, randomizeAddr, big.NewInt(0), 200000, big.NewInt(0), inputData)
|
||||
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// Get random from randomize contract.
|
||||
func GetRandomizeFromContract(client bind.ContractBackend, addrMasternode common.Address) (int64, error) {
|
||||
randomize, err := randomizeContract.NewXDCRandomize(common.RandomizeSMCBinary, client)
|
||||
if err != nil {
|
||||
log.Error("Fail to get instance of randomize", "error", err)
|
||||
}
|
||||
opts := new(bind.CallOpts)
|
||||
secrets, err := randomize.GetSecret(opts, addrMasternode)
|
||||
if err != nil {
|
||||
log.Error("Fail get secrets from randomize", "error", err)
|
||||
}
|
||||
opening, err := randomize.GetOpening(opts, addrMasternode)
|
||||
if err != nil {
|
||||
log.Error("Fail get opening from randomize", "error", err)
|
||||
}
|
||||
|
||||
return DecryptRandomizeFromSecretsAndOpening(secrets, opening)
|
||||
}
|
||||
|
||||
// Generate m2 listing from randomize array.
|
||||
func GenM2FromRandomize(randomizes []int64, lenSigners int64) ([]int64, error) {
|
||||
blockValidator := NewSlice(int64(0), lenSigners, 1)
|
||||
randIndexs := make([]int64, lenSigners)
|
||||
total := int64(0)
|
||||
var temp int64 = 0
|
||||
for _, j := range randomizes {
|
||||
total += j
|
||||
}
|
||||
rand.Seed(total)
|
||||
for i := len(blockValidator) - 1; i >= 0; i-- {
|
||||
blockLength := len(blockValidator) - 1
|
||||
if blockLength <= 1 {
|
||||
blockLength = 1
|
||||
}
|
||||
randomIndex := int64(rand.Intn(blockLength))
|
||||
temp = blockValidator[randomIndex]
|
||||
blockValidator[randomIndex] = blockValidator[i]
|
||||
blockValidator[i] = temp
|
||||
blockValidator = append(blockValidator[:i], blockValidator[i+1:]...)
|
||||
randIndexs[i] = temp
|
||||
}
|
||||
|
||||
return randIndexs, nil
|
||||
}
|
||||
|
||||
// Get validators from m2 array integer.
|
||||
func BuildValidatorFromM2(listM2 []int64) []byte {
|
||||
var validatorBytes []byte
|
||||
for _, numberM2 := range listM2 {
|
||||
// Convert number to byte.
|
||||
m2Byte := common.LeftPadBytes([]byte(fmt.Sprintf("%d", numberM2)), utils.M2ByteLength)
|
||||
validatorBytes = append(validatorBytes, m2Byte...)
|
||||
}
|
||||
|
||||
return validatorBytes
|
||||
}
|
||||
|
||||
// Decode validator hex string.
|
||||
func DecodeValidatorsHexData(validatorsStr string) ([]int64, error) {
|
||||
validatorsByte, err := hexutil.Decode(validatorsStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return utils.ExtractValidatorsFromBytes(validatorsByte), nil
|
||||
}
|
||||
|
||||
// Decrypt randomize from secrets and opening.
|
||||
func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) (int64, error) {
|
||||
var random int64
|
||||
if len(secrets) > 0 {
|
||||
for _, secret := range secrets {
|
||||
trimSecret := bytes.TrimLeft(secret[:], "\x00")
|
||||
decryptSecret := Decrypt(opening[:], string(trimSecret))
|
||||
if isInt(decryptSecret) {
|
||||
intNumber, err := strconv.Atoi(decryptSecret)
|
||||
if err != nil {
|
||||
log.Error("Can not convert string to integer", "error", err)
|
||||
return -1, err
|
||||
}
|
||||
random = int64(intNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return random, nil
|
||||
}
|
||||
|
||||
// Dynamic generate array sequence of numbers.
|
||||
func NewSlice(start int64, end int64, step int64) []int64 {
|
||||
s := make([]int64, end-start)
|
||||
for i := range s {
|
||||
s[i] = start
|
||||
start += step
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Shuffle array.
|
||||
func Shuffle(slice []int64) []int64 {
|
||||
newSlice := make([]int64, len(slice))
|
||||
copy(newSlice, slice)
|
||||
|
||||
for i := 0; i < len(slice)-1; i++ {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
randIndex := rand.Intn(len(newSlice))
|
||||
x := newSlice[i]
|
||||
newSlice[i] = newSlice[randIndex]
|
||||
newSlice[randIndex] = x
|
||||
}
|
||||
|
||||
return newSlice
|
||||
}
|
||||
|
||||
// encrypt string to base64 crypto using AES
|
||||
func Encrypt(key []byte, text string) string {
|
||||
plaintext := []byte(text)
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
log.Error("Fail to encrypt", "err", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
// The IV needs to be unique, but not secure. Therefore it's common to
|
||||
// include it at the beginning of the ciphertext.
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(cryptoRand.Reader, iv); err != nil {
|
||||
log.Error("Fail to encrypt iv", "err", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
// convert to base64
|
||||
return base64.URLEncoding.EncodeToString(ciphertext)
|
||||
}
|
||||
|
||||
// decrypt from base64 to decrypted string
|
||||
func Decrypt(key []byte, cryptoText string) string {
|
||||
ciphertext, _ := base64.URLEncoding.DecodeString(cryptoText)
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
log.Error("Fail to decrypt", "err", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
// The IV needs to be unique, but not secure. Therefore it's common to
|
||||
// include it at the beginning of the ciphertext.
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
log.Error("ciphertext too short")
|
||||
return ""
|
||||
}
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
ciphertext = ciphertext[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
|
||||
// XORKeyStream can work in-place if the two arguments are the same.
|
||||
stream.XORKeyStream(ciphertext, ciphertext)
|
||||
|
||||
return string(ciphertext[:])
|
||||
}
|
||||
|
||||
// Generate random string.
|
||||
func RandStringByte(n int) []byte {
|
||||
letterBytes := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Helper function check string is numeric.
|
||||
func isInt(strNumber string) bool {
|
||||
if _, err := strconv.Atoi(strNumber); err == nil {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
41
core/state/state_reader.go
Normal file
41
core/state/state_reader.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
// This file provides utilities for reading smart contract state slots.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
func GetLocSimpleVariable(slot uint64) common.Hash {
|
||||
slotHash := common.BigToHash(new(big.Int).SetUint64(slot))
|
||||
return slotHash
|
||||
}
|
||||
|
||||
func GetLocMappingAtKey(key common.Hash, slot uint64) *big.Int {
|
||||
slotHash := common.BigToHash(new(big.Int).SetUint64(slot))
|
||||
retByte := crypto.Keccak256(key.Bytes(), slotHash.Bytes())
|
||||
ret := new(big.Int)
|
||||
ret.SetBytes(retByte)
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetLocDynamicArrAtElement(slotHash common.Hash, index uint64, elementSize uint64) common.Hash {
|
||||
slotKecBig := crypto.Keccak256Hash(slotHash.Bytes()).Big()
|
||||
//arrBig = slotKecBig + index * elementSize
|
||||
arrBig := slotKecBig.Add(slotKecBig, new(big.Int).SetUint64(index*elementSize))
|
||||
return common.BigToHash(arrBig)
|
||||
}
|
||||
|
||||
func GetLocFixedArrAtElement(slot uint64, index uint64, elementSize uint64) common.Hash {
|
||||
slotBig := new(big.Int).SetUint64(slot)
|
||||
arrBig := slotBig.Add(slotBig, new(big.Int).SetUint64(index*elementSize))
|
||||
return common.BigToHash(arrBig)
|
||||
}
|
||||
|
||||
func GetLocOfStructElement(locOfStruct *big.Int, elementSlotInstruct *big.Int) common.Hash {
|
||||
return common.BigToHash(new(big.Int).Add(locOfStruct, elementSlotInstruct))
|
||||
}
|
||||
184
core/state/statedb_utils.go
Normal file
184
core/state/statedb_utils.go
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
// This file provides utilities for accessing XDPoS state data.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
slotBlockSignerMapping = map[string]uint64{
|
||||
"blockSigners": 0,
|
||||
"blocks": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func GetSigners(statedb *StateDB, block *types.Block) []common.Address {
|
||||
slot := slotBlockSignerMapping["blockSigners"]
|
||||
keys := []common.Hash{}
|
||||
keyArrSlot := GetLocMappingAtKey(block.Hash(), slot)
|
||||
arrSlot := statedb.GetState(common.BlockSignersBinary, common.BigToHash(keyArrSlot))
|
||||
arrLength := arrSlot.Big().Uint64()
|
||||
for i := uint64(0); i < arrLength; i++ {
|
||||
key := GetLocDynamicArrAtElement(common.BigToHash(keyArrSlot), i, 1)
|
||||
keys = append(keys, key)
|
||||
}
|
||||
rets := []common.Address{}
|
||||
for _, key := range keys {
|
||||
ret := statedb.GetState(common.BlockSignersBinary, key)
|
||||
rets = append(rets, common.HexToAddress(ret.Hex()))
|
||||
}
|
||||
|
||||
return rets
|
||||
}
|
||||
|
||||
var (
|
||||
slotRandomizeMapping = map[string]uint64{
|
||||
"randomSecret": 0,
|
||||
"randomOpening": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func GetSecret(statedb *StateDB, address common.Address) [][32]byte {
|
||||
slot := slotRandomizeMapping["randomSecret"]
|
||||
locSecret := GetLocMappingAtKey(common.BytesToHash(address.Bytes()), slot)
|
||||
arrLength := statedb.GetState(common.RandomizeSMCBinary, common.BigToHash(locSecret))
|
||||
keys := []common.Hash{}
|
||||
for i := uint64(0); i < arrLength.Big().Uint64(); i++ {
|
||||
key := GetLocDynamicArrAtElement(common.BigToHash(locSecret), i, 1)
|
||||
keys = append(keys, key)
|
||||
}
|
||||
rets := [][32]byte{}
|
||||
for _, key := range keys {
|
||||
ret := statedb.GetState(common.RandomizeSMCBinary, key)
|
||||
rets = append(rets, ret)
|
||||
}
|
||||
return rets
|
||||
}
|
||||
|
||||
func GetOpening(statedb *StateDB, address common.Address) [32]byte {
|
||||
slot := slotRandomizeMapping["randomOpening"]
|
||||
locOpening := GetLocMappingAtKey(common.BytesToHash(address.Bytes()), slot)
|
||||
ret := statedb.GetState(common.RandomizeSMCBinary, common.BigToHash(locOpening))
|
||||
return ret
|
||||
}
|
||||
|
||||
// The smart contract and the compiled byte code (in corresponding *.go file) is at commit "KYC Layer added." 7f856ffe672162dfa9c4006c89afb45a24fb7f9f
|
||||
// Notice that if smart contract and the compiled byte code (in corresponding *.go file) changes, below also changes
|
||||
var (
|
||||
slotValidatorMapping = map[string]uint64{
|
||||
"withdrawsState": 0,
|
||||
"validatorsState": 1,
|
||||
"voters": 2,
|
||||
"KYCString": 3,
|
||||
"invalidKYCCount": 4,
|
||||
"hasVotedInvalid": 5,
|
||||
"ownerToCandidate": 6,
|
||||
"owners": 7,
|
||||
"candidates": 8,
|
||||
"candidateCount": 9,
|
||||
"ownerCount": 10,
|
||||
"minCandidateCap": 11,
|
||||
"minVoterCap": 12,
|
||||
"maxValidatorNumber": 13,
|
||||
"candidateWithdrawDelay": 14,
|
||||
"voterWithdrawDelay": 15,
|
||||
}
|
||||
)
|
||||
|
||||
func GetCandidates(statedb *StateDB) []common.Address {
|
||||
slot := slotValidatorMapping["candidates"]
|
||||
slotHash := common.BigToHash(new(big.Int).SetUint64(slot))
|
||||
arrLength := statedb.GetState(common.MasternodeVotingSMCBinary, slotHash)
|
||||
count := arrLength.Big().Uint64()
|
||||
rets := make([]common.Address, 0, count)
|
||||
|
||||
emptyHash := common.Hash{}
|
||||
for i := uint64(0); i < count; i++ {
|
||||
key := GetLocDynamicArrAtElement(slotHash, i, 1)
|
||||
ret := statedb.GetState(common.MasternodeVotingSMCBinary, key)
|
||||
if ret != emptyHash {
|
||||
rets = append(rets, common.HexToAddress(ret.Hex()))
|
||||
}
|
||||
}
|
||||
|
||||
return rets
|
||||
}
|
||||
|
||||
func GetCandidateOwner(statedb *StateDB, candidate common.Address) common.Address {
|
||||
slot := slotValidatorMapping["validatorsState"]
|
||||
// validatorsState[_candidate].owner;
|
||||
locValidatorsState := GetLocMappingAtKey(common.BytesToHash(candidate.Bytes()), slot)
|
||||
locCandidateOwner := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(0)))
|
||||
ret := statedb.GetState(common.MasternodeVotingSMCBinary, common.BigToHash(locCandidateOwner))
|
||||
return common.HexToAddress(ret.Hex())
|
||||
}
|
||||
|
||||
func GetCandidateCap(statedb *StateDB, candidate common.Address) *big.Int {
|
||||
slot := slotValidatorMapping["validatorsState"]
|
||||
// validatorsState[_candidate].cap;
|
||||
locValidatorsState := GetLocMappingAtKey(common.BytesToHash(candidate.Bytes()), slot)
|
||||
locCandidateCap := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(1)))
|
||||
ret := statedb.GetState(common.MasternodeVotingSMCBinary, common.BigToHash(locCandidateCap))
|
||||
return ret.Big()
|
||||
}
|
||||
|
||||
func GetVoters(statedb *StateDB, candidate common.Address) []common.Address {
|
||||
//mapping(address => address[]) voters;
|
||||
slot := slotValidatorMapping["voters"]
|
||||
locVoters := GetLocMappingAtKey(common.BytesToHash(candidate.Bytes()), slot)
|
||||
arrLength := statedb.GetState(common.MasternodeVotingSMCBinary, common.BigToHash(locVoters))
|
||||
keys := []common.Hash{}
|
||||
for i := uint64(0); i < arrLength.Big().Uint64(); i++ {
|
||||
key := GetLocDynamicArrAtElement(common.BigToHash(locVoters), i, 1)
|
||||
keys = append(keys, key)
|
||||
}
|
||||
rets := []common.Address{}
|
||||
for _, key := range keys {
|
||||
ret := statedb.GetState(common.MasternodeVotingSMCBinary, key)
|
||||
rets = append(rets, common.HexToAddress(ret.Hex()))
|
||||
}
|
||||
|
||||
return rets
|
||||
}
|
||||
|
||||
func GetVoterCap(statedb *StateDB, candidate, voter common.Address) *big.Int {
|
||||
slot := slotValidatorMapping["validatorsState"]
|
||||
locValidatorsState := GetLocMappingAtKey(common.BytesToHash(candidate.Bytes()), slot)
|
||||
locCandidateVoters := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(2)))
|
||||
retByte := crypto.Keccak256(common.BytesToHash(voter.Bytes()).Bytes(), common.BigToHash(locCandidateVoters).Bytes())
|
||||
ret := statedb.GetState(common.MasternodeVotingSMCBinary, common.BytesToHash(retByte))
|
||||
return ret.Big()
|
||||
}
|
||||
|
||||
var (
|
||||
slotMintedRecordTotalMinted uint64 = 0
|
||||
slotMintedRecordLastEpochNum uint64 = 1
|
||||
)
|
||||
|
||||
func GetTotalMinted(statedb *StateDB) common.Hash {
|
||||
hash := GetLocSimpleVariable(slotMintedRecordTotalMinted)
|
||||
totalMinted := statedb.GetState(common.MintedRecordAddressBinary, hash)
|
||||
return totalMinted
|
||||
}
|
||||
|
||||
func PutTotalMinted(statedb *StateDB, value common.Hash) {
|
||||
hash := GetLocSimpleVariable(slotMintedRecordTotalMinted)
|
||||
statedb.SetState(common.MintedRecordAddressBinary, hash, value)
|
||||
}
|
||||
|
||||
func GetLastEpochNum(statedb *StateDB) common.Hash {
|
||||
hash := GetLocSimpleVariable(slotMintedRecordLastEpochNum)
|
||||
totalMinted := statedb.GetState(common.MintedRecordAddressBinary, hash)
|
||||
return totalMinted
|
||||
}
|
||||
|
||||
func PutLastEpochNum(statedb *StateDB, value common.Hash) {
|
||||
hash := GetLocSimpleVariable(slotMintedRecordLastEpochNum)
|
||||
statedb.SetState(common.MintedRecordAddressBinary, hash, value)
|
||||
}
|
||||
|
|
@ -81,6 +81,11 @@ type Header struct {
|
|||
MixDigest common.Hash `json:"mixHash"`
|
||||
Nonce BlockNonce `json:"nonce"`
|
||||
|
||||
// XDPoS fields for validator consensus
|
||||
Validators []byte `json:"validators" rlp:"optional"`
|
||||
Validator []byte `json:"validator" rlp:"optional"`
|
||||
Penalties []byte `json:"penalties" rlp:"optional"`
|
||||
|
||||
// BaseFee was added by EIP-1559 and is ignored in legacy headers.
|
||||
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
|
||||
|
||||
|
|
@ -112,6 +117,10 @@ type headerMarshaling struct {
|
|||
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
|
||||
BlobGasUsed *hexutil.Uint64
|
||||
ExcessBlobGas *hexutil.Uint64
|
||||
// XDPoS fields
|
||||
Validators hexutil.Bytes
|
||||
Validator hexutil.Bytes
|
||||
Penalties hexutil.Bytes
|
||||
}
|
||||
|
||||
// Hash returns the block hash of the header, which is simply the keccak256 hash of its
|
||||
|
|
@ -129,7 +138,7 @@ func (h *Header) Size() common.StorageSize {
|
|||
if h.BaseFee != nil {
|
||||
baseFeeBits = h.BaseFee.BitLen()
|
||||
}
|
||||
return headerSize + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen()+baseFeeBits)/8)
|
||||
return headerSize + common.StorageSize(len(h.Extra)+len(h.Validators)+len(h.Validator)+len(h.Penalties)+(h.Difficulty.BitLen()+h.Number.BitLen()+baseFeeBits)/8)
|
||||
}
|
||||
|
||||
// SanityCheck checks a few basic things -- these checks are way beyond what
|
||||
|
|
|
|||
141
core/types/consensus_v2.go
Normal file
141
core/types/consensus_v2.go
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
// XDPoS 2.0 consensus types
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// Round number type in XDPoS 2.0
|
||||
type Round uint64
|
||||
type Signature []byte
|
||||
|
||||
// Block Info struct in XDPoS 2.0, used for vote message, etc.
|
||||
type BlockInfo struct {
|
||||
Hash common.Hash `json:"hash"`
|
||||
Round Round `json:"round"`
|
||||
Number *big.Int `json:"number"`
|
||||
}
|
||||
|
||||
// Vote message in XDPoS 2.0
|
||||
type VoteXDPoS struct {
|
||||
signer common.Address //field not exported
|
||||
ProposedBlockInfo *BlockInfo `json:"proposedBlockInfo"`
|
||||
Signature Signature `json:"signature"`
|
||||
GapNumber uint64 `json:"gapNumber"`
|
||||
}
|
||||
|
||||
func (v *VoteXDPoS) Hash() common.Hash {
|
||||
return rlpHash(v)
|
||||
}
|
||||
|
||||
func (v *VoteXDPoS) PoolKey() string {
|
||||
// return the voted block hash
|
||||
return fmt.Sprint(v.ProposedBlockInfo.Round, ":", v.GapNumber, ":", v.ProposedBlockInfo.Number, ":", v.ProposedBlockInfo.Hash.Hex())
|
||||
}
|
||||
|
||||
func (v *VoteXDPoS) GetSigner() common.Address {
|
||||
return v.signer
|
||||
}
|
||||
|
||||
func (v *VoteXDPoS) SetSigner(signer common.Address) {
|
||||
v.signer = signer
|
||||
}
|
||||
|
||||
// Timeout message in XDPoS 2.0
|
||||
type Timeout struct {
|
||||
signer common.Address
|
||||
Round Round
|
||||
Signature Signature
|
||||
GapNumber uint64
|
||||
}
|
||||
|
||||
func (t *Timeout) Hash() common.Hash {
|
||||
return rlpHash(t)
|
||||
}
|
||||
|
||||
func (t *Timeout) PoolKey() string {
|
||||
// timeout pool key is round:gapNumber
|
||||
return fmt.Sprint(t.Round, ":", t.GapNumber)
|
||||
}
|
||||
|
||||
func (t *Timeout) GetSigner() common.Address {
|
||||
return t.signer
|
||||
}
|
||||
|
||||
func (t *Timeout) SetSigner(signer common.Address) {
|
||||
t.signer = signer
|
||||
}
|
||||
|
||||
// BFT Sync Info message in XDPoS 2.0
|
||||
type SyncInfo struct {
|
||||
HighestQuorumCert *QuorumCert
|
||||
HighestTimeoutCert *TimeoutCert
|
||||
}
|
||||
|
||||
func (s *SyncInfo) Hash() common.Hash {
|
||||
return rlpHash(s)
|
||||
}
|
||||
|
||||
// Quorum Certificate struct in XDPoS 2.0
|
||||
type QuorumCert struct {
|
||||
ProposedBlockInfo *BlockInfo `json:"proposedBlockInfo"`
|
||||
Signatures []Signature `json:"signatures"`
|
||||
GapNumber uint64 `json:"gapNumber"`
|
||||
}
|
||||
|
||||
// Timeout Certificate struct in XDPoS 2.0
|
||||
type TimeoutCert struct {
|
||||
Round Round
|
||||
Signatures []Signature
|
||||
GapNumber uint64
|
||||
}
|
||||
|
||||
// The parsed extra fields in block header in XDPoS 2.0 (excluding the version byte)
|
||||
// The version byte (consensus version) is the first byte in header's extra and it's only valid with value >= 2
|
||||
type ExtraFields_v2 struct {
|
||||
Round Round
|
||||
QuorumCert *QuorumCert
|
||||
}
|
||||
|
||||
// Encode XDPoS 2.0 extra fields into bytes
|
||||
func (e *ExtraFields_v2) EncodeToBytes() ([]byte, error) {
|
||||
bytes, err := rlp.EncodeToBytes(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
versionByte := []byte{2}
|
||||
return append(versionByte, bytes...), nil
|
||||
}
|
||||
|
||||
type EpochSwitchInfo struct {
|
||||
Penalties []common.Address
|
||||
Standbynodes []common.Address
|
||||
Masternodes []common.Address
|
||||
MasternodesLen int
|
||||
EpochSwitchBlockInfo *BlockInfo
|
||||
EpochSwitchParentBlockInfo *BlockInfo
|
||||
}
|
||||
|
||||
type VoteForSign struct {
|
||||
ProposedBlockInfo *BlockInfo
|
||||
GapNumber uint64
|
||||
}
|
||||
|
||||
func VoteSigHash(m *VoteForSign) common.Hash {
|
||||
return rlpHash(m)
|
||||
}
|
||||
|
||||
type TimeoutForSign struct {
|
||||
Round Round
|
||||
GapNumber uint64
|
||||
}
|
||||
|
||||
func TimeoutSigHash(m *TimeoutForSign) common.Hash {
|
||||
return rlpHash(m)
|
||||
}
|
||||
|
|
@ -57,6 +57,11 @@ func (b *EthAPIBackend) ChainConfig() *params.ChainConfig {
|
|||
return b.eth.blockchain.Config()
|
||||
}
|
||||
|
||||
// BlockChain returns the underlying blockchain for XDPoS operations.
|
||||
func (b *EthAPIBackend) BlockChain() *core.BlockChain {
|
||||
return b.eth.blockchain
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) CurrentBlock() *types.Header {
|
||||
return b.eth.blockchain.CurrentBlock()
|
||||
}
|
||||
|
|
|
|||
379
internal/ethapi/api_xdc.go
Normal file
379
internal/ethapi/api_xdc.go
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
// Copyright (c) 2018 XDPoSChain
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ethapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/big"
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/XDPoS"
|
||||
"github.com/ethereum/go-ethereum/consensus/XDPoS/utils"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
// XDC status field names
|
||||
const (
|
||||
fieldStatus = "status"
|
||||
fieldCapacity = "capacity"
|
||||
fieldSuccess = "success"
|
||||
fieldEpoch = "epoch"
|
||||
|
||||
statusMasternode = "MASTERNODE"
|
||||
statusSlashed = "SLASHED"
|
||||
statusProposed = "PROPOSED"
|
||||
statusPenalty = "PENALTY"
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyHeader = errors.New("empty header")
|
||||
)
|
||||
|
||||
// GetBlockSignersByHash returns the signers of a block by hash
|
||||
func (s *BlockChainAPI) GetBlockSignersByHash(ctx context.Context, blockHash common.Hash) ([]common.Address, error) {
|
||||
block, err := s.b.BlockByHash(ctx, blockHash)
|
||||
if err != nil || block == nil {
|
||||
return []common.Address{}, err
|
||||
}
|
||||
masternodes, err := s.GetMasternodes(ctx, block)
|
||||
if err != nil || len(masternodes) == 0 {
|
||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes))
|
||||
return []common.Address{}, err
|
||||
}
|
||||
return s.rpcOutputBlockSigners(block, ctx, masternodes)
|
||||
}
|
||||
|
||||
// GetBlockSignersByNumber returns the signers of a block by number
|
||||
func (s *BlockChainAPI) GetBlockSignersByNumber(ctx context.Context, blockNumber rpc.BlockNumber) ([]common.Address, error) {
|
||||
block, err := s.b.BlockByNumber(ctx, blockNumber)
|
||||
if err != nil || block == nil {
|
||||
return []common.Address{}, err
|
||||
}
|
||||
masternodes, err := s.GetMasternodes(ctx, block)
|
||||
if err != nil || len(masternodes) == 0 {
|
||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes))
|
||||
return []common.Address{}, err
|
||||
}
|
||||
return s.rpcOutputBlockSigners(block, ctx, masternodes)
|
||||
}
|
||||
|
||||
// GetBlockFinalityByHash returns the finality of a block by hash
|
||||
func (s *BlockChainAPI) GetBlockFinalityByHash(ctx context.Context, blockHash common.Hash) (uint, error) {
|
||||
block, err := s.b.BlockByHash(ctx, blockHash)
|
||||
if err != nil || block == nil {
|
||||
return uint(0), err
|
||||
}
|
||||
masternodes, err := s.GetMasternodes(ctx, block)
|
||||
if err != nil || len(masternodes) == 0 {
|
||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes))
|
||||
return uint(0), err
|
||||
}
|
||||
return s.findFinalityOfBlock(ctx, block, masternodes)
|
||||
}
|
||||
|
||||
// GetBlockFinalityByNumber returns the finality of a block by number
|
||||
func (s *BlockChainAPI) GetBlockFinalityByNumber(ctx context.Context, blockNumber rpc.BlockNumber) (uint, error) {
|
||||
block, err := s.b.BlockByNumber(ctx, blockNumber)
|
||||
if err != nil || block == nil {
|
||||
return uint(0), err
|
||||
}
|
||||
masternodes, err := s.GetMasternodes(ctx, block)
|
||||
if err != nil || len(masternodes) == 0 {
|
||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes))
|
||||
return uint(0), err
|
||||
}
|
||||
return s.findFinalityOfBlock(ctx, block, masternodes)
|
||||
}
|
||||
|
||||
// GetMasternodes returns masternodes set at the starting block of epoch of the given block
|
||||
func (s *BlockChainAPI) GetMasternodes(ctx context.Context, b *types.Block) ([]common.Address, error) {
|
||||
var masternodes []common.Address
|
||||
if b.Number().Int64() >= 0 {
|
||||
if engine, ok := s.b.Engine().(*XDPoS.XDPoS); ok {
|
||||
// Get block epoch masternodes
|
||||
chain := s.b.BlockChain()
|
||||
if chain != nil {
|
||||
return engine.GetMasternodes(chain, b.Header()), nil
|
||||
}
|
||||
} else {
|
||||
log.Error("Undefined XDPoS consensus engine")
|
||||
}
|
||||
}
|
||||
return masternodes, nil
|
||||
}
|
||||
|
||||
// GetCandidateStatus returns status of the given candidate at a specified epochNumber
|
||||
func (s *BlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAddress common.Address, epoch rpc.BlockNumber) (map[string]interface{}, error) {
|
||||
result := map[string]interface{}{
|
||||
fieldStatus: "",
|
||||
fieldCapacity: 0,
|
||||
fieldSuccess: true,
|
||||
}
|
||||
|
||||
config := s.b.ChainConfig()
|
||||
if config.XDPoS == nil {
|
||||
return result, errors.New("XDPoS config not found")
|
||||
}
|
||||
epochConfig := config.XDPoS.Epoch
|
||||
|
||||
// Calculate checkpoint block number
|
||||
blockNum := uint64(epoch)
|
||||
if epoch < 0 {
|
||||
blockNum = s.b.CurrentBlock().Number.Uint64()
|
||||
}
|
||||
checkpointNumber := (blockNum / epochConfig) * epochConfig
|
||||
if checkpointNumber == 0 {
|
||||
checkpointNumber = epochConfig
|
||||
}
|
||||
|
||||
result[fieldEpoch] = checkpointNumber / epochConfig
|
||||
|
||||
block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(checkpointNumber))
|
||||
if err != nil || block == nil {
|
||||
result[fieldSuccess] = false
|
||||
return result, err
|
||||
}
|
||||
|
||||
header := block.Header()
|
||||
if header == nil {
|
||||
log.Error("Empty header at checkpoint", "num", checkpointNumber)
|
||||
return result, errEmptyHeader
|
||||
}
|
||||
|
||||
// Get candidates from state
|
||||
statedb, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.BlockNumber(checkpointNumber))
|
||||
if err != nil {
|
||||
result[fieldSuccess] = false
|
||||
return result, err
|
||||
}
|
||||
if statedb == nil {
|
||||
result[fieldSuccess] = false
|
||||
return result, errors.New("nil statedb in GetCandidateStatus")
|
||||
}
|
||||
|
||||
candidatesAddresses := state.GetCandidates(statedb)
|
||||
candidates := make([]utils.Masternode, 0, len(candidatesAddresses))
|
||||
for _, address := range candidatesAddresses {
|
||||
v := state.GetCandidateCap(statedb, address)
|
||||
candidates = append(candidates, utils.Masternode{Address: address, Stake: v})
|
||||
}
|
||||
|
||||
if len(candidates) == 0 {
|
||||
log.Debug("Candidates list cannot be found", "len(candidates)", len(candidates), "err", err)
|
||||
result[fieldSuccess] = false
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Check if the address is a candidate
|
||||
isCandidate := false
|
||||
for i := 0; i < len(candidates); i++ {
|
||||
if coinbaseAddress == candidates[i].Address {
|
||||
isCandidate = true
|
||||
result[fieldStatus] = statusProposed
|
||||
result[fieldCapacity] = candidates[i].Stake
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Get masternode list
|
||||
var masternodes []common.Address
|
||||
if engine, ok := s.b.Engine().(*XDPoS.XDPoS); ok {
|
||||
masternodes = engine.GetMasternodesFromCheckpointHeader(header, header.Number.Uint64(), epochConfig)
|
||||
if len(masternodes) == 0 {
|
||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes), "blockNum", header.Number.Uint64())
|
||||
result[fieldSuccess] = false
|
||||
return result, err
|
||||
}
|
||||
} else {
|
||||
log.Error("Undefined XDPoS consensus engine")
|
||||
}
|
||||
|
||||
// Set to statusMasternode if it is masternode
|
||||
for _, masternode := range masternodes {
|
||||
if coinbaseAddress == masternode {
|
||||
result[fieldStatus] = statusMasternode
|
||||
if !isCandidate {
|
||||
result[fieldCapacity] = -1
|
||||
log.Warn("Find non-candidate masternode", "masternode", masternode.String(), "checkpointNumber", checkpointNumber, "epoch", epoch)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetCandidates returns status of all candidates at a specified epochNumber
|
||||
func (s *BlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.BlockNumber) (map[string]interface{}, error) {
|
||||
result := map[string]interface{}{
|
||||
"candidates": []map[string]interface{}{},
|
||||
"success": true,
|
||||
}
|
||||
|
||||
config := s.b.ChainConfig()
|
||||
if config.XDPoS == nil {
|
||||
result["success"] = false
|
||||
return result, errors.New("XDPoS config not found")
|
||||
}
|
||||
epochConfig := config.XDPoS.Epoch
|
||||
|
||||
// Calculate checkpoint block number
|
||||
blockNum := uint64(epoch)
|
||||
if epoch < 0 {
|
||||
blockNum = s.b.CurrentBlock().Number.Uint64()
|
||||
}
|
||||
checkpointNumber := (blockNum / epochConfig) * epochConfig
|
||||
if checkpointNumber == 0 {
|
||||
checkpointNumber = epochConfig
|
||||
}
|
||||
|
||||
result["epoch"] = checkpointNumber / epochConfig
|
||||
|
||||
// Get candidates from state
|
||||
statedb, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.BlockNumber(checkpointNumber))
|
||||
if err != nil {
|
||||
result["success"] = false
|
||||
return result, err
|
||||
}
|
||||
if statedb == nil {
|
||||
result["success"] = false
|
||||
return result, errors.New("nil statedb in GetCandidates")
|
||||
}
|
||||
|
||||
candidatesAddresses := state.GetCandidates(statedb)
|
||||
candidates := make([]map[string]interface{}, 0, len(candidatesAddresses))
|
||||
for _, address := range candidatesAddresses {
|
||||
cap := state.GetCandidateCap(statedb, address)
|
||||
owner := state.GetCandidateOwner(statedb, address)
|
||||
candidates = append(candidates, map[string]interface{}{
|
||||
"address": address,
|
||||
"capacity": cap,
|
||||
"owner": owner,
|
||||
})
|
||||
}
|
||||
|
||||
// Sort by capacity descending
|
||||
sort.Slice(candidates, func(i, j int) bool {
|
||||
capI := candidates[i]["capacity"].(*big.Int)
|
||||
capJ := candidates[j]["capacity"].(*big.Int)
|
||||
return capI.Cmp(capJ) > 0
|
||||
})
|
||||
|
||||
result["candidates"] = candidates
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// rpcOutputBlockSigners returns block signers for RPC output
|
||||
func (s *BlockChainAPI) rpcOutputBlockSigners(block *types.Block, ctx context.Context, masternodes []common.Address) ([]common.Address, error) {
|
||||
if block == nil {
|
||||
return nil, errors.New("block not found")
|
||||
}
|
||||
|
||||
header := block.Header()
|
||||
if header == nil {
|
||||
return nil, errors.New("header not found")
|
||||
}
|
||||
|
||||
// Extract signers from header's Validator field
|
||||
signers := make([]common.Address, 0)
|
||||
if len(header.Validator) > 0 {
|
||||
// Decode validator bytes to addresses
|
||||
for i := 0; i+common.AddressLength <= len(header.Validator); i += common.AddressLength {
|
||||
var addr common.Address
|
||||
copy(addr[:], header.Validator[i:i+common.AddressLength])
|
||||
signers = append(signers, addr)
|
||||
}
|
||||
}
|
||||
|
||||
// If no signers found in Validator field, return the block miner
|
||||
if len(signers) == 0 {
|
||||
signers = append(signers, header.Coinbase)
|
||||
}
|
||||
|
||||
return signers, nil
|
||||
}
|
||||
|
||||
// findFinalityOfBlock calculates the finality percentage of a block
|
||||
func (s *BlockChainAPI) findFinalityOfBlock(ctx context.Context, block *types.Block, masternodes []common.Address) (uint, error) {
|
||||
if block == nil || len(masternodes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
signers, err := s.rpcOutputBlockSigners(block, ctx, masternodes)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Calculate finality percentage
|
||||
signerCount := len(signers)
|
||||
masternodeCount := len(masternodes)
|
||||
|
||||
if masternodeCount == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
finality := uint((signerCount * 100) / masternodeCount)
|
||||
return finality, nil
|
||||
}
|
||||
|
||||
// RPCMarshalHeaderXDC converts a header to the RPC output with XDC fields
|
||||
func RPCMarshalHeaderXDC(header *types.Header) map[string]interface{} {
|
||||
result := map[string]interface{}{
|
||||
"number": (*hexutil.Big)(header.Number),
|
||||
"hash": header.Hash(),
|
||||
"parentHash": header.ParentHash,
|
||||
"nonce": header.Nonce,
|
||||
"mixHash": header.MixDigest,
|
||||
"sha3Uncles": header.UncleHash,
|
||||
"logsBloom": header.Bloom,
|
||||
"stateRoot": header.Root,
|
||||
"miner": header.Coinbase,
|
||||
"difficulty": (*hexutil.Big)(header.Difficulty),
|
||||
"extraData": hexutil.Bytes(header.Extra),
|
||||
"size": hexutil.Uint64(header.Size()),
|
||||
"gasLimit": hexutil.Uint64(header.GasLimit),
|
||||
"gasUsed": hexutil.Uint64(header.GasUsed),
|
||||
"timestamp": hexutil.Uint64(header.Time),
|
||||
"transactionsRoot": header.TxHash,
|
||||
"receiptsRoot": header.ReceiptHash,
|
||||
}
|
||||
|
||||
// Add XDPoS-specific fields
|
||||
if header.Validators != nil {
|
||||
result["validators"] = hexutil.Bytes(header.Validators)
|
||||
}
|
||||
if header.Validator != nil {
|
||||
result["validator"] = hexutil.Bytes(header.Validator)
|
||||
}
|
||||
if header.Penalties != nil {
|
||||
result["penalties"] = hexutil.Bytes(header.Penalties)
|
||||
}
|
||||
|
||||
if header.BaseFee != nil {
|
||||
result["baseFeePerGas"] = (*hexutil.Big)(header.BaseFee)
|
||||
}
|
||||
if header.WithdrawalsHash != nil {
|
||||
result["withdrawalsRoot"] = header.WithdrawalsHash
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
@ -91,6 +91,9 @@ type Backend interface {
|
|||
Engine() consensus.Engine
|
||||
HistoryPruningCutoff() uint64
|
||||
|
||||
// XDPoS-specific method
|
||||
BlockChain() *core.BlockChain
|
||||
|
||||
// This is copied from filters.Backend
|
||||
// eth/filters needs to be initialized from this backend type, so methods needed by
|
||||
// it must also be included here.
|
||||
|
|
|
|||
Loading…
Reference in a new issue