Add readme
This commit is contained in:
		
							parent
							
								
									2591a73950
								
							
						
					
					
						commit
						b0779aa9f3
					
				
							
								
								
									
										44
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| # chainlib | ||||
| 
 | ||||
| Chainlib is a prototype attempt at writing a generalized code library structure in python3 for concepts that are valid across blockchains, either within the same chain technology or across them. If useful and/or successful, it should be considered ported to a more performant language (rust?). | ||||
| 
 | ||||
| It is primarily aimed at console-environment development. | ||||
| 
 | ||||
| It aims to give fine-grained control and transparency to all operations and transformations.  | ||||
| 
 | ||||
| It library code should be easy to understand and maintain. | ||||
| 
 | ||||
| To achieve transparency and improve maintainability, it deliberately exposes the _user_ of this code to a certain degree of complexity. | ||||
| 
 | ||||
| Ultimately, the chainlib library is for the developer who seeks to understand and contribute, rather than merely defer and consume. | ||||
| 
 | ||||
| 
 | ||||
| ## Requirements | ||||
| 
 | ||||
| Chainlib seeks to keep its dependency graph and small as possible. Because of baggage from the initial phase of development, it depends on the `crypto-dev-signer` library to represent transaction structures. As this dependency also includes other routines not necessary for the code in the library, it will be replaced with a dedicated component. `crypto-dev-signer` will still be used as default for tests, and for the time being also for the CLI runnables. | ||||
| 
 | ||||
