Skip to content

Commit

Permalink
Merge branch 'master' into get-stake
Browse files Browse the repository at this point in the history
  • Loading branch information
qinwei-gong committed Sep 20, 2022
2 parents 9d650c8 + 4631820 commit c6806c2
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 21 deletions.
5 changes: 4 additions & 1 deletion common/heights.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ const HeightSupportThetaTokenInSmartContract uint64 = 13123789 // approximate ti
const HeightValidatorStakeChangedTo200K uint64 = 14526120 // approximate time: 12pm Mar 14, 2022 PT

// HeightSupportWrappedTheta specifies the block height to support wrapped Theta
const HeightSupportWrappedTheta uint64 = 1000000000
const HeightSupportWrappedTheta uint64 = 17285755 // approximate time: 7pm Sep 28, 2022 PT

// HeightEnableMetachainSupport specifies the block height to enable Theta Metachain support (i.e. Mainnet 4.0)
const HeightEnableMetachainSupport uint64 = 1000000000

// CheckpointInterval defines the interval between checkpoints.
const CheckpointInterval = int64(100)
Expand Down
13 changes: 8 additions & 5 deletions common/result/error_code.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ type ErrorCode int
const (
CodeOK ErrorCode = 0

CodeUndecided ErrorCode = 2

// Common Errors
CodeGenericError ErrorCode = 100000
CodeInvalidSignature ErrorCode = 100001
Expand All @@ -29,11 +31,12 @@ const (
CodeUnauthorizedToUpdateSplitRule ErrorCode = 104001

// SmartContract Errors
CodeEVMError ErrorCode = 105001
CodeInvalidValueToTransfer ErrorCode = 105002
CodeInvalidGasPrice ErrorCode = 105003
CodeFeeLimitTooHigh ErrorCode = 105004
CodeInvalidGasLimit ErrorCode = 105005
CodeEVMError ErrorCode = 105001
CodeInvalidValueToTransfer ErrorCode = 105002
CodeInvalidGasPrice ErrorCode = 105003
CodeFeeLimitTooHigh ErrorCode = 105004
CodeInvalidGasLimit ErrorCode = 105005
CodeDoNotSupportNativeThetaInSubchain ErrorCode = 105006

// Stake Deposit/Withdrawal Errors
CodeInvalidStakePurpose ErrorCode = 106001
Expand Down
17 changes: 17 additions & 0 deletions common/result/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ func (res Result) IsOK() bool {
return res.Code == CodeOK
}

// IsUndecided indicates if the execution succeeded
func (res Result) IsUndecided() bool {
return res.Code == CodeUndecided
}

// IsError indicates if the execution results in an error
func (res Result) IsError() bool {
return res.Code != CodeOK
Expand Down Expand Up @@ -58,6 +63,18 @@ func OKWith(info Info) Result {
return res
}

// UndecidedWith returns a success result with extra information
func UndecidedWith(info Info) Result {
res := Result{
Code: CodeUndecided,
Info: make(Info),
}
for k, v := range info {
res.Info[k] = v
}
return res
}

// Error returns an error result
func Error(msgFormat string, a ...interface{}) Result {
msg := fmt.Sprintf(msgFormat, a...)
Expand Down
56 changes: 56 additions & 0 deletions common/size.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library 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.
//
// The go-ethereum library 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package common

import (
"fmt"
)

// StorageSize is a wrapper around a float value that supports user friendly
// formatting.
type StorageSize float64

// String implements the stringer interface.
func (s StorageSize) String() string {
if s > 1099511627776 {
return fmt.Sprintf("%.2f TiB", s/1099511627776)
} else if s > 1073741824 {
return fmt.Sprintf("%.2f GiB", s/1073741824)
} else if s > 1048576 {
return fmt.Sprintf("%.2f MiB", s/1048576)
} else if s > 1024 {
return fmt.Sprintf("%.2f KiB", s/1024)
} else {
return fmt.Sprintf("%.2f B", s)
}
}

// TerminalString implements log.TerminalStringer, formatting a string for console
// output during logging.
func (s StorageSize) TerminalString() string {
if s > 1099511627776 {
return fmt.Sprintf("%.2fTiB", s/1099511627776)
} else if s > 1073741824 {
return fmt.Sprintf("%.2fGiB", s/1073741824)
} else if s > 1048576 {
return fmt.Sprintf("%.2fMiB", s/1048576)
} else if s > 1024 {
return fmt.Sprintf("%.2fKiB", s/1024)
} else {
return fmt.Sprintf("%.2fB", s)
}
}
4 changes: 4 additions & 0 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ const (
MainnetGenesisBlockHash = "0xd8836c6cf3c3ccea0b015b4ed0f9efb0ffe6254db793a515843c9d0f68cbab65"

GenesisBlockHeight = uint64(0)

SubchainChainIDPrefix = "tsub"

MinSubchainID = 1000
)
4 changes: 3 additions & 1 deletion ledger/execution/tx_smart_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ func (exec *SmartContractTxExecutor) process(chainID string, view *st.StoreView,
// Note: for contract deployment, vm.Execute() might transfer coins from the fromAccount to the
// deployed smart contract. Thus, we should call vm.Execute() before calling getInput().
// Otherwise, the fromAccount returned by getInput() will have incorrect balance.
evmRet, contractAddr, gasUsed, evmErr := vm.Execute(exec.state.ParentBlock(), tx, view)
pb := exec.state.ParentBlock()
parentBlockInfo := vm.NewBlockInfo(pb.Height, pb.Timestamp, pb.ChainID)
evmRet, contractAddr, gasUsed, evmErr := vm.Execute(parentBlockInfo, tx, view)

fromAddress := tx.From.Address
fromAccount, success := getInput(view, tx.From)
Expand Down
46 changes: 45 additions & 1 deletion ledger/types/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/json"
"fmt"
"math/big"
"strconv"
"strings"
"sync"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -1101,7 +1103,20 @@ func MapChainID(chainIDStr string, blockHeight uint64) *big.Int {

// For replay attack protection, should NOT use the same chainID as Ethereum
chainID := big.NewInt(1).Add(big.NewInt(CHAIN_ID_OFFSET), chainIDWithoutOffset)
return chainID

if blockHeight < common.HeightEnableMetachainSupport {
return chainID
} else {
// attempt to extract the IDs for subchains. ChainID in the form of tsub[1-9][0-9]* is considered as a Theta Subchain
subchainID, err := extractSubchainID(chainIDStr) // no need to add offset to the subchainIDs
if err == nil {
// this is a subchain chainID
return subchainID
} else {
// fallback
return chainID
}
}
}

func mapChainIDWithoutOffset(chainIDStr string) *big.Int {
Expand All @@ -1120,3 +1135,32 @@ func mapChainIDWithoutOffset(chainIDStr string) *big.Int {
chainIDBigInt := new(big.Int).Abs(crypto.Keccak256Hash(common.Bytes(chainIDStr)).Big()) // all other chainIDs
return chainIDBigInt
}

// Subchain chainID should have the form tsub[1-9][0-9]*
func extractSubchainID(chainIDStr string) (*big.Int, error) {
if !strings.HasPrefix(chainIDStr, core.SubchainChainIDPrefix) {
return nil, fmt.Errorf("invalid subchain ID prefix: %v", chainIDStr)
}

if len(chainIDStr) < 5 {
return nil, fmt.Errorf("subchain ID too short: %v", chainIDStr)
}

leadingDigit := chainIDStr[4]
if leadingDigit == byte('0') {
return nil, fmt.Errorf("the leading digit of the subchain ID should not be zero: %v", chainIDStr)
}

chainIDIntStr := chainIDStr[4:]
chainID, err := strconv.Atoi(chainIDIntStr)
if err != nil {
return nil, err
}

// we require subchain ID to be at least core.MinSubchainID, so it doesn't overlap with the ID of the mainchain
if chainID < core.MinSubchainID {
return nil, fmt.Errorf("subchain ID too small: %v", chainIDStr)
}

return big.NewInt(int64(chainID)), nil
}
97 changes: 97 additions & 0 deletions ledger/types/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,103 @@ import (

var chainID string = "test_chain"

func TestChainID(t *testing.T) {

//
// The IDs for the main chains
//

chainIDStrMainnet := "mainnet"
chainIDStr := chainIDStrMainnet
chainID := MapChainID(chainIDStr, common.HeightRPCCompatibility+1)
assert.True(t, chainID.Cmp(big.NewInt(361)) == 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

chainIDStrTestnet := "testnet"
chainIDStr = chainIDStrTestnet
chainID = MapChainID(chainIDStr, common.HeightRPCCompatibility+1)
assert.True(t, chainID.Cmp(big.NewInt(365)) == 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

chainIDStrPrivatenet := "privatenet"
chainIDStr = chainIDStrPrivatenet
chainID = MapChainID(chainIDStr, common.HeightRPCCompatibility+1)
assert.True(t, chainID.Cmp(big.NewInt(366)) == 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

//
// Invalid subchain IDs
//

var err error
invalidSubchainID0 := "tsub_881" // with an extra underscore
chainIDStr = invalidSubchainID0
chainID, err = extractSubchainID(chainIDStr)
assert.True(t, err != nil, "should be an invalid subchain ID: %v", chainIDStr)
chainID = MapChainID(chainIDStr, common.HeightEnableMetachainSupport+1)
assert.True(t, chainID.Cmp(big.NewInt(881)) != 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

invalidSubchainID1 := "ts881"
chainIDStr = invalidSubchainID1
chainID, err = extractSubchainID(chainIDStr)
assert.True(t, err != nil, "should be an invalid subchain ID: %v", chainIDStr)
chainID = MapChainID(chainIDStr, common.HeightEnableMetachainSupport+1)
assert.True(t, chainID.Cmp(big.NewInt(881)) != 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

invalidSubchainID2 := "tsub09998" // leading digit should not be 0
chainIDStr = invalidSubchainID2
chainID, err = extractSubchainID(chainIDStr)
assert.True(t, err != nil, "should be an invalid subchain ID: %v", chainIDStr)
chainID = MapChainID(chainIDStr, common.HeightEnableMetachainSupport+1)
assert.True(t, chainID.Cmp(big.NewInt(9998)) != 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

invalidSubchainID3 := "tsubabc9" // hex not allowed in chainID
chainIDStr = invalidSubchainID3
chainID, err = extractSubchainID(chainIDStr)
assert.True(t, err != nil, "should be an invalid subchain ID: %v", chainIDStr)
chainID = MapChainID(chainIDStr, common.HeightEnableMetachainSupport+1)
assert.True(t, chainID.Cmp(big.NewInt(43977)) != 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

invalidSubchainID4 := "tsub999" // subchain ID needs to be at least 1000
chainIDStr = invalidSubchainID4
chainID, err = extractSubchainID(chainIDStr)
assert.True(t, err != nil, "should be an invalid subchain ID: %v", chainIDStr)
chainID = MapChainID(chainIDStr, common.HeightEnableMetachainSupport+1)
assert.True(t, chainID.Cmp(big.NewInt(999)) != 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

invalidSubchainID5 := "tsub34535873957238957239573985728957283957923528357238572893572983457238957238495893" // subchain ID needs to be smaller than uint64.max
chainIDStr = invalidSubchainID5
chainID, err = extractSubchainID(chainIDStr)
assert.True(t, err != nil, "should be an invalid subchain ID: %v", chainIDStr)
chainID = MapChainID(chainIDStr, common.HeightEnableMetachainSupport+1)
cid, _ := big.NewInt(0).SetString("34535873957238957239573985728957283957923528357238572893572983457238957238495893", 10)
assert.True(t, chainID.Cmp(cid) != 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

//
// Valid subchain IDs
//

validSubchainID1 := "tsub1991"
chainIDStr = validSubchainID1
chainID = MapChainID(chainIDStr, common.HeightEnableMetachainSupport+1)
assert.True(t, chainID.Cmp(big.NewInt(1991)) == 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

validSubchainID2 := "tsub4546325235"
chainIDStr = validSubchainID2
chainID = MapChainID(chainIDStr, common.HeightEnableMetachainSupport+1)
assert.True(t, chainID.Cmp(big.NewInt(4546325235)) == 0, "mapped chainID for %v is %v", chainIDStr, chainID)
fmt.Printf("extracted chainID for %v: %v\n", chainIDStr, chainID)

// assert.True(t, false)
}

func TestCoinbaseTxSignable(t *testing.T) {
chainID := "test_chain_id"
va1PrivAcc := PrivAccountFromSecret("validator1")
Expand Down
31 changes: 23 additions & 8 deletions ledger/vm/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,43 @@ import (
"math/big"

"github.com/thetatoken/theta/common"
"github.com/thetatoken/theta/core"
"github.com/thetatoken/theta/ledger/state"
"github.com/thetatoken/theta/ledger/types"
"github.com/thetatoken/theta/ledger/vm/params"
)

type BlockInfo struct {
Height uint64
Timestamp *big.Int
ChainID string
}

func NewBlockInfo(height uint64, timestamp *big.Int, chainID string) *BlockInfo {
return &BlockInfo{
Height: height,
Timestamp: timestamp,
ChainID: chainID,
}
}

// Execute executes the given smart contract
func Execute(parentBlock *core.Block, tx *types.SmartContractTx, storeView *state.StoreView) (evmRet common.Bytes,
func Execute(parentBlockInfo *BlockInfo, tx *types.SmartContractTx, statedb StateDB) (evmRet common.Bytes,
contractAddr common.Address, gasUsed uint64, evmErr error) {
context := Context{
CanTransfer: CanTransfer,
Transfer: Transfer,
Origin: tx.From.Address,
GasPrice: tx.GasPrice,
GasLimit: tx.GasLimit,
BlockNumber: new(big.Int).SetUint64(parentBlock.Height + 1),
Time: parentBlock.Timestamp,
BlockNumber: new(big.Int).SetUint64(parentBlockInfo.Height + 1),
Time: parentBlockInfo.Timestamp,
Difficulty: new(big.Int).SetInt64(0),
}
chainIDBigInt := types.MapChainID(parentBlock.ChainID, context.BlockNumber.Uint64())
chainIDBigInt := types.MapChainID(parentBlockInfo.ChainID, context.BlockNumber.Uint64())
chainConfig := &params.ChainConfig{
ChainID: chainIDBigInt,
}
config := Config{}
evm := NewEVM(context, storeView, chainConfig, config)
evm := NewEVM(context, statedb, chainConfig, config)

value := tx.From.Coins.TFuelWei
if value == nil {
Expand All @@ -49,7 +61,10 @@ func Execute(parentBlock *core.Block, tx *types.SmartContractTx, storeView *stat
// if gasLimit > maxGasLimit {
// return common.Bytes{}, common.Address{}, 0, ErrInvalidGasLimit
// }
blockHeight := storeView.Height() + 1

// blockHeight := storeView.Height() + 1
blockHeight := statedb.GetBlockHeight() // GetBlockHeight() returns storeView.Height() + 1 so it is equivalent to the above commented line

maxGasLimit := types.GetMaxGasLimit(blockHeight)
if new(big.Int).SetUint64(gasLimit).Cmp(maxGasLimit) > 0 {
return common.Bytes{}, common.Address{}, 0, ErrInvalidGasLimit
Expand Down
3 changes: 2 additions & 1 deletion ledger/vm/params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ const (
MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.

MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
MaxCodeSizeForMetachain = 49152 // Maximum bytecode to permit for a contract

// Precompiled contract gas prices

Expand Down
Loading

0 comments on commit c6806c2

Please sign in to comment.