diff --git a/config/config.go b/config/config.go index 169cce8..39174b4 100644 --- a/config/config.go +++ b/config/config.go @@ -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) @@ -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 } diff --git a/internal/orchestrator/simulator.go b/internal/orchestrator/simulator.go index 1f1df52..71bc0cc 100644 --- a/internal/orchestrator/simulator.go +++ b/internal/orchestrator/simulator.go @@ -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" ) @@ -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 @@ -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: ¶ms.ChainConfig{ ChainID: big.NewInt(1337), diff --git a/internal/orchestrator/statedb.go b/internal/orchestrator/statedb.go index fbc4f1d..f4a305e 100644 --- a/internal/orchestrator/statedb.go +++ b/internal/orchestrator/statedb.go @@ -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. // @@ -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 @@ -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 { @@ -710,4 +706,3 @@ func (s *SimulationStateDB) GetFetchErrors() []error { copy(result, s.fetchErrors) return result } - diff --git a/internal/shard/evm.go b/internal/shard/evm.go index 48e9a98..5a5be15 100644 --- a/internal/shard/evm.go +++ b/internal/shard/evm.go @@ -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{ diff --git a/internal/shard/server.go b/internal/shard/server.go index d5a81dd..7f6afc5 100644 --- a/internal/shard/server.go +++ b/internal/shard/server.go @@ -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{}{ @@ -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 { @@ -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) @@ -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()) } @@ -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)", @@ -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. @@ -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) @@ -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 @@ -1251,7 +1250,7 @@ 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) @@ -1259,7 +1258,7 @@ func (s *Server) handleTxSubmit(w http.ResponseWriter, r *http.Request) { } // 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) @@ -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 @@ -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 } diff --git a/internal/shard/shard_test.go b/internal/shard/shard_test.go index d78f49d..4eb161e 100644 --- a/internal/shard/shard_test.go +++ b/internal/shard/shard_test.go @@ -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) }