@nomicfoundation/edr 0.10.0 → 0.12.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +26 -23
- package/index.d.ts +145 -76
- package/index.js +31 -3
- package/package.json +16 -14
- package/src/account.rs +41 -11
- package/src/block.rs +1 -1
- package/src/call_override.rs +1 -1
- package/src/cast.rs +54 -2
- package/src/chains/generic.rs +51 -0
- package/src/chains/l1.rs +260 -0
- package/src/chains/op.rs +368 -0
- package/src/chains.rs +7 -0
- package/src/config.rs +393 -67
- package/src/context.rs +135 -17
- package/src/lib.rs +28 -14
- package/src/log.rs +2 -2
- package/src/logger.rs +54 -1152
- package/src/provider/factory.rs +22 -0
- package/src/provider/response.rs +70 -0
- package/src/provider.rs +55 -322
- package/src/result.rs +44 -44
- package/src/scenarios.rs +12 -18
- package/src/subscription.rs +32 -0
- package/src/trace/exit.rs +8 -9
- package/src/trace/return_data.rs +1 -1
- package/src/trace/solidity_stack_trace.rs +5 -4
- package/src/trace.rs +9 -7
- package/src/withdrawal.rs +1 -1
- package/src/provider/config.rs +0 -291
- package/src/subscribe.rs +0 -63
package/src/cast.rs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
use edr_eth::{Address,
|
|
1
|
+
use edr_eth::{Address, B64, B256, Bytecode, Bytes, U256};
|
|
2
2
|
use napi::{
|
|
3
|
-
bindgen_prelude::{BigInt, Buffer},
|
|
4
3
|
Status,
|
|
4
|
+
bindgen_prelude::{BigInt, Buffer, Uint8Array},
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
/// An attempted conversion that consumes `self`, which may or may not be
|
|
@@ -29,6 +29,20 @@ impl TryCast<Address> for Buffer {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
impl TryCast<Address> for Uint8Array {
|
|
33
|
+
type Error = napi::Error;
|
|
34
|
+
|
|
35
|
+
fn try_cast(self) -> std::result::Result<Address, Self::Error> {
|
|
36
|
+
if self.len() != 20 {
|
|
37
|
+
return Err(napi::Error::new(
|
|
38
|
+
Status::InvalidArg,
|
|
39
|
+
"Uint8Array was expected to be 20 bytes.".to_string(),
|
|
40
|
+
));
|
|
41
|
+
}
|
|
42
|
+
Ok(Address::from_slice(&self))
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
32
46
|
impl TryCast<B64> for Buffer {
|
|
33
47
|
type Error = napi::Error;
|
|
34
48
|
|
|
@@ -57,6 +71,20 @@ impl TryCast<B256> for Buffer {
|
|
|
57
71
|
}
|
|
58
72
|
}
|
|
59
73
|
|
|
74
|
+
impl TryCast<Bytecode> for Uint8Array {
|
|
75
|
+
type Error = napi::Error;
|
|
76
|
+
|
|
77
|
+
fn try_cast(self) -> std::result::Result<Bytecode, Self::Error> {
|
|
78
|
+
let bytes = Bytes::copy_from_slice(&self);
|
|
79
|
+
Bytecode::new_raw_checked(bytes).map_err(|error| {
|
|
80
|
+
napi::Error::new(
|
|
81
|
+
Status::InvalidArg,
|
|
82
|
+
format!("Uint8Array was not valid bytecode: {error}"),
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
60
88
|
impl TryCast<u64> for BigInt {
|
|
61
89
|
type Error = napi::Error;
|
|
62
90
|
|
|
@@ -81,6 +109,30 @@ impl TryCast<u64> for BigInt {
|
|
|
81
109
|
}
|
|
82
110
|
}
|
|
83
111
|
|
|
112
|
+
impl TryCast<u128> for BigInt {
|
|
113
|
+
type Error = napi::Error;
|
|
114
|
+
|
|
115
|
+
fn try_cast(self) -> std::result::Result<u128, Self::Error> {
|
|
116
|
+
let (signed, value, lossless) = self.get_u128();
|
|
117
|
+
|
|
118
|
+
if signed {
|
|
119
|
+
return Err(napi::Error::new(
|
|
120
|
+
Status::InvalidArg,
|
|
121
|
+
"BigInt was expected to be unsigned.".to_string(),
|
|
122
|
+
));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if !lossless {
|
|
126
|
+
return Err(napi::Error::new(
|
|
127
|
+
Status::InvalidArg,
|
|
128
|
+
"BigInt was expected to fit within 128 bits.".to_string(),
|
|
129
|
+
));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Ok(value)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
84
136
|
impl TryCast<usize> for BigInt {
|
|
85
137
|
type Error = napi::Error;
|
|
86
138
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
use std::sync::Arc;
|
|
2
|
+
|
|
3
|
+
use edr_eth::l1;
|
|
4
|
+
use edr_generic::GenericChainSpec;
|
|
5
|
+
use edr_napi_core::{
|
|
6
|
+
logger::{self, Logger},
|
|
7
|
+
provider::{self, ProviderBuilder, SyncProviderFactory},
|
|
8
|
+
spec::SyncNapiSpec as _,
|
|
9
|
+
subscription,
|
|
10
|
+
};
|
|
11
|
+
use edr_solidity::contract_decoder::ContractDecoder;
|
|
12
|
+
use napi_derive::napi;
|
|
13
|
+
|
|
14
|
+
use crate::provider::ProviderFactory;
|
|
15
|
+
|
|
16
|
+
pub struct GenericChainProviderFactory;
|
|
17
|
+
|
|
18
|
+
impl SyncProviderFactory for GenericChainProviderFactory {
|
|
19
|
+
fn create_provider_builder(
|
|
20
|
+
&self,
|
|
21
|
+
env: &napi::Env,
|
|
22
|
+
provider_config: edr_napi_core::provider::Config,
|
|
23
|
+
logger_config: logger::Config,
|
|
24
|
+
subscription_config: subscription::Config,
|
|
25
|
+
contract_decoder: Arc<ContractDecoder>,
|
|
26
|
+
) -> napi::Result<Box<dyn provider::Builder>> {
|
|
27
|
+
let logger = Logger::<GenericChainSpec>::new(logger_config, Arc::clone(&contract_decoder))?;
|
|
28
|
+
|
|
29
|
+
let provider_config =
|
|
30
|
+
edr_provider::ProviderConfig::<l1::SpecId>::try_from(provider_config)?;
|
|
31
|
+
|
|
32
|
+
let subscription_callback =
|
|
33
|
+
subscription::Callback::new(env, subscription_config.subscription_callback)?;
|
|
34
|
+
|
|
35
|
+
Ok(Box::new(ProviderBuilder::new(
|
|
36
|
+
contract_decoder,
|
|
37
|
+
Box::new(logger),
|
|
38
|
+
provider_config,
|
|
39
|
+
subscription_callback,
|
|
40
|
+
)))
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#[napi]
|
|
45
|
+
pub const GENERIC_CHAIN_TYPE: &str = GenericChainSpec::CHAIN_TYPE;
|
|
46
|
+
|
|
47
|
+
#[napi]
|
|
48
|
+
pub fn generic_chain_provider_factory() -> ProviderFactory {
|
|
49
|
+
let factory: Arc<dyn SyncProviderFactory> = Arc::new(GenericChainProviderFactory);
|
|
50
|
+
factory.into()
|
|
51
|
+
}
|
package/src/chains/l1.rs
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
use std::{str::FromStr, sync::Arc};
|
|
2
|
+
|
|
3
|
+
use edr_eth::l1::{self, L1ChainSpec};
|
|
4
|
+
use edr_evm::eips::{
|
|
5
|
+
eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_UNSUPPORTED_BYTECODE},
|
|
6
|
+
eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_BYTECODE},
|
|
7
|
+
};
|
|
8
|
+
use edr_napi_core::{
|
|
9
|
+
logger::Logger,
|
|
10
|
+
provider::{self, ProviderBuilder, SyncProviderFactory},
|
|
11
|
+
spec::SyncNapiSpec as _,
|
|
12
|
+
subscription,
|
|
13
|
+
};
|
|
14
|
+
use edr_solidity::contract_decoder::ContractDecoder;
|
|
15
|
+
use napi::bindgen_prelude::{BigInt, Uint8Array};
|
|
16
|
+
use napi_derive::napi;
|
|
17
|
+
|
|
18
|
+
use crate::{account::Account, provider::ProviderFactory};
|
|
19
|
+
|
|
20
|
+
pub struct L1ProviderFactory;
|
|
21
|
+
|
|
22
|
+
impl SyncProviderFactory for L1ProviderFactory {
|
|
23
|
+
fn create_provider_builder(
|
|
24
|
+
&self,
|
|
25
|
+
env: &napi::Env,
|
|
26
|
+
provider_config: edr_napi_core::provider::Config,
|
|
27
|
+
logger_config: edr_napi_core::logger::Config,
|
|
28
|
+
subscription_config: edr_napi_core::subscription::Config,
|
|
29
|
+
contract_decoder: Arc<ContractDecoder>,
|
|
30
|
+
) -> napi::Result<Box<dyn provider::Builder>> {
|
|
31
|
+
let logger = Logger::<L1ChainSpec>::new(logger_config, Arc::clone(&contract_decoder))?;
|
|
32
|
+
|
|
33
|
+
let provider_config =
|
|
34
|
+
edr_provider::ProviderConfig::<l1::SpecId>::try_from(provider_config)?;
|
|
35
|
+
|
|
36
|
+
let subscription_callback =
|
|
37
|
+
subscription::Callback::new(env, subscription_config.subscription_callback)?;
|
|
38
|
+
|
|
39
|
+
Ok(Box::new(ProviderBuilder::new(
|
|
40
|
+
contract_decoder,
|
|
41
|
+
Box::new(logger),
|
|
42
|
+
provider_config,
|
|
43
|
+
subscription_callback,
|
|
44
|
+
)))
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#[napi]
|
|
49
|
+
pub const L1_CHAIN_TYPE: &str = L1ChainSpec::CHAIN_TYPE;
|
|
50
|
+
|
|
51
|
+
#[napi]
|
|
52
|
+
pub fn l1_genesis_state(hardfork: SpecId) -> Vec<Account> {
|
|
53
|
+
// Use closures for lazy execution
|
|
54
|
+
let beacon_roots_account_constructor = || Account {
|
|
55
|
+
address: Uint8Array::from(BEACON_ROOTS_ADDRESS.as_slice()),
|
|
56
|
+
balance: BigInt::from(0u64),
|
|
57
|
+
nonce: BigInt::from(0u64),
|
|
58
|
+
code: Some(Uint8Array::from(BEACON_ROOTS_BYTECODE)),
|
|
59
|
+
storage: Vec::new(),
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
let history_storage_account_constructor = || Account {
|
|
63
|
+
address: Uint8Array::from(HISTORY_STORAGE_ADDRESS.as_slice()),
|
|
64
|
+
balance: BigInt::from(0u64),
|
|
65
|
+
nonce: BigInt::from(0u64),
|
|
66
|
+
code: Some(Uint8Array::from(HISTORY_STORAGE_UNSUPPORTED_BYTECODE)),
|
|
67
|
+
storage: Vec::new(),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
if hardfork < SpecId::Cancun {
|
|
71
|
+
Vec::new()
|
|
72
|
+
} else if hardfork < SpecId::Prague {
|
|
73
|
+
vec![beacon_roots_account_constructor()]
|
|
74
|
+
} else {
|
|
75
|
+
vec![
|
|
76
|
+
beacon_roots_account_constructor(),
|
|
77
|
+
history_storage_account_constructor(),
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#[napi]
|
|
83
|
+
pub fn l1_provider_factory() -> ProviderFactory {
|
|
84
|
+
let factory: Arc<dyn SyncProviderFactory> = Arc::new(L1ProviderFactory);
|
|
85
|
+
factory.into()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Identifier for the Ethereum spec.
|
|
89
|
+
#[napi]
|
|
90
|
+
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
|
91
|
+
pub enum SpecId {
|
|
92
|
+
/// Frontier
|
|
93
|
+
Frontier = 0,
|
|
94
|
+
/// Frontier Thawing
|
|
95
|
+
FrontierThawing = 1,
|
|
96
|
+
/// Homestead
|
|
97
|
+
Homestead = 2,
|
|
98
|
+
/// DAO Fork
|
|
99
|
+
DaoFork = 3,
|
|
100
|
+
/// Tangerine
|
|
101
|
+
Tangerine = 4,
|
|
102
|
+
/// Spurious Dragon
|
|
103
|
+
SpuriousDragon = 5,
|
|
104
|
+
/// Byzantium
|
|
105
|
+
Byzantium = 6,
|
|
106
|
+
/// Constantinople
|
|
107
|
+
Constantinople = 7,
|
|
108
|
+
/// Petersburg
|
|
109
|
+
Petersburg = 8,
|
|
110
|
+
/// Istanbul
|
|
111
|
+
Istanbul = 9,
|
|
112
|
+
/// Muir Glacier
|
|
113
|
+
MuirGlacier = 10,
|
|
114
|
+
/// Berlin
|
|
115
|
+
Berlin = 11,
|
|
116
|
+
/// London
|
|
117
|
+
London = 12,
|
|
118
|
+
/// Arrow Glacier
|
|
119
|
+
ArrowGlacier = 13,
|
|
120
|
+
/// Gray Glacier
|
|
121
|
+
GrayGlacier = 14,
|
|
122
|
+
/// Merge
|
|
123
|
+
Merge = 15,
|
|
124
|
+
/// Shanghai
|
|
125
|
+
Shanghai = 16,
|
|
126
|
+
/// Cancun
|
|
127
|
+
Cancun = 17,
|
|
128
|
+
/// Prague
|
|
129
|
+
Prague = 18,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
impl FromStr for SpecId {
|
|
133
|
+
type Err = napi::Error;
|
|
134
|
+
|
|
135
|
+
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
136
|
+
match s {
|
|
137
|
+
edr_eth::l1::hardfork::name::FRONTIER => Ok(SpecId::Frontier),
|
|
138
|
+
edr_eth::l1::hardfork::name::FRONTIER_THAWING => Ok(SpecId::FrontierThawing),
|
|
139
|
+
edr_eth::l1::hardfork::name::HOMESTEAD => Ok(SpecId::Homestead),
|
|
140
|
+
edr_eth::l1::hardfork::name::DAO_FORK => Ok(SpecId::DaoFork),
|
|
141
|
+
edr_eth::l1::hardfork::name::TANGERINE => Ok(SpecId::Tangerine),
|
|
142
|
+
edr_eth::l1::hardfork::name::SPURIOUS_DRAGON => Ok(SpecId::SpuriousDragon),
|
|
143
|
+
edr_eth::l1::hardfork::name::BYZANTIUM => Ok(SpecId::Byzantium),
|
|
144
|
+
edr_eth::l1::hardfork::name::CONSTANTINOPLE => Ok(SpecId::Constantinople),
|
|
145
|
+
edr_eth::l1::hardfork::name::PETERSBURG => Ok(SpecId::Petersburg),
|
|
146
|
+
edr_eth::l1::hardfork::name::ISTANBUL => Ok(SpecId::Istanbul),
|
|
147
|
+
edr_eth::l1::hardfork::name::MUIR_GLACIER => Ok(SpecId::MuirGlacier),
|
|
148
|
+
edr_eth::l1::hardfork::name::BERLIN => Ok(SpecId::Berlin),
|
|
149
|
+
edr_eth::l1::hardfork::name::LONDON => Ok(SpecId::London),
|
|
150
|
+
edr_eth::l1::hardfork::name::ARROW_GLACIER => Ok(SpecId::ArrowGlacier),
|
|
151
|
+
edr_eth::l1::hardfork::name::GRAY_GLACIER => Ok(SpecId::GrayGlacier),
|
|
152
|
+
edr_eth::l1::hardfork::name::MERGE => Ok(SpecId::Merge),
|
|
153
|
+
edr_eth::l1::hardfork::name::SHANGHAI => Ok(SpecId::Shanghai),
|
|
154
|
+
edr_eth::l1::hardfork::name::CANCUN => Ok(SpecId::Cancun),
|
|
155
|
+
edr_eth::l1::hardfork::name::PRAGUE => Ok(SpecId::Prague),
|
|
156
|
+
_ => Err(napi::Error::new(
|
|
157
|
+
napi::Status::InvalidArg,
|
|
158
|
+
format!("The provided hardfork `{s}` is not supported."),
|
|
159
|
+
)),
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
impl From<SpecId> for edr_eth::l1::SpecId {
|
|
165
|
+
fn from(value: SpecId) -> Self {
|
|
166
|
+
match value {
|
|
167
|
+
SpecId::Frontier => edr_eth::l1::SpecId::FRONTIER,
|
|
168
|
+
SpecId::FrontierThawing => edr_eth::l1::SpecId::FRONTIER_THAWING,
|
|
169
|
+
SpecId::Homestead => edr_eth::l1::SpecId::HOMESTEAD,
|
|
170
|
+
SpecId::DaoFork => edr_eth::l1::SpecId::DAO_FORK,
|
|
171
|
+
SpecId::Tangerine => edr_eth::l1::SpecId::TANGERINE,
|
|
172
|
+
SpecId::SpuriousDragon => edr_eth::l1::SpecId::SPURIOUS_DRAGON,
|
|
173
|
+
SpecId::Byzantium => edr_eth::l1::SpecId::BYZANTIUM,
|
|
174
|
+
SpecId::Constantinople => edr_eth::l1::SpecId::CONSTANTINOPLE,
|
|
175
|
+
SpecId::Petersburg => edr_eth::l1::SpecId::PETERSBURG,
|
|
176
|
+
SpecId::Istanbul => edr_eth::l1::SpecId::ISTANBUL,
|
|
177
|
+
SpecId::MuirGlacier => edr_eth::l1::SpecId::MUIR_GLACIER,
|
|
178
|
+
SpecId::Berlin => edr_eth::l1::SpecId::BERLIN,
|
|
179
|
+
SpecId::London => edr_eth::l1::SpecId::LONDON,
|
|
180
|
+
SpecId::ArrowGlacier => edr_eth::l1::SpecId::ARROW_GLACIER,
|
|
181
|
+
SpecId::GrayGlacier => edr_eth::l1::SpecId::GRAY_GLACIER,
|
|
182
|
+
SpecId::Merge => edr_eth::l1::SpecId::MERGE,
|
|
183
|
+
SpecId::Shanghai => edr_eth::l1::SpecId::SHANGHAI,
|
|
184
|
+
SpecId::Cancun => edr_eth::l1::SpecId::CANCUN,
|
|
185
|
+
SpecId::Prague => edr_eth::l1::SpecId::PRAGUE,
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// Tries to parse the provided string to create a [`SpecId`] instance.
|
|
191
|
+
///
|
|
192
|
+
/// Returns an error if the string does not match any known hardfork.
|
|
193
|
+
#[napi]
|
|
194
|
+
pub fn l1_hardfork_from_string(hardfork: String) -> napi::Result<SpecId> {
|
|
195
|
+
hardfork.parse()
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
#[napi]
|
|
199
|
+
pub fn l1_hardfork_to_string(harfork: SpecId) -> &'static str {
|
|
200
|
+
match harfork {
|
|
201
|
+
SpecId::Frontier => edr_eth::l1::hardfork::name::FRONTIER,
|
|
202
|
+
SpecId::FrontierThawing => edr_eth::l1::hardfork::name::FRONTIER_THAWING,
|
|
203
|
+
SpecId::Homestead => edr_eth::l1::hardfork::name::HOMESTEAD,
|
|
204
|
+
SpecId::DaoFork => edr_eth::l1::hardfork::name::DAO_FORK,
|
|
205
|
+
SpecId::Tangerine => edr_eth::l1::hardfork::name::TANGERINE,
|
|
206
|
+
SpecId::SpuriousDragon => edr_eth::l1::hardfork::name::SPURIOUS_DRAGON,
|
|
207
|
+
SpecId::Byzantium => edr_eth::l1::hardfork::name::BYZANTIUM,
|
|
208
|
+
SpecId::Constantinople => edr_eth::l1::hardfork::name::CONSTANTINOPLE,
|
|
209
|
+
SpecId::Petersburg => edr_eth::l1::hardfork::name::PETERSBURG,
|
|
210
|
+
SpecId::Istanbul => edr_eth::l1::hardfork::name::ISTANBUL,
|
|
211
|
+
SpecId::MuirGlacier => edr_eth::l1::hardfork::name::MUIR_GLACIER,
|
|
212
|
+
SpecId::Berlin => edr_eth::l1::hardfork::name::BERLIN,
|
|
213
|
+
SpecId::London => edr_eth::l1::hardfork::name::LONDON,
|
|
214
|
+
SpecId::ArrowGlacier => edr_eth::l1::hardfork::name::ARROW_GLACIER,
|
|
215
|
+
SpecId::GrayGlacier => edr_eth::l1::hardfork::name::GRAY_GLACIER,
|
|
216
|
+
SpecId::Merge => edr_eth::l1::hardfork::name::MERGE,
|
|
217
|
+
SpecId::Shanghai => edr_eth::l1::hardfork::name::SHANGHAI,
|
|
218
|
+
SpecId::Cancun => edr_eth::l1::hardfork::name::CANCUN,
|
|
219
|
+
SpecId::Prague => edr_eth::l1::hardfork::name::PRAGUE,
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/// Returns the latest supported OP hardfork.
|
|
224
|
+
///
|
|
225
|
+
/// The returned value will be updated after each network upgrade.
|
|
226
|
+
#[napi]
|
|
227
|
+
pub fn l1_hardfork_latest() -> SpecId {
|
|
228
|
+
SpecId::Prague
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
macro_rules! export_spec_id {
|
|
232
|
+
($($variant:ident),*) => {
|
|
233
|
+
$(
|
|
234
|
+
#[napi]
|
|
235
|
+
pub const $variant: &str = edr_eth::l1::hardfork::name::$variant;
|
|
236
|
+
)*
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export_spec_id!(
|
|
241
|
+
FRONTIER,
|
|
242
|
+
FRONTIER_THAWING,
|
|
243
|
+
HOMESTEAD,
|
|
244
|
+
DAO_FORK,
|
|
245
|
+
TANGERINE,
|
|
246
|
+
SPURIOUS_DRAGON,
|
|
247
|
+
BYZANTIUM,
|
|
248
|
+
CONSTANTINOPLE,
|
|
249
|
+
PETERSBURG,
|
|
250
|
+
ISTANBUL,
|
|
251
|
+
MUIR_GLACIER,
|
|
252
|
+
BERLIN,
|
|
253
|
+
LONDON,
|
|
254
|
+
ARROW_GLACIER,
|
|
255
|
+
GRAY_GLACIER,
|
|
256
|
+
MERGE,
|
|
257
|
+
SHANGHAI,
|
|
258
|
+
CANCUN,
|
|
259
|
+
PRAGUE
|
|
260
|
+
);
|