thread local chain type vs global chain type ()

* Introduce GLOBAL_CHAIN_TYPE and make CHAIN_TYPE thread_local.
This makes testing more explicit and significantly more robust.

* set_local_chain_type() in tests

* cleanup - weird

* get pool tests working with explicit local chain_type config

* core tests working with explicit local chain_type

* p2p tests working with explicit local chain_type

* store tests working

* cleanup, feedback
This commit is contained in:
Antioch Peverell 2020-05-22 12:51:58 +01:00 committed by GitHub
parent 096b6924ce
commit 6faa0e8d75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 192 additions and 114 deletions

View file

@ -70,7 +70,7 @@ where
/// Mine a chain of specified length to assist with automated tests.
/// Probably a good idea to call clean_output_dir at the beginning and end of each test.
pub fn mine_chain(dir_name: &str, chain_length: u64) -> Chain {
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
let genesis = genesis_block(&keychain);
let mut chain = init_chain(dir_name, genesis.clone());

View file

@ -118,7 +118,7 @@ fn process_block(chain: &Chain, block: &Block) {
fn test_block_a_block_b_block_b_fork_header_c_fork_block_c() {
let chain_dir = ".grin.block_a_block_b_block_b_fork_header_c_fork_block_c";
clean_output_dir(chain_dir);
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let kc = ExtKeychain::from_random_seed(false).unwrap();
let genesis = pow::mine_genesis_block().unwrap();
let last_status = RwLock::new(None);
@ -170,7 +170,7 @@ fn test_block_a_block_b_block_b_fork_header_c_fork_block_c() {
fn test_block_a_block_b_block_b_fork_header_c_fork_block_c_fork() {
let chain_dir = ".grin.block_a_block_b_block_b_fork_header_c_fork_block_c_fork";
clean_output_dir(chain_dir);
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let kc = ExtKeychain::from_random_seed(false).unwrap();
let genesis = pow::mine_genesis_block().unwrap();
let last_status = RwLock::new(None);
@ -226,7 +226,7 @@ fn test_block_a_block_b_block_b_fork_header_c_fork_block_c_fork() {
fn test_block_a_header_b_header_b_fork_block_b_fork_block_b_block_c() {
let chain_dir = ".grin.test_block_a_header_b_header_b_fork_block_b_fork_block_b_block_c";
clean_output_dir(chain_dir);
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let kc = ExtKeychain::from_random_seed(false).unwrap();
let genesis = pow::mine_genesis_block().unwrap();
let last_status = RwLock::new(None);
@ -282,7 +282,7 @@ fn test_block_a_header_b_header_b_fork_block_b_fork_block_b_block_c() {
fn test_block_a_header_b_header_b_fork_block_b_fork_block_b_block_c_fork() {
let chain_dir = ".grin.test_block_a_header_b_header_b_fork_block_b_fork_block_b_block_c_fork";
clean_output_dir(chain_dir);
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let kc = ExtKeychain::from_random_seed(false).unwrap();
let genesis = pow::mine_genesis_block().unwrap();
let last_status = RwLock::new(None);
@ -347,7 +347,7 @@ fn mine_reorg() {
const DIR_NAME: &str = ".grin_reorg";
clean_output_dir(DIR_NAME);
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let kc = ExtKeychain::from_random_seed(false).unwrap();
let genesis = pow::mine_genesis_block().unwrap();
@ -399,7 +399,7 @@ fn mine_reorg() {
#[test]
fn mine_forks() {
clean_output_dir(".grin2");
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
{
let chain = init_chain(".grin2", pow::mine_genesis_block().unwrap());
let kc = ExtKeychain::from_random_seed(false).unwrap();
@ -447,7 +447,7 @@ fn mine_forks() {
#[test]
fn mine_losing_fork() {
clean_output_dir(".grin3");
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let kc = ExtKeychain::from_random_seed(false).unwrap();
{
let chain = init_chain(".grin3", pow::mine_genesis_block().unwrap());
@ -484,7 +484,7 @@ fn mine_losing_fork() {
#[test]
fn longer_fork() {
clean_output_dir(".grin4");
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let kc = ExtKeychain::from_random_seed(false).unwrap();
// to make it easier to compute the txhashset roots in the test, we
// prepare 2 chains, the 2nd will be have the forked blocks we can
@ -528,7 +528,7 @@ fn longer_fork() {
#[test]
fn spend_rewind_spend() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
util::init_test_logger();
clean_output_dir(".grin_spend_rewind_spend");
@ -607,7 +607,7 @@ fn spend_rewind_spend() {
#[test]
fn spend_in_fork_and_compact() {
clean_output_dir(".grin6");
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
util::init_test_logger();
{
let chain = init_chain(".grin6", pow::mine_genesis_block().unwrap());
@ -746,7 +746,7 @@ fn spend_in_fork_and_compact() {
/// Test ability to retrieve block headers for a given output
#[test]
fn output_header_mappings() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
{
let chain = init_chain(
".grin_header_for_output",
@ -902,7 +902,7 @@ where
#[test]
#[ignore]
fn actual_diff_iter_output() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let genesis_block = pow::mine_genesis_block().unwrap();
let verifier_cache = Arc::new(RwLock::new(LruVerifierCache::new()));
let chain = chain::Chain::init(

View file

@ -40,7 +40,7 @@ fn test_coinbase_maturity() {
let _ = env_logger::init();
let chain_dir = ".grin_coinbase";
clean_output_dir(chain_dir);
global::set_mining_mode(ChainTypes::AutomatedTesting);
global::set_local_chain_type(ChainTypes::AutomatedTesting);
let genesis_block = pow::mine_genesis_block().unwrap();

View file

@ -23,9 +23,10 @@ use std::sync::Arc;
use crate::chain::store::ChainStore;
use crate::chain::txhashset;
use crate::core::core::hash::Hashed;
use crate::core::core::BlockHeader;
use crate::core::global;
use crate::util::file;
use grin_core::core::hash::Hashed;
fn clean_output_dir(dir_name: &str) {
let _ = fs::remove_dir_all(dir_name);
@ -33,6 +34,7 @@ fn clean_output_dir(dir_name: &str) {
#[test]
fn test_unexpected_zip() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let db_root = format!(".grin_txhashset_zip");
clean_output_dir(&db_root);
{

View file

@ -142,7 +142,7 @@ pub const TESTING_SECOND_HARD_FORK: u64 = 6;
/// Compute possible block version at a given height, implements
/// 6 months interval scheduled hard forks for the first 2 years.
pub fn header_version(height: u64) -> HeaderVersion {
let chain_type = global::CHAIN_TYPE.read().clone();
let chain_type = global::get_chain_type();
let hf_interval = (1 + height / HARD_FORK_INTERVAL) as u16;
match chain_type {
global::ChainTypes::Mainnet => HeaderVersion(hf_interval),
@ -383,6 +383,8 @@ mod test {
#[test]
fn test_graph_weight() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
// initial weights
assert_eq!(graph_weight(1, 31), 256 * 31);
assert_eq!(graph_weight(1, 32), 512 * 32);

View file

@ -272,11 +272,13 @@ pub fn genesis_main() -> core::Block {
mod test {
use super::*;
use crate::core::hash::Hashed;
use crate::global;
use crate::ser::{self, ProtocolVersion};
use util::ToHex;
#[test]
fn floonet_genesis_hash() {
global::set_local_chain_type(global::ChainTypes::Floonet);
let gen_hash = genesis_floo().hash();
println!("floonet genesis hash: {}", gen_hash.to_hex());
let gen_bin = ser::ser_vec(&genesis_floo(), ProtocolVersion(1)).unwrap();
@ -293,6 +295,7 @@ mod test {
#[test]
fn mainnet_genesis_hash() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let gen_hash = genesis_main().hash();
println!("mainnet genesis hash: {}", gen_hash.to_hex());
let gen_bin = ser::ser_vec(&genesis_main(), ProtocolVersion(1)).unwrap();

View file

@ -27,7 +27,8 @@ use crate::pow::{
self, new_cuckaroo_ctx, new_cuckarood_ctx, new_cuckaroom_ctx, new_cuckatoo_ctx, EdgeType,
PoWContext,
};
use util::RwLock;
use std::cell::Cell;
use util::OneTime;
/// An enum collecting sets of parameters used throughout the
/// code wherever mining is needed. This should allow for
@ -104,7 +105,7 @@ pub const TXHASHSET_ARCHIVE_INTERVAL: u64 = 12 * 60;
/// Types of chain a server can run with, dictates the genesis block and
/// and mining parameters used.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub enum ChainTypes {
/// For CI testing
AutomatedTesting,
@ -134,31 +135,43 @@ impl Default for ChainTypes {
}
}
/// PoW test mining and verifier context
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum PoWContextTypes {
/// Classic Cuckoo
Cuckoo,
/// ASIC-friendly Cuckatoo
Cuckatoo,
/// ASIC-resistant Cuckaroo
Cuckaroo,
}
lazy_static! {
/// The mining parameter mode
pub static ref CHAIN_TYPE: RwLock<ChainTypes> =
RwLock::new(ChainTypes::Mainnet);
/// PoW context type to instantiate
pub static ref POW_CONTEXT_TYPE: RwLock<PoWContextTypes> =
RwLock::new(PoWContextTypes::Cuckoo);
/// Global chain_type that must be initialized once on node startup.
/// This is accessed via get_chain_type() which allows the global value
/// to be overridden on a per-thread basis (for testing).
pub static ref GLOBAL_CHAIN_TYPE: OneTime<ChainTypes> = OneTime::new();
}
/// Set the mining mode
pub fn set_mining_mode(mode: ChainTypes) {
let mut param_ref = CHAIN_TYPE.write();
*param_ref = mode;
thread_local! {
/// Mainnet|Floonet|UserTesting|AutomatedTesting
pub static CHAIN_TYPE: Cell<Option<ChainTypes>> = Cell::new(None);
}
/// Set the chain type on a per-thread basis via thread_local storage.
pub fn set_local_chain_type(new_type: ChainTypes) {
CHAIN_TYPE.with(|chain_type| chain_type.set(Some(new_type)))
}
/// Get the chain type via thread_local, fallback to global chain_type.
pub fn get_chain_type() -> ChainTypes {
CHAIN_TYPE.with(|chain_type| match chain_type.get() {
None => {
if GLOBAL_CHAIN_TYPE.is_init() {
let chain_type = GLOBAL_CHAIN_TYPE.borrow();
set_local_chain_type(chain_type);
chain_type
} else {
panic!("GLOBAL_CHAIN_TYPE and CHAIN_TYPE unset. Consider set_local_chain_type() in tests.");
}
}
Some(chain_type) => chain_type,
})
}
/// One time initialization of the global chain_type.
/// Will panic if we attempt to re-initialize this (via OneTime).
pub fn init_global_chain_type(new_type: ChainTypes) {
GLOBAL_CHAIN_TYPE.init(new_type)
}
/// Return either a cuckoo context or a cuckatoo context
@ -172,7 +185,7 @@ pub fn create_pow_context<T>(
where
T: EdgeType + 'static,
{
let chain_type = CHAIN_TYPE.read().clone();
let chain_type = get_chain_type();
match chain_type {
// Mainnet has Cuckaroo(d)29 for AR and Cuckatoo31+ for AF
ChainTypes::Mainnet if edge_bits > 29 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
@ -201,8 +214,7 @@ where
/// The minimum acceptable edge_bits
pub fn min_edge_bits() -> u8 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
_ => DEFAULT_MIN_EDGE_BITS,
@ -213,8 +225,7 @@ pub fn min_edge_bits() -> u8 {
/// while the min_edge_bits can be changed on a soft fork, changing
/// base_edge_bits is a hard fork.
pub fn base_edge_bits() -> u8 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
_ => BASE_EDGE_BITS,
@ -223,8 +234,7 @@ pub fn base_edge_bits() -> u8 {
/// The proofsize
pub fn proofsize() -> usize {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_PROOF_SIZE,
ChainTypes::UserTesting => USER_TESTING_PROOF_SIZE,
_ => PROOFSIZE,
@ -233,8 +243,7 @@ pub fn proofsize() -> usize {
/// Coinbase maturity for coinbases to be spent
pub fn coinbase_maturity() -> u64 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_COINBASE_MATURITY,
ChainTypes::UserTesting => USER_TESTING_COINBASE_MATURITY,
_ => COINBASE_MATURITY,
@ -243,8 +252,7 @@ pub fn coinbase_maturity() -> u64 {
/// Initial mining difficulty
pub fn initial_block_difficulty() -> u64 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => TESTING_INITIAL_DIFFICULTY,
ChainTypes::UserTesting => TESTING_INITIAL_DIFFICULTY,
ChainTypes::Floonet => INITIAL_DIFFICULTY,
@ -253,8 +261,7 @@ pub fn initial_block_difficulty() -> u64 {
}
/// Initial mining secondary scale
pub fn initial_graph_weight() -> u32 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => TESTING_INITIAL_GRAPH_WEIGHT,
ChainTypes::UserTesting => TESTING_INITIAL_GRAPH_WEIGHT,
ChainTypes::Floonet => graph_weight(0, SECOND_POW_EDGE_BITS) as u32,
@ -264,8 +271,7 @@ pub fn initial_graph_weight() -> u32 {
/// Maximum allowed block weight.
pub fn max_block_weight() -> usize {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => TESTING_MAX_BLOCK_WEIGHT,
ChainTypes::UserTesting => TESTING_MAX_BLOCK_WEIGHT,
ChainTypes::Floonet => MAX_BLOCK_WEIGHT,
@ -275,8 +281,7 @@ pub fn max_block_weight() -> usize {
/// Horizon at which we can cut-through and do full local pruning
pub fn cut_through_horizon() -> u32 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_CUT_THROUGH_HORIZON,
ChainTypes::UserTesting => USER_TESTING_CUT_THROUGH_HORIZON,
_ => CUT_THROUGH_HORIZON,
@ -285,8 +290,7 @@ pub fn cut_through_horizon() -> u32 {
/// Threshold at which we can request a txhashset (and full blocks from)
pub fn state_sync_threshold() -> u32 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => TESTING_STATE_SYNC_THRESHOLD,
ChainTypes::UserTesting => TESTING_STATE_SYNC_THRESHOLD,
_ => STATE_SYNC_THRESHOLD,
@ -295,8 +299,7 @@ pub fn state_sync_threshold() -> u32 {
/// Number of blocks to reuse a txhashset zip for.
pub fn txhashset_archive_interval() -> u64 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
match get_chain_type() {
ChainTypes::AutomatedTesting => TESTING_TXHASHSET_ARCHIVE_INTERVAL,
ChainTypes::UserTesting => TESTING_TXHASHSET_ARCHIVE_INTERVAL,
_ => TXHASHSET_ARCHIVE_INTERVAL,
@ -306,8 +309,11 @@ pub fn txhashset_archive_interval() -> u64 {
/// Are we in production mode?
/// Production defined as a live public network, testnet[n] or mainnet.
pub fn is_production_mode() -> bool {
let param_ref = CHAIN_TYPE.read();
ChainTypes::Floonet == *param_ref || ChainTypes::Mainnet == *param_ref
match get_chain_type() {
ChainTypes::Floonet => true,
ChainTypes::Mainnet => true,
_ => false,
}
}
/// Are we in floonet?
@ -315,8 +321,10 @@ pub fn is_production_mode() -> bool {
/// as possible to "mainnet" configuration as possible.
/// We want to avoid missing any mainnet only code paths.
pub fn is_floonet() -> bool {
let param_ref = CHAIN_TYPE.read();
ChainTypes::Floonet == *param_ref
match get_chain_type() {
ChainTypes::Floonet => true,
_ => false,
}
}
/// Converts an iterator of block difficulty data to more a more manageable

View file

@ -252,6 +252,7 @@ mod test {
use super::*;
use crate::core::transaction::Weighting;
use crate::core::verifier_cache::{LruVerifierCache, VerifierCache};
use crate::global;
use crate::libtx::ProofBuilder;
use keychain::{ExtKeychain, ExtKeychainPath};
@ -261,6 +262,7 @@ mod test {
#[test]
fn blind_simple_tx() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
@ -282,6 +284,7 @@ mod test {
#[test]
fn blind_simple_tx_with_offset() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
@ -303,6 +306,7 @@ mod test {
#[test]
fn blind_simpler_tx() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();

View file

@ -130,7 +130,7 @@ mod test {
/// We'll be generating genesis blocks differently
#[test]
fn genesis_pow() {
global::set_mining_mode(ChainTypes::UserTesting);
global::set_local_chain_type(ChainTypes::UserTesting);
let mut b = genesis::genesis_dev();
b.header.pow.nonce = 28106;

View file

@ -170,6 +170,7 @@ mod test {
#[test]
fn cuckaroo19_vectors() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let mut ctx = new_impl::<u64>(19, 42);
ctx.params.siphash_keys = V1_19_HASH;
assert!(ctx.verify(&Proof::new(V1_19_SOL.to_vec())).is_ok());

View file

@ -172,6 +172,7 @@ mod test {
#[test]
fn cuckarood19_29_vectors() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let mut ctx19 = new_impl::<u64>(19, 42);
ctx19.params.siphash_keys = V1_19_HASH;
assert!(ctx19.verify(&Proof::new(V1_19_SOL.to_vec())).is_ok());

View file

@ -165,6 +165,7 @@ mod test {
#[test]
fn cuckaroom19_29_vectors() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let mut ctx19 = new_impl::<u64>(19, 42);
ctx19.params.siphash_keys = V1_19_HASH;
assert!(ctx19.verify(&Proof::new(V1_19_SOL.to_vec())).is_ok());

View file

@ -367,6 +367,7 @@ mod test {
#[test]
fn cuckatoo() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let ret = basic_solve::<u32>();
if let Err(r) = ret {
panic!("basic_solve u32: Error: {}", r);

View file

@ -88,10 +88,12 @@ impl Lean {
#[cfg(test)]
mod test {
use super::*;
use crate::global;
use crate::pow::types::PoWContext;
#[test]
fn lean_miner() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let nonce = 15465723;
let header = [0u8; 84].to_vec(); // with nonce
let edge_bits = 19;

View file

@ -507,6 +507,7 @@ mod tests {
#[test]
fn test_proof_rw() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
for edge_bits in 10..63 {
let mut proof = Proof::new(gen_proof(edge_bits as u32));
proof.edge_bits = edge_bits;

View file

@ -29,18 +29,22 @@ use crate::core::libtx::ProofBuilder;
use crate::core::{global, ser};
use chrono::Duration;
use grin_core as core;
use grin_core::global::ChainTypes;
use keychain::{BlindingFactor, ExtKeychain, Keychain};
use std::sync::Arc;
use util::{secp, RwLock, ToHex};
// Setup test with AutomatedTesting chain_type;
fn test_setup() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
}
fn verifier_cache() -> Arc<RwLock<dyn VerifierCache>> {
Arc::new(RwLock::new(LruVerifierCache::new()))
}
#[test]
fn too_large_block() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let max_out = global::max_block_weight() / BLOCK_OUTPUT_WEIGHT;
@ -71,6 +75,7 @@ fn too_large_block() {
// block with no inputs/outputs/kernels
// no fees, no reward, no coinbase
fn very_empty_block() {
test_setup();
let b = Block::with_header(BlockHeader::default());
assert_eq!(
@ -82,6 +87,7 @@ fn very_empty_block() {
#[test]
// builds a block with a tx spending another and check that cut_through occurred
fn block_with_cut_through() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -120,6 +126,7 @@ fn block_with_cut_through() {
#[test]
fn empty_block_with_coinbase_is_valid() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();
@ -158,6 +165,7 @@ fn empty_block_with_coinbase_is_valid() {
// invalidates the block and specifically it causes verify_coinbase to fail
// additionally verifying the merkle_inputs_outputs also fails
fn remove_coinbase_output_flag() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();
@ -181,6 +189,7 @@ fn remove_coinbase_output_flag() {
// test that flipping the COINBASE flag on the kernel features
// invalidates the block and specifically it causes verify_coinbase to fail
fn remove_coinbase_kernel_flag() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();
@ -223,6 +232,7 @@ fn serialize_deserialize_header_version() {
#[test]
fn serialize_deserialize_block_header() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();
@ -240,6 +250,7 @@ fn serialize_deserialize_block_header() {
#[test]
fn serialize_deserialize_block() {
test_setup();
let tx1 = tx1i2o();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
@ -260,7 +271,7 @@ fn serialize_deserialize_block() {
#[test]
fn empty_block_serialized_size() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();
@ -273,7 +284,7 @@ fn empty_block_serialized_size() {
#[test]
fn block_single_tx_serialized_size() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let tx1 = tx1i2o();
@ -287,7 +298,7 @@ fn block_single_tx_serialized_size() {
#[test]
fn empty_compact_block_serialized_size() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();
@ -301,7 +312,7 @@ fn empty_compact_block_serialized_size() {
#[test]
fn compact_block_single_tx_serialized_size() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let tx1 = tx1i2o();
@ -316,7 +327,7 @@ fn compact_block_single_tx_serialized_size() {
#[test]
fn block_10_tx_serialized_size() {
global::set_mining_mode(global::ChainTypes::AutomatedTesting);
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
@ -353,7 +364,7 @@ fn block_10_tx_serialized_size() {
#[test]
fn compact_block_10_tx_serialized_size() {
global::set_mining_mode(ChainTypes::AutomatedTesting);
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
@ -373,6 +384,7 @@ fn compact_block_10_tx_serialized_size() {
#[test]
fn compact_block_hash_with_nonce() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let tx = tx1i2o();
@ -404,6 +416,7 @@ fn compact_block_hash_with_nonce() {
#[test]
fn convert_block_to_compact_block() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let tx1 = tx1i2o();
@ -428,6 +441,7 @@ fn convert_block_to_compact_block() {
#[test]
fn hydrate_empty_compact_block() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();
@ -442,6 +456,7 @@ fn hydrate_empty_compact_block() {
#[test]
fn serialize_deserialize_compact_block() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let tx1 = tx1i2o();
@ -469,6 +484,7 @@ fn serialize_deserialize_compact_block() {
// Duplicate a range proof from a valid output into another of the same amount
#[test]
fn same_amount_outputs_copy_range_proof() {
test_setup();
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -511,6 +527,7 @@ fn same_amount_outputs_copy_range_proof() {
// Swap a range proof with the right private key but wrong amount
#[test]
fn wrong_amount_range_proof() {
test_setup();
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = keychain::ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -563,6 +580,7 @@ fn wrong_amount_range_proof() {
#[test]
fn validate_header_proof() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();

View file

@ -22,7 +22,7 @@ use grin_core::pow::Difficulty;
/// Checks different next_target adjustments and difficulty boundaries
#[test]
fn next_target_adjustment() {
global::set_mining_mode(global::ChainTypes::AutomatedTesting);
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let cur_time = Utc::now().timestamp() as u64;
let diff_min = Difficulty::min();

View file

@ -21,7 +21,7 @@ use grin_core::global;
#[test]
fn test_secondary_pow_ratio() {
// Tests for Floonet chain type (covers pre and post hardfork).
global::set_mining_mode(global::ChainTypes::Floonet);
global::set_local_chain_type(global::ChainTypes::Floonet);
assert_eq!(global::is_floonet(), true);
assert_eq!(secondary_pow_ratio(1), 90);
@ -63,7 +63,7 @@ fn test_secondary_pow_ratio() {
#[test]
fn hard_forks() {
global::set_mining_mode(global::ChainTypes::Floonet);
global::set_local_chain_type(global::ChainTypes::Floonet);
assert_eq!(global::is_floonet(), true);
assert!(valid_header_version(0, HeaderVersion(1)));
assert!(valid_header_version(10, HeaderVersion(1)));

View file

@ -245,8 +245,7 @@ fn print_chain_sim(chain_sim: Vec<(HeaderInfo, DiffStats)>) {
/// Checks different next_target adjustments and difficulty boundaries
#[test]
fn adjustment_scenarios() {
// Use production parameters for genesis diff
global::set_mining_mode(global::ChainTypes::Mainnet);
global::set_local_chain_type(global::ChainTypes::Mainnet);
// Genesis block with initial diff
let chain_sim = create_chain_sim(global::initial_block_difficulty());
@ -318,8 +317,7 @@ fn adjustment_scenarios() {
#[test]
fn test_secondary_pow_ratio() {
global::set_mining_mode(global::ChainTypes::Mainnet);
assert_eq!(global::is_floonet(), false);
global::set_local_chain_type(global::ChainTypes::Mainnet);
assert_eq!(secondary_pow_ratio(1), 90);
assert_eq!(secondary_pow_ratio(89), 90);
@ -360,12 +358,11 @@ fn test_secondary_pow_ratio() {
#[test]
fn test_secondary_pow_scale() {
global::set_local_chain_type(global::ChainTypes::Mainnet);
let window = DIFFICULTY_ADJUST_WINDOW;
let mut hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 100);
global::set_mining_mode(global::ChainTypes::Mainnet);
assert_eq!(global::is_floonet(), false);
// all primary, factor should increase so it becomes easier to find a high
// difficulty block
hi.is_secondary = false;
@ -436,8 +433,8 @@ fn test_secondary_pow_scale() {
#[test]
fn hard_forks() {
global::set_mining_mode(global::ChainTypes::Mainnet);
assert_eq!(global::is_floonet(), false);
global::set_local_chain_type(global::ChainTypes::Mainnet);
assert!(valid_header_version(0, HeaderVersion(1)));
assert!(valid_header_version(10, HeaderVersion(1)));
assert!(!valid_header_version(10, HeaderVersion(2)));

View file

@ -25,7 +25,7 @@ use self::core::core::{
};
use self::core::libtx::build::{self, initial_tx, input, output, with_excess};
use self::core::libtx::ProofBuilder;
use self::core::ser;
use self::core::{global, ser};
use crate::common::{new_block, tx1i1o, tx1i2o, tx2i1o};
use grin_core as core;
use keychain::{BlindingFactor, ExtKeychain, Keychain};
@ -33,6 +33,11 @@ use std::sync::Arc;
use util::static_secp_instance;
use util::RwLock;
// Setup test with AutomatedTesting chain_type;
fn test_setup() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
}
#[test]
fn simple_tx_ser() {
let tx = tx2i1o();
@ -61,6 +66,7 @@ fn simple_tx_ser() {
#[test]
fn simple_tx_ser_deser() {
test_setup();
let tx = tx2i1o();
let mut vec = Vec::new();
ser::serialize_default(&mut vec, &tx).expect("serialization failed");
@ -73,6 +79,7 @@ fn simple_tx_ser_deser() {
#[test]
fn tx_double_ser_deser() {
test_setup();
// checks serializing doesn't mess up the tx and produces consistent results
let btx = tx2i1o();
@ -91,6 +98,7 @@ fn tx_double_ser_deser() {
#[test]
#[should_panic(expected = "Keychain Error")]
fn test_zero_commit_fails() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -111,6 +119,7 @@ fn verifier_cache() -> Arc<RwLock<dyn VerifierCache>> {
#[test]
fn build_tx_kernel() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -143,6 +152,7 @@ fn build_tx_kernel() {
// and check it still validates.
#[test]
fn transaction_cut_through() {
test_setup();
let tx1 = tx1i2o();
let tx2 = tx2i1o();
@ -164,6 +174,7 @@ fn transaction_cut_through() {
// Attempt to deaggregate a multi-kernel transaction in a different way
#[test]
fn multi_kernel_transaction_deaggregation() {
test_setup();
let tx1 = tx1i1o();
let tx2 = tx1i1o();
let tx3 = tx1i1o();
@ -202,6 +213,7 @@ fn multi_kernel_transaction_deaggregation() {
#[test]
fn multi_kernel_transaction_deaggregation_2() {
test_setup();
let tx1 = tx1i1o();
let tx2 = tx1i1o();
let tx3 = tx1i1o();
@ -227,6 +239,7 @@ fn multi_kernel_transaction_deaggregation_2() {
#[test]
fn multi_kernel_transaction_deaggregation_3() {
test_setup();
let tx1 = tx1i1o();
let tx2 = tx1i1o();
let tx3 = tx1i1o();
@ -253,6 +266,7 @@ fn multi_kernel_transaction_deaggregation_3() {
#[test]
fn multi_kernel_transaction_deaggregation_4() {
test_setup();
let tx1 = tx1i1o();
let tx2 = tx1i1o();
let tx3 = tx1i1o();
@ -288,6 +302,7 @@ fn multi_kernel_transaction_deaggregation_4() {
#[test]
fn multi_kernel_transaction_deaggregation_5() {
test_setup();
let tx1 = tx1i1o();
let tx2 = tx1i1o();
let tx3 = tx1i1o();
@ -327,6 +342,7 @@ fn multi_kernel_transaction_deaggregation_5() {
// Attempt to deaggregate a multi-kernel transaction
#[test]
fn basic_transaction_deaggregation() {
test_setup();
let tx1 = tx1i2o();
let tx2 = tx2i1o();
@ -412,6 +428,7 @@ fn tx_hash_diff() {
/// 2 inputs, 2 outputs transaction.
#[test]
fn tx_build_exchange() {
test_setup();
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -457,6 +474,7 @@ fn tx_build_exchange() {
#[test]
fn reward_empty_block() {
test_setup();
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -473,6 +491,7 @@ fn reward_empty_block() {
#[test]
fn reward_with_tx_block() {
test_setup();
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -500,6 +519,7 @@ fn reward_with_tx_block() {
#[test]
fn simple_block() {
test_setup();
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -523,6 +543,7 @@ fn simple_block() {
#[test]
fn test_block_with_timelocked_tx() {
test_setup();
let keychain = keychain::ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
@ -581,6 +602,7 @@ fn test_block_with_timelocked_tx() {
#[test]
pub fn test_verify_1i1o_sig() {
test_setup();
let tx = tx1i1o();
tx.validate(Weighting::AsTransaction, verifier_cache())
.unwrap();
@ -588,6 +610,7 @@ pub fn test_verify_1i1o_sig() {
#[test]
pub fn test_verify_2i1o_sig() {
test_setup();
let tx = tx2i1o();
tx.validate(Weighting::AsTransaction, verifier_cache())
.unwrap();

View file

@ -92,7 +92,7 @@ fn main() {
{
// setup a tmp chain to set block header roots
core::global::set_mining_mode(core::global::ChainTypes::UserTesting);
core::global::set_local_chain_type(core::global::ChainTypes::UserTesting);
let tmp_chain = setup_chain(".grin.tmp", core::pow::mine_genesis_block().unwrap());
tmp_chain.set_txhashset_roots(&mut gen).unwrap();
}
@ -103,7 +103,7 @@ fn main() {
gen.header.prev_root = core::core::hash::Hash::from_hex(&h1).unwrap();
// mine a Cuckaroo29 block
core::global::set_mining_mode(core::global::ChainTypes::Mainnet);
core::global::set_local_chain_type(core::global::ChainTypes::Mainnet);
let plugin_lib = cuckoo::PluginLibrary::new(PLUGIN_PATH).unwrap();
let mut params = plugin_lib.get_default_params();
params.mutate_nonce = false;
@ -216,7 +216,7 @@ fn update_genesis_rs(gen: &core::core::Block) {
"excess".to_string(),
format!(
"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
gen.kernels()[0].excess.to_hex())
gen.kernels()[0].excess.to_hex()
),
));
replacements.push((

View file

@ -106,7 +106,7 @@ fn max_msg_size(msg_type: Type) -> u64 {
}
fn magic() -> [u8; 2] {
match *global::CHAIN_TYPE.read() {
match global::get_chain_type() {
global::ChainTypes::Floonet => FLOONET_MAGIC,
global::ChainTypes::Mainnet => MAINNET_MAGIC,
_ => OTHER_MAGIC,

View file

@ -23,6 +23,7 @@ use std::sync::Arc;
use std::{thread, time};
use crate::core::core::hash::Hash;
use crate::core::global;
use crate::core::pow::Difficulty;
use crate::p2p::types::PeerAddr;
use crate::p2p::Peer;
@ -35,11 +36,17 @@ fn open_port() -> u16 {
listener.local_addr().unwrap().port()
}
// Setup test with AutomatedTesting chain_type;
fn test_setup() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
util::init_test_logger();
}
// Starts a server and connects a client peer to it to check handshake,
// followed by a ping/pong exchange to make sure the connection is live.
#[test]
fn peer_handshake() {
util::init_test_logger();
test_setup();
let p2p_config = p2p::P2PConfig {
host: "127.0.0.1".parse().unwrap(),
@ -62,7 +69,11 @@ fn peer_handshake() {
);
let p2p_inner = server.clone();
let _ = thread::spawn(move || p2p_inner.listen());
let _ = thread::spawn(move || {
// Test setup relies on thread local for chain_type so make sure we setup here.
test_setup();
p2p_inner.listen()
});
thread::sleep(time::Duration::from_secs(1));

View file

@ -17,12 +17,12 @@
use chrono::prelude::{DateTime, Utc};
use self::core::consensus;
use self::core::core::block;
use self::core::core::committed;
use self::core::core::hash::Hash;
use self::core::core::transaction::{self, Transaction};
use self::core::core::{BlockHeader, BlockSums};
use self::core::{consensus, global};
use failure::Fail;
use grin_core as core;
use grin_keychain as keychain;
@ -144,7 +144,7 @@ fn default_max_stempool_size() -> usize {
50_000
}
fn default_mineable_max_weight() -> usize {
global::max_block_weight()
consensus::MAX_BLOCK_WEIGHT
}
/// Represents a single entry in the pool.

View file

@ -17,8 +17,8 @@ pub mod common;
use self::core::core::hash::Hashed;
use self::core::core::verifier_cache::LruVerifierCache;
use self::core::core::{Block, BlockHeader, Transaction};
use self::core::libtx;
use self::core::pow::Difficulty;
use self::core::{global, libtx};
use self::keychain::{ExtKeychain, Keychain};
use self::util::RwLock;
use crate::common::*;
@ -30,6 +30,7 @@ use std::sync::Arc;
#[test]
fn test_transaction_pool_block_building() {
util::init_test_logger();
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let keychain: ExtKeychain = Keychain::from_random_seed(false).unwrap();
let db_root = ".grin_block_building".to_string();

View file

@ -33,7 +33,7 @@ use std::sync::Arc;
#[test]
fn test_block_building_max_weight() {
util::init_test_logger();
global::set_mining_mode(global::ChainTypes::AutomatedTesting);
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let keychain: ExtKeychain = Keychain::from_random_seed(false).unwrap();

View file

@ -17,8 +17,8 @@ pub mod common;
use self::core::core::hash::Hashed;
use self::core::core::verifier_cache::LruVerifierCache;
use self::core::core::{Block, BlockHeader};
use self::core::libtx;
use self::core::pow::Difficulty;
use self::core::{global, libtx};
use self::keychain::{ExtKeychain, Keychain};
use self::util::RwLock;
use crate::common::ChainAdapter;
@ -30,6 +30,7 @@ use std::sync::Arc;
#[test]
fn test_transaction_pool_block_reconciliation() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let keychain: ExtKeychain = Keychain::from_random_seed(false).unwrap();
let db_root = ".grin_block_reconciliation".to_string();

View file

@ -17,6 +17,7 @@ pub mod common;
use self::core::core::hash::Hash;
use self::core::core::verifier_cache::LruVerifierCache;
use self::core::core::{BlockHeader, BlockSums, Transaction};
use self::core::global;
use self::keychain::{ExtKeychain, Keychain};
use self::pool::types::{BlockChain, PoolError};
use self::util::RwLock;
@ -67,6 +68,7 @@ impl BlockChain for CoinbaseMaturityErrorChainAdapter {
/// Test we correctly verify coinbase maturity when adding txs to the pool.
#[test]
fn test_coinbase_maturity() {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let keychain: ExtKeychain = Keychain::from_random_seed(false).unwrap();
// Mocking this up with an adapter that will raise an error for coinbase

View file

@ -16,8 +16,8 @@ pub mod common;
use self::core::core::verifier_cache::LruVerifierCache;
use self::core::core::{transaction, Block, BlockHeader, Weighting};
use self::core::libtx;
use self::core::pow::Difficulty;
use self::core::{global, libtx};
use self::keychain::{ExtKeychain, Keychain};
use self::pool::TxSource;
use self::util::RwLock;
@ -31,6 +31,8 @@ use std::sync::Arc;
/// Test we can add some txs to the pool (both stempool and txpool).
#[test]
fn test_the_transaction_pool() {
// Use mainnet config to allow for reasonably large block weights.
global::set_local_chain_type(global::ChainTypes::Mainnet);
let keychain: ExtKeychain = Keychain::from_random_seed(false).unwrap();
let db_root = ".grin_transaction_pool".to_string();

View file

@ -23,7 +23,6 @@ use clap::ArgMatches;
use ctrlc;
use crate::config::GlobalConfig;
use crate::core::global;
use crate::p2p::Seeding;
use crate::servers;
use crate::tui::ui;
@ -86,19 +85,9 @@ fn start_server_tui(config: servers::ServerConfig, logs_rx: Option<mpsc::Receive
/// configuration.
pub fn server_command(
server_args: Option<&ArgMatches<'_>>,
mut global_config: GlobalConfig,
global_config: GlobalConfig,
logs_rx: Option<mpsc::Receiver<LogEntry>>,
) -> i32 {
global::set_mining_mode(
global_config
.members
.as_mut()
.unwrap()
.server
.clone()
.chain_type,
);
// just get defaults from the global config
let mut server_config = global_config.members.as_ref().unwrap().server.clone();

View file

@ -140,7 +140,8 @@ fn real_main() -> i32 {
};
init_logger(Some(logging_config), logs_tx);
global::set_mining_mode(config.members.unwrap().server.chain_type);
// One time initialization of the global chain_type.
global::init_global_chain_type(config.members.unwrap().server.chain_type);
if let Some(file_path) = &config.config_file_path {
info!(

View file

@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use grin_core as core;
use grin_store as store;
use grin_util as util;
use grin_core::ser::{self, Readable, Reader, Writeable, Writer};
use crate::core::global;
use crate::core::ser::{self, Readable, Reader, Writeable, Writer};
use std::fs;
const WRITE_CHUNK_SIZE: usize = 20;
@ -59,6 +60,7 @@ fn clean_output_dir(test_dir: &str) {
}
fn setup(test_dir: &str) {
global::set_local_chain_type(global::ChainTypes::Mainnet);
util::init_test_logger();
clean_output_dir(test_dir);
}

View file

@ -100,6 +100,11 @@ where
.clone()
.expect("Cannot borrow one_time before initialization.")
}
/// Has this OneTime been initialized?
pub fn is_init(&self) -> bool {
self.inner.read().is_some()
}
}
/// Encode an utf8 string to a base64 string