Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ type NetworkConfig struct {
MaxDelayMs int `json:"max_delay_ms"` // Maximum delay in milliseconds
}

var Configuration Config

func GetConfig() Config {
return Configuration
}

// Load reads and parses the config.json file
func Load(configPath string) (*Config, error) {
data, err := os.ReadFile(configPath)
Expand All @@ -33,6 +39,7 @@ func Load(configPath string) (*Config, error) {
return nil, fmt.Errorf("failed to parse config file: %w", err)
}

Configuration = *cfg
return cfg, nil
}

Expand Down
7 changes: 4 additions & 3 deletions internal/orchestrator/simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
"github.com/sharding-experiment/sharding/config"
"github.com/sharding-experiment/sharding/internal/protocol"
)

Expand All @@ -26,8 +27,8 @@ type Simulator struct {
fetcher *StateFetcher
queue chan *simulationJob
results map[string]*SimulationResult
onSuccess func(tx protocol.CrossShardTx) // Callback when simulation succeeds
onError func(tx protocol.CrossShardTx) // Callback when simulation fails (V2)
onSuccess func(tx protocol.CrossShardTx) // Callback when simulation succeeds
onError func(tx protocol.CrossShardTx) // Callback when simulation fails (V2)
chainConfig *params.ChainConfig
vmConfig vm.Config
numShards int // V2.2: Total number of shards for address mapping
Expand Down Expand Up @@ -55,7 +56,7 @@ func NewSimulator(fetcher *StateFetcher, onSuccess func(tx protocol.CrossShardTx
queue: make(chan *simulationJob, 100),
results: make(map[string]*SimulationResult),
onSuccess: onSuccess,
numShards: NumShards, // V2.2: Use constant from statedb.go
numShards: config.GetConfig().ShardNum, // V2.2: Use constant from statedb.go
stopCleanup: make(chan struct{}),
chainConfig: &params.ChainConfig{
ChainID: big.NewInt(1337),
Expand Down
39 changes: 17 additions & 22 deletions internal/orchestrator/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ import (
"github.com/sharding-experiment/sharding/internal/protocol"
)

// NumShards is the total number of shards in the system
// Used for address-to-shard mapping
const NumShards = 8

// SimulationStateDB implements vm.StateDB for cross-shard transaction simulation.
// It fetches state on-demand from State Shards and tracks all reads/writes for RwSet construction.
//
Expand All @@ -29,32 +25,32 @@ const NumShards = 8
// This design allows the EVM to continue executing (collecting partial RwSet data for debugging)
// while ensuring the simulation ultimately fails if any required state couldn't be fetched.
type SimulationStateDB struct {
mu sync.RWMutex
txID string
fetcher *StateFetcher
mu sync.RWMutex
txID string
fetcher *StateFetcher

// Cached account state (fetched on first access)
accounts map[common.Address]*accountState
accounts map[common.Address]*accountState

// Track reads and writes for RwSet construction
reads map[common.Address]map[common.Hash]common.Hash // addr -> slot -> value read
writes map[common.Address]map[common.Hash]common.Hash // addr -> slot -> new value written
writeOlds map[common.Address]map[common.Hash]common.Hash // addr -> slot -> old value before write
reads map[common.Address]map[common.Hash]common.Hash // addr -> slot -> value read
writes map[common.Address]map[common.Hash]common.Hash // addr -> slot -> new value written
writeOlds map[common.Address]map[common.Hash]common.Hash // addr -> slot -> old value before write

// Access list for EIP-2929
accessList *accessList
accessList *accessList

// Transaction logs
logs []*types.Log
logs []*types.Log

// Refund counter
refund uint64
refund uint64

// Snapshots for revert
snapshots []snapshot
snapshots []snapshot

// Transient storage (EIP-1153)
transient map[common.Address]map[common.Hash]common.Hash
transient map[common.Address]map[common.Hash]common.Hash

// Track fetch errors - if any fetch fails, simulation should abort
fetchErrors []error
Expand All @@ -72,11 +68,11 @@ type accountState struct {
}

type snapshot struct {
accounts map[common.Address]*accountState
reads map[common.Address]map[common.Hash]common.Hash
writes map[common.Address]map[common.Hash]common.Hash
refund uint64
logsLen int
accounts map[common.Address]*accountState
reads map[common.Address]map[common.Hash]common.Hash
writes map[common.Address]map[common.Hash]common.Hash
refund uint64
logsLen int
}

type accessList struct {
Expand Down Expand Up @@ -710,4 +706,3 @@ func (s *SimulationStateDB) GetFetchErrors() []error {
copy(result, s.fetchErrors)
return result
}

2 changes: 1 addition & 1 deletion internal/shard/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ func (e *EVMState) SimulateCallForRwSet(caller, contract common.Address, input [

// Create tracking wrapper - for local simulation, all addresses are "local"
// We track reads/writes regardless of shard assignment
trackingDB := NewTrackingStateDB(e.stateDB, refBlock.ShardNum, NumShards)
trackingDB := NewTrackingStateDB(e.stateDB, refBlock.ShardNum, config.GetConfig().ShardNum)

// Create EVM with tracking state
blockCtx := vm.BlockContext{
Expand Down
41 changes: 20 additions & 21 deletions internal/shard/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ func (s *Server) handleDeploy(w http.ResponseWriter, r *http.Request) {
}

// Use tracked deployment to capture constructor storage writes
contractAddr, returnData, gasUsed, _, storageWrites, err := s.evmState.DeployContractTracked(from, bytecode, value, gas, NumShards)
contractAddr, returnData, gasUsed, _, storageWrites, err := s.evmState.DeployContractTracked(from, bytecode, value, gas, config.GetConfig().ShardNum)
if err != nil {
log.Printf("Shard %d: Deploy failed: %v", s.shardID, err)
json.NewEncoder(w).Encode(map[string]interface{}{
Expand All @@ -597,7 +597,7 @@ func (s *Server) handleDeploy(w http.ResponseWriter, r *http.Request) {
}

// Check which shard this contract address maps to
targetShard := int(contractAddr[len(contractAddr)-1]) % NumShards
targetShard := int(contractAddr[len(contractAddr)-1]) % config.GetConfig().ShardNum
deployedCode := s.evmState.GetCode(contractAddr)

if targetShard != s.shardID {
Expand Down Expand Up @@ -669,7 +669,7 @@ func (s *Server) handleSetCode(w http.ResponseWriter, r *http.Request) {
code := common.FromHex(req.Code)

// Verify this address belongs to this shard
targetShard := int(addr[len(addr)-1]) % NumShards
targetShard := int(addr[len(addr)-1]) % config.GetConfig().ShardNum
if targetShard != s.shardID {
http.Error(w, fmt.Sprintf("address %s belongs to shard %d, not %d",
addr.Hex(), targetShard, s.shardID), http.StatusBadRequest)
Expand Down Expand Up @@ -1026,7 +1026,7 @@ func (s *Server) processOrchestratorBlock(block *protocol.OrchestratorShardBlock
if tx.FromShard == s.shardID {
// V2 Optimistic: Don't lock funds now - Lock tx will validate and lock atomically
// Store pending credit info for destination if this shard is also destination
toShard := int(tx.To[len(tx.To)-1]) % NumShards
toShard := int(tx.To[len(tx.To)-1]) % config.GetConfig().ShardNum
if tx.Value.ToBigInt().Sign() > 0 && toShard == s.shardID {
s.chain.StorePendingCredit(tx.ID, tx.To, tx.Value.ToBigInt())
}
Expand All @@ -1050,7 +1050,7 @@ func (s *Server) processOrchestratorBlock(block *protocol.OrchestratorShardBlock
// V2 Optimistic: Don't lock addresses now - Lock tx validates+locks atomically

// Store pending credit ONLY for tx.To address
toShard := int(tx.To[len(tx.To)-1]) % NumShards
toShard := int(tx.To[len(tx.To)-1]) % config.GetConfig().ShardNum
if tx.Value.ToBigInt().Sign() > 0 && toShard == s.shardID {
s.chain.StorePendingCredit(tx.ID, tx.To, tx.Value.ToBigInt())
log.Printf("Shard %d: Pending credit %s for %s (value=%s)",
Expand Down Expand Up @@ -1089,12 +1089,12 @@ type StateFetchRequest struct {

// StateFetchResponse is the response format for /state/fetch
type StateFetchResponse struct {
Success bool `json:"success"`
Error string `json:"error,omitempty"`
Balance *big.Int `json:"balance"`
Nonce uint64 `json:"nonce"`
Code []byte `json:"code,omitempty"`
CodeHash common.Hash `json:"code_hash"`
Success bool `json:"success"`
Error string `json:"error,omitempty"`
Balance *big.Int `json:"balance"`
Nonce uint64 `json:"nonce"`
Code []byte `json:"code,omitempty"`
CodeHash common.Hash `json:"code_hash"`
}

// handleStateFetch returns account state WITHOUT acquiring locks.
Expand Down Expand Up @@ -1135,7 +1135,7 @@ func (s *Server) handleRwSet(w http.ResponseWriter, r *http.Request) {
s.shardID, req.TxID, req.Address.Hex())

// Verify the target address belongs to this shard
targetShard := int(req.Address[len(req.Address)-1]) % NumShards
targetShard := int(req.Address[len(req.Address)-1]) % config.GetConfig().ShardNum
if targetShard != s.shardID {
log.Printf("Shard %d: RwSetRequest for address %s belongs to shard %d",
s.shardID, req.Address.Hex(), targetShard)
Expand Down Expand Up @@ -1201,11 +1201,10 @@ type TxSubmitRequest struct {
}

const (
NumShards = 8 // TODO: make configurable (see issue #28)
MinGasLimit = 21_000 // Minimum gas for a basic transfer (Ethereum standard)
DefaultGasLimit = 1_000_000 // Default gas limit for transactions
MaxGasLimit = 30_000_000 // Maximum gas limit per transaction
SimulationGasLimit = 3_000_000 // Higher gas limit for simulation
MinGasLimit = 21_000 // Minimum gas for a basic transfer (Ethereum standard)
DefaultGasLimit = 1_000_000 // Default gas limit for transactions
MaxGasLimit = 30_000_000 // Maximum gas limit per transaction
SimulationGasLimit = 3_000_000 // Higher gas limit for simulation
)

// handleTxSubmit is the unified transaction endpoint
Expand Down Expand Up @@ -1251,15 +1250,15 @@ func (s *Server) handleTxSubmit(w http.ResponseWriter, r *http.Request) {
}

// Check which shard the sender is on
fromShard := int(from[len(from)-1]) % NumShards
fromShard := int(from[len(from)-1]) % config.GetConfig().ShardNum
if fromShard != s.shardID {
// Sender is on a different shard - reject
http.Error(w, fmt.Sprintf("sender %s belongs to shard %d, not shard %d", from.Hex(), fromShard, s.shardID), http.StatusBadRequest)
return
}

// Quick check: is 'to' address on another shard?
toShard := int(to[len(to)-1]) % NumShards
toShard := int(to[len(to)-1]) % config.GetConfig().ShardNum

// Check if 'to' is a contract (has code)
toCode := s.evmState.GetCode(to)
Expand All @@ -1286,7 +1285,7 @@ func (s *Server) handleTxSubmit(w http.ResponseWriter, r *http.Request) {
simGas = SimulationGasLimit
}

_, accessedAddrs, hasCrossShard, simErr := s.evmState.SimulateCall(from, to, data, value, simGas, s.shardID, NumShards)
_, accessedAddrs, hasCrossShard, simErr := s.evmState.SimulateCall(from, to, data, value, simGas, s.shardID, config.GetConfig().ShardNum)

if simErr != nil {
// Classify the error to determine if it's cross-shard or a real error
Expand All @@ -1307,7 +1306,7 @@ func (s *Server) handleTxSubmit(w http.ResponseWriter, r *http.Request) {
// Build map of cross-shard addresses
crossShardAddrs = make(map[common.Address]int)
for _, addr := range accessedAddrs {
addrShard := int(addr[len(addr)-1]) % NumShards
addrShard := int(addr[len(addr)-1]) % config.GetConfig().ShardNum
if addrShard != s.shardID {
crossShardAddrs[addr] = addrShard
}
Expand Down
2 changes: 1 addition & 1 deletion internal/shard/shard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ func TestShardAssignment(t *testing.T) {

for _, tc := range tests {
addr := common.HexToAddress(tc.address)
shard := int(addr[len(addr)-1]) % NumShards
shard := int(addr[len(addr)-1]) % config.GetConfig().ShardNum
if shard != tc.expected {
t.Errorf("Address %s: expected shard %d, got %d", tc.address, tc.expected, shard)
}
Expand Down