| To generate the bitcoin-style keccak256 hashes, `pysha3` is used. `pysha3` is a very fast python wrapper around the official keccak implementation from [XKCP](https://github.com/XKCP/XKCP). | ||||
| 
 | ||||
| The other requirements are very this code fragments that merely help to relieve a bit of tedium, and add no magic. | ||||
| 
 | ||||
| Chainlib is not compatible with python2, nor is there any reason to expect it will aim to be. | ||||
| 
 | ||||
| 
 | ||||
| ## Structure | ||||
| 
 | ||||
| Any generalizable structures and code can be found in the base module directory `chainlib/` | ||||
| 
 | ||||
| Currently the only operational code for available targets is for the `evm` and the `Ethereum` network protocol. This code can be found in `chainlib/eth`. | ||||
| 
 | ||||
| Every module will have a subdirectory `runnable` which contains CLI convenience tooling for common operations. Any directory `example` will contain code snippets demonstrating usage. | ||||
| 
 | ||||
| 
 | ||||
| ## How to use | ||||
| 
 | ||||
| There are no (exhaustive) tutorial planned for chainlib. All you need to know should be possible to easily understand from code in the `example` `tests` and `runnable` subfolders. | ||||
| 
 | ||||
| 
 | ||||
| ## See also | ||||
| 
 | ||||
| * The [chainsyncer](https://gitlab.com/chaintool/chainsyncer) project, which provides a simple chain syncer framework allowing for an arbitrary amount of pluggable code to be executed for each block transaction. | ||||
| * The [chainqueue](https://gitlab.com/chaintool/chainqueue) project, which provides a transaction queueing daemon that handles conditional submisssion and resubmission of transactions to the network. | ||||
| @ -79,7 +79,7 @@ class ABIContractDecoder: | ||||
|         length = int.from_bytes(b[cursor:cursor+32], 'big') | ||||
|         cursor += 32 | ||||
|         content = b[cursor:cursor+length] | ||||
|         logg.debug('parsing {}'.format(content)) | ||||
|         logg.debug('parsing string offset {} length {} content {}'.format(offset, length, content)) | ||||
|         return content.decode('utf-8') | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -38,7 +38,10 @@ from chainlib.eth.gas import ( | ||||
|         RPCGasOracle, | ||||
|         OverrideGasOracle, | ||||
|         ) | ||||
| from chainlib.eth.tx import TxFactory | ||||
| from chainlib.eth.tx import ( | ||||
|         TxFactory, | ||||
|         raw, | ||||
|         ) | ||||
| from chainlib.chain import ChainSpec | ||||
| from chainlib.eth.runnable.util import decode_for_puny_humans | ||||
| 
 | ||||
| @ -53,7 +56,8 @@ argparser.add_argument('-p', '--provider', dest='p', default='http://localhost:8 | ||||
| argparser.add_argument('-w', action='store_true', help='Wait for the last transaction to be confirmed') | ||||
| argparser.add_argument('-ww', action='store_true', help='Wait for every transaction to be confirmed') | ||||
| argparser.add_argument('-i', '--chain-spec', dest='i', type=str, default='evm:ethereum:1', help='Chain specification string') | ||||
| argparser.add_argument('-y', '--key-file', required=True, dest='y', type=str, help='Ethereum keystore file to use for signing') | ||||
| argparser.add_argument('-y', '--key-file', dest='y', type=str, help='Ethereum keystore file to use for signing') | ||||
| argparser.add_argument('-u', '--unsafe', dest='u', action='store_true', help='Auto-convert address to checksum adddress') | ||||
| argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') | ||||
| argparser.add_argument('--nonce', type=int, help='override nonce') | ||||
| argparser.add_argument('--gas-price', dest='gas_price', type=int, help='override gas price') | ||||
| @ -63,6 +67,7 @@ argparser.add_argument('-value', type=int, help='gas value of transaction in wei | ||||
| argparser.add_argument('-v', action='store_true', help='Be verbose') | ||||
| argparser.add_argument('-vv', action='store_true', help='Be more verbose') | ||||
| argparser.add_argument('-s', '--send', dest='s', action='store_true', help='Send to network') | ||||
| argparser.add_argument('-l', '--local', dest='l', action='store_true', help='Local contract call') | ||||
| argparser.add_argument('data', nargs='?', type=str, help='Transaction data') | ||||
| args = argparser.parse_args() | ||||
| 
 | ||||
| @ -93,24 +98,30 @@ signer = EIP155Signer(keystore) | ||||
| 
 | ||||
| conn = EthHTTPConnection(args.p) | ||||
| 
 | ||||
| nonce_oracle = None | ||||
| if args.nonce != None: | ||||
|     nonce_oracle = OverrideNonceOracle(signer_address, args.nonce) | ||||
| else: | ||||
|     nonce_oracle = RPCNonceOracle(signer_address, conn) | ||||
| send = args.s | ||||
| 
 | ||||
| local = args.l | ||||
| if local: | ||||
|     send = False | ||||
| 
 | ||||
| nonce_oracle = None | ||||
| gas_oracle = None | ||||
| if args.gas_price or args.gas_limit != None: | ||||
|     gas_oracle = OverrideGasOracle(price=args.gas_price, limit=args.gas_limit, conn=conn) | ||||
| else: | ||||
|     gas_oracle = RPCGasOracle(conn) | ||||
| if signer_address != None and not local: | ||||
|     if args.nonce != None: | ||||
|         nonce_oracle = OverrideNonceOracle(signer_address, args.nonce) | ||||
|     else: | ||||
|         nonce_oracle = RPCNonceOracle(signer_address, conn) | ||||
| 
 | ||||
|     if args.gas_price or args.gas_limit != None: | ||||
|         gas_oracle = OverrideGasOracle(price=args.gas_price, limit=args.gas_limit, conn=conn) | ||||
|     else: | ||||
|         gas_oracle = RPCGasOracle(conn) | ||||
| 
 | ||||
| 
 | ||||
| chain_spec = ChainSpec.from_chain_str(args.i) | ||||
| 
 | ||||
| value = args.value | ||||
| 
 | ||||
| send = args.s | ||||
| 
 | ||||
| g = TxFactory(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle) | ||||
| 
 | ||||
| @ -121,14 +132,43 @@ def main(): | ||||
|         if not args.u and recipient != add_0x(recipient): | ||||
|             raise ValueError('invalid checksum address') | ||||
| 
 | ||||
|     tx = g.template(signer_address, recipient, use_nonce=True) | ||||
|     if args.data != None: | ||||
|         tx = g.set_code(tx, add_0x(args.data)) | ||||
|     if local: | ||||
|         o = jsonrpc_template() | ||||
|         o['method'] = 'eth_call' | ||||
|         o['params'].append({ | ||||
|             'to': recipient, | ||||
|             'from': signer_address, | ||||
|             'value': '0x00', | ||||
|             'gas': add_0x(int.to_bytes(8000000, 8, byteorder='big').hex()), # TODO: better get of network gas limit | ||||
|             'gasPrice': '0x01', | ||||
|             'data': add_0x(args.data), | ||||
|             }) | ||||
|         o['params'].append('latest') | ||||
|         r = conn.do(o) | ||||
|         print(strip_0x(r)) | ||||
|         return | ||||
| 
 | ||||
|     (tx_hash_hex, o) = g.finalize(tx) | ||||
|     elif signer_address != None: | ||||
|         tx = g.template(signer_address, recipient, use_nonce=True) | ||||
|         if args.data != None: | ||||
|             tx = g.set_code(tx, add_0x(args.data)) | ||||
| 
 | ||||
|         (tx_hash_hex, o) = g.finalize(tx) | ||||
|     | ||||
|     print(o) | ||||
|     print(tx_hash_hex) | ||||
|         if send: | ||||
|             r = conn.do(o) | ||||
|             print(r) | ||||
|         else: | ||||
|             print(o) | ||||
|             print(tx_hash_hex) | ||||
| 
 | ||||
|     else: | ||||
|         o = raw(args.data) | ||||
|         if send: | ||||
|             r = conn.do(o) | ||||
|             print(r) | ||||
|         else: | ||||
|             print(o) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|  | ||||
| @ -187,7 +187,7 @@ def receipt(hsh): | ||||
| def raw(tx_raw_hex): | ||||
|     o = jsonrpc_template() | ||||
|     o['method'] = 'eth_sendRawTransaction' | ||||
|     o['params'].append(tx_raw_hex) | ||||
|     o['params'].append(add_0x(tx_raw_hex)) | ||||
|     return o | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user