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')
|
length = int.from_bytes(b[cursor:cursor+32], 'big')
|
||||||
cursor += 32
|
cursor += 32
|
||||||
content = b[cursor:cursor+length]
|
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')
|
return content.decode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +38,10 @@ from chainlib.eth.gas import (
|
|||||||
RPCGasOracle,
|
RPCGasOracle,
|
||||||
OverrideGasOracle,
|
OverrideGasOracle,
|
||||||
)
|
)
|
||||||
from chainlib.eth.tx import TxFactory
|
from chainlib.eth.tx import (
|
||||||
|
TxFactory,
|
||||||
|
raw,
|
||||||
|
)
|
||||||
from chainlib.chain import ChainSpec
|
from chainlib.chain import ChainSpec
|
||||||
from chainlib.eth.runnable.util import decode_for_puny_humans
|
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('-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('-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('-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('--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('--nonce', type=int, help='override nonce')
|
||||||
argparser.add_argument('--gas-price', dest='gas_price', type=int, help='override gas price')
|
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('-v', action='store_true', help='Be verbose')
|
||||||
argparser.add_argument('-vv', action='store_true', help='Be more 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('-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')
|
argparser.add_argument('data', nargs='?', type=str, help='Transaction data')
|
||||||
args = argparser.parse_args()
|
args = argparser.parse_args()
|
||||||
|
|
||||||
@ -93,16 +98,23 @@ signer = EIP155Signer(keystore)
|
|||||||
|
|
||||||
conn = EthHTTPConnection(args.p)
|
conn = EthHTTPConnection(args.p)
|
||||||
|
|
||||||
|
send = args.s
|
||||||
|
|
||||||
|
local = args.l
|
||||||
|
if local:
|
||||||
|
send = False
|
||||||
|
|
||||||
nonce_oracle = None
|
nonce_oracle = None
|
||||||
if args.nonce != None:
|
gas_oracle = None
|
||||||
|
if signer_address != None and not local:
|
||||||
|
if args.nonce != None:
|
||||||
nonce_oracle = OverrideNonceOracle(signer_address, args.nonce)
|
nonce_oracle = OverrideNonceOracle(signer_address, args.nonce)
|
||||||
else:
|
else:
|
||||||
nonce_oracle = RPCNonceOracle(signer_address, conn)
|
nonce_oracle = RPCNonceOracle(signer_address, conn)
|
||||||
|
|
||||||
gas_oracle = None
|
if args.gas_price or args.gas_limit != None:
|
||||||
if args.gas_price or args.gas_limit != None:
|
|
||||||
gas_oracle = OverrideGasOracle(price=args.gas_price, limit=args.gas_limit, conn=conn)
|
gas_oracle = OverrideGasOracle(price=args.gas_price, limit=args.gas_limit, conn=conn)
|
||||||
else:
|
else:
|
||||||
gas_oracle = RPCGasOracle(conn)
|
gas_oracle = RPCGasOracle(conn)
|
||||||
|
|
||||||
|
|
||||||
@ -110,7 +122,6 @@ chain_spec = ChainSpec.from_chain_str(args.i)
|
|||||||
|
|
||||||
value = args.value
|
value = args.value
|
||||||
|
|
||||||
send = args.s
|
|
||||||
|
|
||||||
g = TxFactory(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
|
g = TxFactory(chain_spec, signer=signer, gas_oracle=gas_oracle, nonce_oracle=nonce_oracle)
|
||||||
|
|
||||||
@ -121,15 +132,44 @@ def main():
|
|||||||
if not args.u and recipient != add_0x(recipient):
|
if not args.u and recipient != add_0x(recipient):
|
||||||
raise ValueError('invalid checksum address')
|
raise ValueError('invalid checksum address')
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
elif signer_address != None:
|
||||||
tx = g.template(signer_address, recipient, use_nonce=True)
|
tx = g.template(signer_address, recipient, use_nonce=True)
|
||||||
if args.data != None:
|
if args.data != None:
|
||||||
tx = g.set_code(tx, add_0x(args.data))
|
tx = g.set_code(tx, add_0x(args.data))
|
||||||
|
|
||||||
(tx_hash_hex, o) = g.finalize(tx)
|
(tx_hash_hex, o) = g.finalize(tx)
|
||||||
|
|
||||||
|
if send:
|
||||||
|
r = conn.do(o)
|
||||||
|
print(r)
|
||||||
|
else:
|
||||||
print(o)
|
print(o)
|
||||||
print(tx_hash_hex)
|
print(tx_hash_hex)
|
||||||
|
|
||||||
|
else:
|
||||||
|
o = raw(args.data)
|
||||||
|
if send:
|
||||||
|
r = conn.do(o)
|
||||||
|
print(r)
|
||||||
|
else:
|
||||||
|
print(o)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@ -187,7 +187,7 @@ def receipt(hsh):
|
|||||||
def raw(tx_raw_hex):
|
def raw(tx_raw_hex):
|
||||||
o = jsonrpc_template()
|
o = jsonrpc_template()
|
||||||
o['method'] = 'eth_sendRawTransaction'
|
o['method'] = 'eth_sendRawTransaction'
|
||||||
o['params'].append(tx_raw_hex)
|
o['params'].append(add_0x(tx_raw_hex))
|
||||||
return o
|
return o
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = chainlib
|
name = chainlib
|
||||||
version = 0.0.3a3
|
version = 0.0.3rc1
|
||||||
description = Generic blockchain access library and tooling
|
description = Generic blockchain access library and tooling
|
||||||
author = Louis Holbrook
|
author = Louis Holbrook
|
||||||
author_email = dev@holbrook.no
|
author_email = dev@holbrook.no
|
||||||
|
Loading…
Reference in New Issue
Block a user