Make builtins work.
This commit is contained in:
		
							parent
							
								
									c85cabb598
								
							
						
					
					
						commit
						957dd36328
					
				| @ -9,7 +9,7 @@ authors = ["Ethcore <admin@ethcore.io>"] | ||||
| [dependencies] | ||||
| log = "0.3" | ||||
| env_logger = "0.3" | ||||
| ethcore-util = "0.1.0" | ||||
| ethcore-util = { path = "../ethcore-util" } | ||||
| rustc-serialize = "0.3" | ||||
| flate2 = "0.2" | ||||
| rocksdb = "0.2.1" | ||||
|  | ||||
							
								
								
									
										111
									
								
								src/builtin.rs
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								src/builtin.rs
									
									
									
									
									
								
							| @ -1,4 +1,6 @@ | ||||
| use std::cmp::min; | ||||
| use util::uint::*; | ||||
| use rustc_serialize::json::Json; | ||||
| 
 | ||||
| /// Definition of a contract whose implementation is built-in. 
 | ||||
| pub struct Builtin { | ||||
| @ -8,3 +10,112 @@ pub struct Builtin { | ||||
| 	/// being placed into the second.
 | ||||
| 	pub execute: Box<Fn(&[u8], &mut [u8])>, | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| ETH_REGISTER_PRECOMPILED(ecrecover)(bytesConstRef _in, bytesRef _out) | ||||
| { | ||||
| 	struct inType | ||||
| 	{ | ||||
| 		h256 hash; | ||||
| 		h256 v; | ||||
| 		h256 r; | ||||
| 		h256 s; | ||||
| 	} in; | ||||
| 
 | ||||
| 	memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); | ||||
| 
 | ||||
| 	h256 ret; | ||||
| 	u256 v = (u256)in.v; | ||||
| 	if (v >= 27 && v <= 28) | ||||
| 	{ | ||||
| 		SignatureStruct sig(in.r, in.s, (byte)((int)v - 27)); | ||||
| 		if (sig.isValid()) | ||||
| 		{ | ||||
| 			try | ||||
| 			{ | ||||
| 				if (Public rec = recover(sig, in.hash)) | ||||
| 				{ | ||||
| 					ret = dev::sha3(rec); | ||||
| 					memset(ret.data(), 0, 12); | ||||
| 					ret.ref().copyTo(_out); | ||||
| 				} | ||||
| 			} | ||||
| 			catch (...) {} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ETH_REGISTER_PRECOMPILED(sha256)(bytesConstRef _in, bytesRef _out) | ||||
| { | ||||
| 	dev::sha256(_in).ref().copyTo(_out); | ||||
| } | ||||
| 
 | ||||
| ETH_REGISTER_PRECOMPILED(ripemd160)(bytesConstRef _in, bytesRef _out) | ||||
| { | ||||
| 	h256(dev::ripemd160(_in), h256::AlignRight).ref().copyTo(_out); | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| impl Builtin { | ||||
| 	/// Create a new object from components.
 | ||||
| 	pub fn new(cost: Box<Fn(usize) -> U256>, execute: Box<Fn(&[u8], &mut [u8])>) -> Builtin { | ||||
| 		Builtin {cost: cost, execute: execute} | ||||
| 	} | ||||
| 
 | ||||
| 	/// Create a new object from a builtin-function name with a linear cost associated with input size.
 | ||||
| 	pub fn from_named_linear(name: &str, base_cost: usize, word_cost: usize) -> Option<Builtin> { | ||||
| 		new_builtin_exec(name).map(|b| { | ||||
| 			let cost = Box::new(move|s: usize| -> U256 {U256::from(base_cost) + U256::from(word_cost) * U256::from((s + 31) / 32)}); | ||||
| 			Self::new(cost, b) | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	/// Create a builtin from JSON.
 | ||||
| 	///
 | ||||
| 	/// JSON must be of the form `{ "name": "identity", "linear": {"base": 10, "word": 20} }`.
 | ||||
| 	pub fn from_json(json: &Json) -> Option<Builtin> { | ||||
| 		// NICE: figure out a more convenient means of handing errors here.
 | ||||
| 		if let Json::String(ref name) = json["name"] { | ||||
| 			if let Json::Object(ref o) = json["linear"] { | ||||
| 				if let Json::U64(ref word) = o["word"] { | ||||
| 					if let Json::U64(ref base) = o["base"] { | ||||
| 						return Self::from_named_linear(&name[..], *base as usize, *word as usize); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		None | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // TODO: turn in to a factory with dynamic registration.
 | ||||
| pub fn new_builtin_exec(name: &str) -> Option<Box<Fn(&[u8], &mut [u8])>> { | ||||
| 	match name { | ||||
| 		"identity" => Some(Box::new(move|input: &[u8], output: &mut[u8]| { | ||||
| 			for i in 0..min(input.len(), output.len()) { | ||||
| 				output[i] = input[i]; | ||||
| 			} | ||||
| 		})), | ||||
| 		"ecrecover" => Some(Box::new(move|_input: &[u8], _output: &mut[u8]| { | ||||
| 			unimplemented!(); | ||||
| 		})), | ||||
| 		"sha256" => Some(Box::new(move|_input: &[u8], _output: &mut[u8]| { | ||||
| 			unimplemented!(); | ||||
| 		})), | ||||
| 		"ripemd160" => Some(Box::new(move|_input: &[u8], _output: &mut[u8]| { | ||||
| 			unimplemented!(); | ||||
| 		})), | ||||
| 		_ => None | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn identity() { | ||||
| 	let f = new_builtin_exec("identity").unwrap(); | ||||
| 	let i = [0u8, 1, 2, 3]; | ||||
| 	for osize in [2, 4, 8].iter() { | ||||
| 		let mut o = vec![255u8; *osize]; | ||||
| 		f(&i[..], &mut o[..]); | ||||
| 		assert_eq!(i[..], o[..]); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										36
									
								
								src/spec.rs
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								src/spec.rs
									
									
									
									
									
								
							| @ -20,6 +20,8 @@ use null_engine::NullEngine; | ||||
| use denominations::*; | ||||
| use header::*; | ||||
| 
 | ||||
| // TODO: need a JSON->cost closure converter.
 | ||||
| 
 | ||||
| /// Converts file from base64 gzipped bytes to json
 | ||||
| pub fn base_to_json(source: &[u8]) -> Json { | ||||
| 	// there is probably no need to store genesis in based64 gzip,
 | ||||
| @ -139,26 +141,29 @@ impl Spec { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| impl Spec { | ||||
| 	/// Loads a chain-specification from a json data structure
 | ||||
| 	pub fn from_json(json: Json) -> Spec { | ||||
| 		// once we commit ourselves to some json parsing library (serde?)
 | ||||
| 		// move it to proper data structure
 | ||||
| 		let mut state = HashMap::new(); | ||||
| 		let mut builtins = HashMap::new(); | ||||
| 
 | ||||
| 		let accounts = json["alloc"].as_object().expect("Missing genesis state"); | ||||
| 		for (address, acc) in accounts.iter() { | ||||
| 			let addr = Address::from_str(address).unwrap(); | ||||
| 			let o = acc.as_object().unwrap(); | ||||
| 			let balance = U256::from_dec_str(o["balance"].as_string().unwrap()).unwrap(); | ||||
| 			state.insert(addr, Account::new_basic(balance, U256::from(0))); | ||||
| 			if let Json::Object(_) = o["precompiled"] { | ||||
| 				if let Some(b) = Builtin::from_json(&o["precompiled"]) { | ||||
| 					builtins.insert(addr.clone(), b); | ||||
| 				} | ||||
| 			} | ||||
| 			let balance = U256::from_dec_str(o["balance"].as_string().unwrap_or("0")).unwrap(); | ||||
| 			let nonce = U256::from_dec_str(o["nonce"].as_string().unwrap_or("0")).unwrap(); | ||||
| 			// TODO: handle code & data is they exist.
 | ||||
| 			state.insert(addr, Account::new_basic(balance, nonce)); | ||||
| 		} | ||||
| 
 | ||||
| 		let builtins = { | ||||
| 			// TODO: populate from json.
 | ||||
| 			HashMap::new() | ||||
| 		}; | ||||
| 
 | ||||
| 		let (seal_fields, seal_rlp) = { | ||||
| 			if json.find("mixhash").is_some() && json.find("nonce").is_some() { | ||||
| 				let mut s = RlpStream::new(); | ||||
| @ -189,6 +194,15 @@ impl Spec { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn standard_builtins() -> HashMap<Address, Builtin> { | ||||
| 		let mut ret = HashMap::new(); | ||||
| 		ret.insert(Address::from_str("0000000000000000000000000000000000000001").unwrap(), Builtin::from_named_linear("ecrecover", 3000, 0).unwrap()); | ||||
| 		ret.insert(Address::from_str("0000000000000000000000000000000000000002").unwrap(), Builtin::from_named_linear("sha256", 60, 12).unwrap()); | ||||
| 		ret.insert(Address::from_str("0000000000000000000000000000000000000003").unwrap(), Builtin::from_named_linear("ripemd160", 600, 120).unwrap()); | ||||
| 		ret.insert(Address::from_str("0000000000000000000000000000000000000004").unwrap(), Builtin::from_named_linear("identity", 15, 3).unwrap()); | ||||
| 		ret | ||||
| 	} | ||||
| 
 | ||||
| 	/// Creates the Olympic network chain spec.
 | ||||
| 	pub fn olympic() -> Spec { | ||||
| 		Spec { | ||||
| @ -207,7 +221,7 @@ impl Spec { | ||||
| 				acc.insert(vec.0.to_string(), vec.1); | ||||
| 				acc | ||||
| 			}), | ||||
| 			builtins: HashMap::new(),			// TODO: make correct
 | ||||
| 			builtins: Self::standard_builtins(), | ||||
| 			parent_hash: H256::new(), | ||||
| 			author: Address::new(), | ||||
| 			difficulty: U256::from(131_072u64), | ||||
| @ -245,7 +259,7 @@ impl Spec { | ||||
| 				acc.insert(vec.0.to_string(), vec.1); | ||||
| 				acc | ||||
| 			}), | ||||
| 			builtins: HashMap::new(),			// TODO: make correct
 | ||||
| 			builtins: Self::standard_builtins(), | ||||
| 			parent_hash: H256::new(), | ||||
| 			author: Address::new(), | ||||
| 			difficulty: U256::from(131_072u64), | ||||
| @ -283,7 +297,7 @@ impl Spec { | ||||
| 				acc.insert(vec.0.to_string(), vec.1); | ||||
| 				acc | ||||
| 			}), | ||||
| 			builtins: HashMap::new(),			// TODO: make correct
 | ||||
| 			builtins: Self::standard_builtins(), | ||||
| 			parent_hash: H256::new(), | ||||
| 			author: Address::new(), | ||||
| 			difficulty: U256::from(131_072u64), | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user