Then, we connect to the currently running verge instance of the current user on the local machine
66 | with one call to
67 | connect_to_local(). This returns a VERGEConnection objects:
68 |
conn=vergerpc.connect_to_local()
69 |
70 |
71 |
Try to move one verge from account testaccount to account testaccount2 using
72 | move(). Catch the InsufficientFunds
73 | exception in the case the originating account is broke:
74 |
try:
75 | conn.move("testaccount", "testaccount2", 1.0)
76 | except InsufficientFunds,e:
77 | print "Account does not have enough funds available!"
78 |
79 |
80 |
Retrieve general server information with getinfo() and print some statistics:
The goal of this library is to make it easier for:
60 |
61 |
Payment gateways to support verge
62 |
Merchant sites to integrate verge payments directly
63 |
Other services that require (micro-)payments to use verge
64 |
65 |
In this initial release it implements a thin wrapper around the
66 | VERGE JSON-RPC API. Using this API from Python directly is conceptually very simple,
67 | here is the example from the API
68 | documentation page:
However, this approach has some disadvantages, one thing is that error handling is complex, as it
78 | requires manually checking the contents of JSONException objects.
79 |
verge-python attempts to create an even more friendly interface by wrapping the JSON-RPC API. The major advantages
80 | compared to a raw jsonrpc based approach are:
81 |
82 |
Better exception handling. Exceptions are converted to subclasses of VERGEException.
83 |
Automatic verge configuration loading. In case the verge-server or verged program runs on the same
84 | machine as the client script, and as the same user, the configuration file can automatically be parsed. This
85 | makes it unneccesary to explicitly specify a username and password. Of course, this is still possible.
86 |
Documentation in Pythonish format. You are reading this right now.
59 | Please activate JavaScript to enable the search
60 | functionality.
61 |
62 |
63 |
64 | From here you can search these documents. Enter your search
65 | words into the box below and click "search". Note that the search
66 | function will automatically search for all of the words. Pages
67 | containing fewer words won't appear in the result list.
68 |
If you run VERGE with the -server argument, or if you run verged, it can be controlled
64 | either by sending it HTTP-JSON-RPC commands.
65 |
However, beginning with VERGE 0.3.3 you must create a verge.conf file in the VERGE data directory
66 | (default $HOME/.dogeconf) and set an RPC password:
67 |
rpcuser=anything
68 | rpcpassword=anything
69 |
70 |
71 |
Once that is done, the easiest way to check whether VERGE accepts remote commands is by running
72 | VERGE again, with the command (and any parameters) as arguments. For example:
Use the function connect_to_local(). This automagically
83 | sorts out the connection to a verge process running on the current machine,
84 | for the current user.
85 |
conn=vergerpc.connect_to_local()
86 |
87 |
88 |
89 |
Connecting to a remote verge instance
90 |
Use the function connect_to_remote(). For this function
91 | it is neccesary to explicitly specify a hostname and port to connect to, and
92 | to provide user credentials for logging in.
rv = conn.validateaddress(foo)
112 | if rv.isvalid:
113 | print "The address that you provided is valid"
114 | else:
115 | print "The address that you provided is invalid, please correct"
116 |
117 |
118 |
119 |
Sending payments
120 |
The method sendtoaddress() sends a specified
121 | amount of coins to a specified address.
To accept payments, use the method getnewaddress()
128 | to generate a new address. Give this address to the customer and store it in a safe place, to be able to check
129 | when the payment to this address has been made.
130 |
pay_to = conn.getnewaddress()
131 | print "We will ship the pirate sandwidth after payment of 200 coins to ", pay_to
132 |
133 |
134 |
135 |
Check how much has been received at a certain address
136 |
The method getreceivedbyaddress()
137 | returns how many verges have been received at a certain address. Together with the
138 | previous function, this can be used to check whether a payment has been made
139 | by the customer.
140 |
amount = conn.getreceivedbyaddress(pay_to)
141 | if amount > 200.0:
142 | print "Thanks, your sandwidth will be prepared and shipped."
143 |
More advanced usage of verge allows multiple accounts within one wallet. This
151 | can be useful if you are writing software for a bank, or
152 | simply want to have a clear separation between customers payments.
100 |
104 |
105 |
--------------------------------------------------------------------------------
/release_process.txt:
--------------------------------------------------------------------------------
1 | Release process
2 |
3 | - Update Changelog (using git history output from dist-tools/changelog.sh)
4 |
5 | - Change version numbers in setup.py and sphinx/source/conf.py
6 |
7 | - Commit
8 |
9 | - Make tag and upload to github
10 |
11 | - git tag -a vX.X
12 | - git push origin vX.X
13 |
14 | - Run make in doc/
15 |
16 | - Update documentation on github
17 |
18 | - git checkout gh_pages
19 | - rm -r doc
20 | - mkdir doc
21 | - cp -r sphinx/build/html/* doc/
22 | - git add doc
23 | - git commit -a
24 | - git push origin gh-pages:gh-pages
25 |
26 | - Upload to pypi
27 |
28 | - python setup.py sdist upload
29 |
30 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 | setup(
3 | name='verge-python',
4 | version='0.1.3',
5 | description='Friendly VERGE JSON-RPC API binding for Python',
6 | long_description='This package allows performing commands such as listing the current balance'
7 | ' and sending coins to the original client from Python. The communication with the'
8 | ' client happens over JSON-RPC.',
9 | url='https://github.com/vergecurrency/verge-python',
10 | classifiers=[
11 | 'Development Status :: 4 - Beta',
12 | 'Environment :: Console',
13 | 'Environment :: Web Environment',
14 | 'Intended Audience :: Developers',
15 | 'Programming Language :: Python',
16 | 'License :: OSI Approved :: MIT License',
17 | 'Topic :: Office/Business :: Financial'
18 | ],
19 | packages=find_packages("src"),
20 | package_dir={'': 'src'}
21 | )
22 |
--------------------------------------------------------------------------------
/sphinx/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = build
9 |
10 | # Internal variables.
11 | PAPEROPT_a4 = -D latex_paper_size=a4
12 | PAPEROPT_letter = -D latex_paper_size=letter
13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
14 |
15 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
16 |
17 | help:
18 | @echo "Please use \`make ' where is one of"
19 | @echo " html to make standalone HTML files"
20 | @echo " dirhtml to make HTML files named index.html in directories"
21 | @echo " pickle to make pickle files"
22 | @echo " json to make JSON files"
23 | @echo " htmlhelp to make HTML files and a HTML help project"
24 | @echo " qthelp to make HTML files and a qthelp project"
25 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
26 | @echo " changes to make an overview of all changed/added/deprecated items"
27 | @echo " linkcheck to check all external links for integrity"
28 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
29 |
30 | clean:
31 | -rm -rf $(BUILDDIR)/*
32 |
33 | html:
34 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
35 | @echo
36 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
37 |
38 | dirhtml:
39 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
40 | @echo
41 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
42 |
43 | pickle:
44 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
45 | @echo
46 | @echo "Build finished; now you can process the pickle files."
47 |
48 | json:
49 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
50 | @echo
51 | @echo "Build finished; now you can process the JSON files."
52 |
53 | htmlhelp:
54 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
55 | @echo
56 | @echo "Build finished; now you can run HTML Help Workshop with the" \
57 | ".hhp project file in $(BUILDDIR)/htmlhelp."
58 |
59 | qthelp:
60 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
61 | @echo
62 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
63 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
64 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/verge-python.qhcp"
65 | @echo "To view the help file:"
66 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/verge-python.qhc"
67 |
68 | latex:
69 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
70 | @echo
71 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
72 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
73 | "run these through (pdf)latex."
74 |
75 | changes:
76 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
77 | @echo
78 | @echo "The overview file is in $(BUILDDIR)/changes."
79 |
80 | linkcheck:
81 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
82 | @echo
83 | @echo "Link check complete; look for any errors in the above output " \
84 | "or in $(BUILDDIR)/linkcheck/output.txt."
85 |
86 | doctest:
87 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
88 | @echo "Testing of doctests in the sources finished, look at the " \
89 | "results in $(BUILDDIR)/doctest/output.txt."
90 |
--------------------------------------------------------------------------------
/sphinx/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | REM Command file for Sphinx documentation
4 |
5 | set SPHINXBUILD=sphinx-build
6 | set BUILDDIR=build
7 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
8 | if NOT "%PAPER%" == "" (
9 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
10 | )
11 |
12 | if "%1" == "" goto help
13 |
14 | if "%1" == "help" (
15 | :help
16 | echo.Please use `make ^` where ^ is one of
17 | echo. html to make standalone HTML files
18 | echo. dirhtml to make HTML files named index.html in directories
19 | echo. pickle to make pickle files
20 | echo. json to make JSON files
21 | echo. htmlhelp to make HTML files and a HTML help project
22 | echo. qthelp to make HTML files and a qthelp project
23 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
24 | echo. changes to make an overview over all changed/added/deprecated items
25 | echo. linkcheck to check all external links for integrity
26 | echo. doctest to run all doctests embedded in the documentation if enabled
27 | goto end
28 | )
29 |
30 | if "%1" == "clean" (
31 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
32 | del /q /s %BUILDDIR%\*
33 | goto end
34 | )
35 |
36 | if "%1" == "html" (
37 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
38 | echo.
39 | echo.Build finished. The HTML pages are in %BUILDDIR%/html.
40 | goto end
41 | )
42 |
43 | if "%1" == "dirhtml" (
44 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
45 | echo.
46 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
47 | goto end
48 | )
49 |
50 | if "%1" == "pickle" (
51 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
52 | echo.
53 | echo.Build finished; now you can process the pickle files.
54 | goto end
55 | )
56 |
57 | if "%1" == "json" (
58 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
59 | echo.
60 | echo.Build finished; now you can process the JSON files.
61 | goto end
62 | )
63 |
64 | if "%1" == "htmlhelp" (
65 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
66 | echo.
67 | echo.Build finished; now you can run HTML Help Workshop with the ^
68 | .hhp project file in %BUILDDIR%/htmlhelp.
69 | goto end
70 | )
71 |
72 | if "%1" == "qthelp" (
73 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
74 | echo.
75 | echo.Build finished; now you can run "qcollectiongenerator" with the ^
76 | .qhcp project file in %BUILDDIR%/qthelp, like this:
77 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\verge-python.qhcp
78 | echo.To view the help file:
79 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\verge-python.ghc
80 | goto end
81 | )
82 |
83 | if "%1" == "latex" (
84 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
85 | echo.
86 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
87 | goto end
88 | )
89 |
90 | if "%1" == "changes" (
91 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
92 | echo.
93 | echo.The overview file is in %BUILDDIR%/changes.
94 | goto end
95 | )
96 |
97 | if "%1" == "linkcheck" (
98 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
99 | echo.
100 | echo.Link check complete; look for any errors in the above output ^
101 | or in %BUILDDIR%/linkcheck/output.txt.
102 | goto end
103 | )
104 |
105 | if "%1" == "doctest" (
106 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
107 | echo.
108 | echo.Testing of doctests in the sources finished, look at the ^
109 | results in %BUILDDIR%/doctest/output.txt.
110 | goto end
111 | )
112 |
113 | :end
114 |
--------------------------------------------------------------------------------
/sphinx/source/apireference.rst:
--------------------------------------------------------------------------------
1 | =================
2 | API reference
3 | =================
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | vergerpc.rst
9 | vergerpc.connection.rst
10 | vergerpc.exceptions.rst
11 | vergerpc.data.rst
12 | vergerpc.config.rst
13 |
14 |
--------------------------------------------------------------------------------
/sphinx/source/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # verge-python documentation build configuration file, created by
4 | # sphinx-quickstart on Fri Dec 10 21:45:49 2010.
5 | #
6 | # This file is execfile()d with the current directory set to its containing dir.
7 | #
8 | # Note that not all possible configuration values are present in this
9 | # autogenerated file.
10 | #
11 | # All configuration values have a default; values that are commented out
12 | # serve to show the default.
13 |
14 | import sys, os
15 |
16 | # If extensions (or modules to document with autodoc) are in another directory,
17 | # add these directories to sys.path here. If the directory is relative to the
18 | # documentation root, use os.path.abspath to make it absolute, like shown here.
19 | sys.path.append(os.path.abspath('../../src'))
20 |
21 | # -- General configuration -----------------------------------------------------
22 |
23 | # Add any Sphinx extension module names here, as strings. They can be extensions
24 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
25 | extensions = ['sphinx.ext.autodoc']
26 |
27 | # Add any paths that contain templates here, relative to this directory.
28 | templates_path = ['_templates']
29 |
30 | # The suffix of source filenames.
31 | source_suffix = '.rst'
32 |
33 | # The encoding of source files.
34 | #source_encoding = 'utf-8'
35 |
36 | # The master toctree document.
37 | master_doc = 'index'
38 |
39 | # General information about the project.
40 | project = u'verge-python'
41 | copyright = u'2016, verge-python developers'
42 |
43 | # The version info for the project you're documenting, acts as replacement for
44 | # |version| and |release|, also used in various other places throughout the
45 | # built documents.
46 | #
47 | # The short X.Y version.
48 | version = '0.1'
49 | # The full version, including alpha/beta/rc tags.
50 | release = '0.1.3'
51 |
52 | # The language for content autogenerated by Sphinx. Refer to documentation
53 | # for a list of supported languages.
54 | #language = None
55 |
56 | # There are two options for replacing |today|: either, you set today to some
57 | # non-false value, then it is used:
58 | #today = ''
59 | # Else, today_fmt is used as the format for a strftime call.
60 | #today_fmt = '%B %d, %Y'
61 |
62 | # List of documents that shouldn't be included in the build.
63 | #unused_docs = []
64 |
65 | # List of directories, relative to source directory, that shouldn't be searched
66 | # for source files.
67 | exclude_trees = []
68 |
69 | # The reST default role (used for this markup: `text`) to use for all documents.
70 | #default_role = None
71 |
72 | # If true, '()' will be appended to :func: etc. cross-reference text.
73 | #add_function_parentheses = True
74 |
75 | # If true, the current module name will be prepended to all description
76 | # unit titles (such as .. function::).
77 | #add_module_names = True
78 |
79 | # If true, sectionauthor and moduleauthor directives will be shown in the
80 | # output. They are ignored by default.
81 | #show_authors = False
82 |
83 | # The name of the Pygments (syntax highlighting) style to use.
84 | pygments_style = 'sphinx'
85 |
86 | # A list of ignored prefixes for module index sorting.
87 | #modindex_common_prefix = []
88 |
89 |
90 | # -- Options for HTML output ---------------------------------------------------
91 |
92 | # The theme to use for HTML and HTML Help pages. Major themes that come with
93 | # Sphinx are currently 'default' and 'sphinxdoc'.
94 | html_theme = 'default'
95 |
96 | # Theme options are theme-specific and customize the look and feel of a theme
97 | # further. For a list of options available for each theme, see the
98 | # documentation.
99 | #html_theme_options = {}
100 |
101 | # Add any paths that contain custom themes here, relative to this directory.
102 | html_theme_path = ['_theme']
103 | #html_theme_path = []
104 |
105 | # The name for this set of Sphinx documents. If None, it defaults to
106 | # " v documentation".
107 | #html_title = None
108 |
109 | # A shorter title for the navigation bar. Default is the same as html_title.
110 | #html_short_title = None
111 |
112 | # The name of an image file (relative to this directory) to place at the top
113 | # of the sidebar.
114 | #html_logo = None
115 |
116 | # The name of an image file (within the static path) to use as favicon of the
117 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
118 | # pixels large.
119 | #html_favicon = None
120 |
121 | # Add any paths that contain custom static files (such as style sheets) here,
122 | # relative to this directory. They are copied after the builtin static files,
123 | # so a file named "default.css" will overwrite the builtin "default.css".
124 | html_static_path = ['_static']
125 |
126 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
127 | # using the given strftime format.
128 | #html_last_updated_fmt = '%b %d, %Y'
129 |
130 | # If true, SmartyPants will be used to convert quotes and dashes to
131 | # typographically correct entities.
132 | #html_use_smartypants = True
133 |
134 | # Custom sidebar templates, maps document names to template names.
135 | #html_sidebars = {}
136 |
137 | # Additional templates that should be rendered to pages, maps page names to
138 | # template names.
139 | #html_additional_pages = {}
140 |
141 | # If false, no module index is generated.
142 | #html_use_modindex = True
143 |
144 | # If false, no index is generated.
145 | #html_use_index = True
146 |
147 | # If true, the index is split into individual pages for each letter.
148 | #html_split_index = False
149 |
150 | # If true, links to the reST sources are added to the pages.
151 | #html_show_sourcelink = True
152 |
153 | # If true, an OpenSearch description file will be output, and all pages will
154 | # contain a tag referring to it. The value of this option must be the
155 | # base URL from which the finished HTML is served.
156 | #html_use_opensearch = ''
157 |
158 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
159 | #html_file_suffix = ''
160 |
161 | # Output file base name for HTML help builder.
162 | htmlhelp_basename = 'verge-pythondoc'
163 |
164 |
165 | # -- Options for LaTeX output --------------------------------------------------
166 |
167 | # The paper size ('letter' or 'a4').
168 | #latex_paper_size = 'letter'
169 |
170 | # The font size ('10pt', '11pt' or '12pt').
171 | #latex_font_size = '10pt'
172 |
173 | # Grouping the document tree into LaTeX files. List of tuples
174 | # (source start file, target name, title, author, documentclass [howto/manual]).
175 | latex_documents = [
176 | ('index', 'verge-python.tex', u'verge-python Documentation',
177 | u'Witchspace', 'manual'),
178 | ]
179 |
180 | # The name of an image file (relative to this directory) to place at the top of
181 | # the title page.
182 | #latex_logo = None
183 |
184 | # For "manual" documents, if this is true, then toplevel headings are parts,
185 | # not chapters.
186 | #latex_use_parts = False
187 |
188 | # Additional stuff for the LaTeX preamble.
189 | #latex_preamble = ''
190 |
191 | # Documents to append as an appendix to all manuals.
192 | #latex_appendices = []
193 |
194 | # If false, no module index is generated.
195 | #latex_use_modindex = True
196 |
--------------------------------------------------------------------------------
/sphinx/source/examples.rst:
--------------------------------------------------------------------------------
1 | ****************************
2 | Examples
3 | ****************************
4 |
5 | A basic program that uses ``python-verge`` looks like this:
6 |
7 | First, import the library and exceptions.
8 |
9 | ::
10 |
11 | import vergerpc
12 | from vergerpc.exceptions import InsufficientFunds
13 |
14 | Then, we connect to the currently running ``verge`` instance of the current user on the local machine
15 | with one call to
16 | :func:`~vergerpc.connect_to_local`. This returns a :class:`~vergerpc.connection.VERGEConnection` objects:
17 |
18 | ::
19 |
20 | conn = vergerpc.connect_to_local()
21 |
22 | Try to move one verge from account ``testaccount`` to account ``testaccount2`` using
23 | :func:`~vergerpc.connection.VERGEConnection.move`. Catch the :class:`~vergerpc.exceptions.InsufficientFunds`
24 | exception in the case the originating account is broke:
25 |
26 | ::
27 |
28 | try:
29 | conn.move("testaccount", "testaccount2", 100.0)
30 | except InsufficientFunds,e:
31 | print "Account does not have enough funds available!"
32 |
33 |
34 | Retrieve general server information with :func:`~vergerpc.connection.VERGEConnection.getinfo` and print some statistics:
35 |
36 | ::
37 |
38 | info = conn.getinfo()
39 | print "Blocks: %i" % info.blocks
40 | print "Connections: %i" % info.connections
41 | print "Difficulty: %f" % info.difficulty
42 |
43 |
44 |
--------------------------------------------------------------------------------
/sphinx/source/gettingstarted.rst:
--------------------------------------------------------------------------------
1 | =================
2 | Getting Started
3 | =================
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | introduction.rst
9 | usage.rst
10 | examples.rst
11 |
12 |
--------------------------------------------------------------------------------
/sphinx/source/index.rst:
--------------------------------------------------------------------------------
1 | ==================================================
2 | verge-python - Easy-to-use VERGE API client.
3 | ==================================================
4 |
5 | ``verge-python`` is a set of Python libraries that allows easy access to the
6 | verge_ peer-to-peer cryptocurrency client API.
7 |
8 | Contents:
9 |
10 | .. toctree::
11 | :maxdepth: 2
12 |
13 | gettingstarted.rst
14 | apireference.rst
15 |
16 | Indices and tables
17 | ==================
18 |
19 | * :ref:`genindex`
20 | * :ref:`modindex`
21 | * :ref:`search`
22 |
23 | .. _verge: http://vergecurrency.com/
24 |
25 |
--------------------------------------------------------------------------------
/sphinx/source/introduction.rst:
--------------------------------------------------------------------------------
1 | ****************************
2 | Introduction
3 | ****************************
4 |
5 | The goal of this library is to make it easier for:
6 |
7 | - Payment gateways to support verge
8 | - Merchant sites to integrate verge payments directly
9 | - Other services that require (micro-)payments to use verge
10 |
11 | In this initial release it implements a thin wrapper around the
12 | VERGE JSON-RPC API. Using this API from Python directly is conceptually very simple,
13 | here is the example from the API
14 | documentation page:
15 |
16 | ::
17 |
18 | from jsonrpc import ServiceProxy
19 |
20 | access = ServiceProxy("http://user:password@127.0.0.1:20102")
21 | access.getinfo()
22 | access.listreceivedbyaddress(6)
23 | access.sendtoaddress("11yEmxiMso2RsFVfBcCa616npBvGgxiBX", 1000)
24 |
25 | However, this approach has some disadvantages, one thing is that error handling is complex, as it
26 | requires manually checking the contents of :const:`JSONException` objects.
27 |
28 | ``verge-python`` attempts to create an even more friendly interface by wrapping the JSON-RPC API. The major advantages
29 | compared to a raw ``jsonrpc`` based approach are:
30 |
31 | - Better exception handling. Exceptions are converted to subclasses of :class:`~vergerpc.exceptions.VERGEException`.
32 |
33 | - Automatic verge configuration loading. In case the ``verge -server`` or ``verged`` program runs on the same
34 | machine as the client script, and as the same user, the configuration file can automatically be parsed. This
35 | makes it unneccesary to explicitly specify a *username* and *password*. Of course, this is still possible.
36 |
37 | - Documentation in Pythonish format. You are reading this right now.
38 |
39 | - The functions
40 | :func:`~vergerpc.connection.VERGEConnection.getinfo`, :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaccount`,
41 | :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaddress`,
42 | :func:`~vergerpc.connection.VERGEConnection.listtransactions` and more return actual Python objects, instead of simply
43 | dictionaries. This makes for cleaner code, as the fields can simply be addressed with ``x.foo`` instead of
44 | ``x['foo']``.
45 |
46 | The plan for future releases is to add a more high-level interface on top of this.
47 |
48 |
--------------------------------------------------------------------------------
/sphinx/source/usage.rst:
--------------------------------------------------------------------------------
1 | =================
2 | Usage
3 | =================
4 |
5 | See also the `main verge documentation`_ for details and background on setting up and
6 | using verged remotely.
7 |
8 | Setting up verge for remote control
9 | -------------------------------------
10 |
11 | If you run VERGE with the ``-server`` argument, or if you run ``verged``, it can be controlled
12 | either by sending it HTTP-JSON-RPC commands.
13 |
14 | However, beginning with VERGE 0.3.3 you must create a ``VERGE.conf`` file in the VERGE data directory
15 | (default ``$HOME/.vergeconf``) and set an RPC password:
16 |
17 | ::
18 |
19 | rpcuser=anything
20 | rpcpassword=anything
21 |
22 | Once that is done, the easiest way to check whether VERGE accepts remote commands is by running
23 | VERGE again, with the command (and any parameters) as arguments. For example:
24 |
25 | ::
26 |
27 | $ verged getinfo
28 |
29 | Connecting to the wallet from Python
30 | -------------------------------------
31 |
32 | There are two functions for this:
33 |
34 | *Connecting to local verge instance*
35 | Use the function :func:`~vergerpc.connect_to_local`. This automagically
36 | sorts out the connection to a verge process running on the current machine,
37 | for the current user.
38 |
39 | ::
40 |
41 | conn = vergerpc.connect_to_local()
42 |
43 | *Connecting to a remote verge instance*
44 | Use the function :func:`~vergerpc.connect_to_remote`. For this function
45 | it is neccesary to explicitly specify a hostname and port to connect to, and
46 | to provide user credentials for logging in.
47 |
48 | ::
49 |
50 | conn = vergerpc.connect_to_remote('foo', 'bar', host='payments.yoyodyne.com', port=20102)
51 |
52 |
53 | How to use the API
54 | -------------------------------------
55 |
56 | For basic sending and receiving of payments, the four most important methods are
57 |
58 | *Getting the current balance*
59 | Use the method :func:`~vergerpc.connection.VERGEConnection.getbalance` to get the current server balance.
60 |
61 | ::
62 |
63 | print "Your balance is %f" % (conn.getbalance(),)
64 |
65 | *Check a customer address for validity and get information about it*
66 | This can be done with the method :func:`~vergerpc.connection.VERGEConnection.validateaddress`.
67 |
68 | ::
69 |
70 | rv = conn.validateaddress(foo)
71 | if rv.isvalid:
72 | print "The address that you provided is valid"
73 | else:
74 | print "The address that you provided is invalid, please correct"
75 |
76 | *Sending payments*
77 | The method :func:`~vergerpc.connection.VERGEConnection.sendtoaddress` sends a specified
78 | amount of coins to a specified address.
79 |
80 | ::
81 |
82 | conn.sendtoaddress("msTGAm1ApjEJfsWfAaRVaZHRm26mv5GL73", 10000.0)
83 |
84 | *Get a new address for accepting payments*
85 | To accept payments, use the method :func:`~vergerpc.connection.VERGEConnection.getnewaddress`
86 | to generate a new address. Give this address to the customer and store it in a safe place, to be able to check
87 | when the payment to this address has been made.
88 |
89 | ::
90 |
91 | pay_to = conn.getnewaddress()
92 | print "We will ship the pirate sandwidth after payment of 200 coins to ", pay_to
93 |
94 | *Check how much has been received at a certain address*
95 | The method :func:`~vergerpc.connection.VERGEConnection.getreceivedbyaddress`
96 | returns how many verges have been received at a certain address. Together with the
97 | previous function, this can be used to check whether a payment has been made
98 | by the customer.
99 |
100 | ::
101 |
102 | amount = conn.getreceivedbyaddress(pay_to)
103 | if amount > 20000.0:
104 | print "Thanks, your order will be prepared and shipped."
105 |
106 |
107 |
108 |
109 | The account API
110 | -------------------------------------
111 | More advanced usage of verge allows multiple accounts within one wallet. This
112 | can be useful if you are writing software for a bank, or
113 | simply want to have a clear separation between customers payments.
114 |
115 | For this, see the `Account API`_ documentation.
116 |
117 | .. _main bitcoin documentation: https://en.bitcoin.it/wiki/Main_Page
118 | .. _account API: https://en.bitcoin.it/wiki/Accounts_explained
119 |
120 |
121 |
--------------------------------------------------------------------------------
/sphinx/source/vergerpc.config.rst:
--------------------------------------------------------------------------------
1 | :mod:`vergerpc.config` --- Utilities for reading verge configuration files
2 | ====================================================================================
3 |
4 | .. automodule:: vergerpc.config
5 | :members:
6 | :show-inheritance:
7 |
8 |
--------------------------------------------------------------------------------
/sphinx/source/vergerpc.connection.rst:
--------------------------------------------------------------------------------
1 | :mod:`vergerpc.connection` --- Connect to VERGE server via JSON-RPC
2 | ====================================================================================
3 |
4 | .. automodule:: vergerpc.connection
5 | :members:
6 | :show-inheritance:
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sphinx/source/vergerpc.data.rst:
--------------------------------------------------------------------------------
1 | :mod:`vergerpc.data` --- VERGE RPC service, data objects
2 | ====================================================================================
3 |
4 | .. automodule:: vergerpc.data
5 | :members:
6 | :show-inheritance:
7 |
8 |
--------------------------------------------------------------------------------
/sphinx/source/vergerpc.exceptions.rst:
--------------------------------------------------------------------------------
1 | :mod:`vergerpc.exceptions` --- Exception definitions
2 | ====================================================================================
3 |
4 | .. automodule:: vergerpc.exceptions
5 | :members:
6 | :show-inheritance:
7 |
8 |
--------------------------------------------------------------------------------
/sphinx/source/vergerpc.rst:
--------------------------------------------------------------------------------
1 | :mod:`vergerpc` --- Convenience functions
2 | ====================================================================================
3 |
4 | .. automodule:: vergerpc
5 | :members:
6 | :show-inheritance:
7 |
8 |
--------------------------------------------------------------------------------
/sphinx/source/vergerpc.util.rst:
--------------------------------------------------------------------------------
1 | :mod:`vergerpc.util` --- Generic utilities used by verge client library
2 | ====================================================================================
3 |
4 | .. automodule:: vergerpc.util
5 | :members:
6 | :show-inheritance:
7 |
8 |
--------------------------------------------------------------------------------
/src/vergerpc/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2010 Witchspace
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy
4 | # of this software and associated documentation files (the "Software"), to deal
5 | # in the Software without restriction, including without limitation the rights
6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | # copies of the Software, and to permit persons to whom the Software is
8 | # furnished to do so, subject to the following conditions:
9 | #
10 | # The above copyright notice and this permission notice shall be included in
11 | # all copies or substantial portions of the Software.
12 | #
13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | # THE SOFTWARE.
20 | """
21 | verge-python - Easy-to-use VERGE API client
22 | """
23 |
24 |
25 | def connect_to_local(filename=None):
26 | """
27 | Connect to default verge instance owned by this user, on this machine.
28 |
29 | Returns a :class:`~vergerpc.connection.VERGEConnection` object.
30 |
31 | Arguments:
32 |
33 | - `filename`: Path to a configuration file in a non-standard location (optional)
34 | """
35 | from vergerpc.connection import VERGEConnection
36 | from vergerpc.config import read_default_config
37 |
38 | cfg = read_default_config(filename)
39 | if cfg is None:
40 | cfg = {}
41 | #port = int(cfg.get('rpcport', '18332' if cfg.get('testnet') else '20102'))
42 | port = int(cfg.get('rpcport', '20102'))
43 | rpcuser = cfg.get('rpcuser', '')
44 | rpcpassword = cfg.get('rpcpassword', '')
45 |
46 | return VERGEConnection(rpcuser, rpcpassword, 'localhost', port)
47 |
48 |
49 | def connect_to_remote(user, password, host='localhost', port=20102,
50 | use_https=False):
51 | """
52 | Connect to remote or alternative local verge client instance.
53 |
54 | Returns a :class:`~vergerpc.connection.VERGEConnection` object.
55 | """
56 | from vergerpc.connection import VERGEConnection
57 |
58 | return VERGEConnection(user, password, host, port, use_https)
59 |
--------------------------------------------------------------------------------
/src/vergerpc/config.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2010 Witchspace
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy
4 | # of this software and associated documentation files (the "Software"), to deal
5 | # in the Software without restriction, including without limitation the rights
6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | # copies of the Software, and to permit persons to whom the Software is
8 | # furnished to do so, subject to the following conditions:
9 | #
10 | # The above copyright notice and this permission notice shall be included in
11 | # all copies or substantial portions of the Software.
12 | #
13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | # THE SOFTWARE.
20 | """
21 | Utilities for reading verge configuration files.
22 | """
23 |
24 |
25 | def read_config_file(filename):
26 | """
27 | Read a simple ``'='``-delimited config file.
28 | Raises :const:`IOError` if unable to open file, or :const:`ValueError`
29 | if an parse error occurs.
30 | """
31 | f = open(filename)
32 | try:
33 | cfg = {}
34 | for line in f:
35 | line = line.strip()
36 | if line and not line.startswith("#"):
37 | try:
38 | (key, value) = line.split('=', 1)
39 | cfg[key] = value
40 | except ValueError:
41 | pass # Happens when line has no '=', ignore
42 | finally:
43 | f.close()
44 | return cfg
45 |
46 |
47 | def read_default_config(filename=None):
48 | """
49 | Read verge default configuration from the current user's home directory.
50 |
51 | Arguments:
52 |
53 | - `filename`: Path to a configuration file in a non-standard location (optional)
54 | """
55 | if filename is None:
56 | import os
57 | import platform
58 | home = os.getenv("HOME")
59 | if not home:
60 | raise IOError("Home directory not defined, don't know where to look for config file")
61 |
62 | if platform.system() == "Darwin":
63 | location = 'Library/Application Support/VERGE/VERGE.conf'
64 | elif platform.system() in ('Windows', 'Microsoft'):
65 | location = 'AppData\\Roaming\\VERGE\\VERGE.conf'
66 | else:
67 | location = '.VERGE/VERGE.conf'
68 | filename = os.path.join(home, location)
69 |
70 | elif filename.startswith("~"):
71 | import os
72 | filename = os.path.expanduser(filename)
73 |
74 | try:
75 | return read_config_file(filename)
76 | except (IOError, ValueError):
77 | pass # Cannot read config file, ignore
78 |
--------------------------------------------------------------------------------
/src/vergerpc/data.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2010 Witchspace
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy
4 | # of this software and associated documentation files (the "Software"), to deal
5 | # in the Software without restriction, including without limitation the rights
6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | # copies of the Software, and to permit persons to whom the Software is
8 | # furnished to do so, subject to the following conditions:
9 | #
10 | # The above copyright notice and this permission notice shall be included in
11 | # all copies or substantial portions of the Software.
12 | #
13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | # THE SOFTWARE.
20 | """
21 | VERGE RPC service, data objects.
22 | """
23 | from vergerpc.util import DStruct
24 |
25 |
26 | class ServerInfo(DStruct):
27 | """
28 | Information object returned by :func:`~vergerpc.connection.VERGEConnection.getinfo`.
29 |
30 | - *errors* -- Number of errors.
31 |
32 | - *blocks* -- Number of blocks.
33 |
34 | - *paytxfee* -- Amount of transaction fee to pay.
35 |
36 | - *keypoololdest* -- Oldest key in keypool.
37 |
38 | - *genproclimit* -- Processor limit for generation.
39 |
40 | - *connections* -- Number of connections to other clients.
41 |
42 | - *difficulty* -- Current generating difficulty.
43 |
44 | - *testnet* -- True if connected to testnet, False if on real network.
45 |
46 | - *version* -- VERGE client version.
47 |
48 | - *proxy* -- Proxy configured in client.
49 |
50 | - *hashespersec* -- Number of hashes per second (if generation enabled).
51 |
52 | - *balance* -- Total current server balance.
53 |
54 | - *generate* -- True if generation enabled, False if not.
55 |
56 | - *unlocked_until* -- Timestamp (seconds since epoch) after which the wallet
57 | will be/was locked (if wallet encryption is enabled).
58 |
59 | """
60 |
61 |
62 | class AccountInfo(DStruct):
63 | """
64 | Information object returned by :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaccount`.
65 |
66 | - *account* -- The account of the receiving address.
67 |
68 | - *amount* -- Total amount received by the address.
69 |
70 | - *confirmations* -- Number of confirmations of the most recent transaction included.
71 |
72 | """
73 |
74 |
75 | class AddressInfo(DStruct):
76 | """
77 | Information object returned by :func:`~vergerpc.connection.VERGEConnection.listreceivedbyaddress`.
78 |
79 | - *address* -- Receiving address.
80 |
81 | - *account* -- The account of the receiving address.
82 |
83 | - *amount* -- Total amount received by the address.
84 |
85 | - *confirmations* -- Number of confirmations of the most recent transaction included.
86 |
87 | """
88 |
89 |
90 | class TransactionInfo(DStruct):
91 | """
92 | Information object returned by :func:`~vergerpc.connection.VERGEConnection.listtransactions`.
93 |
94 | - *account* -- account name.
95 |
96 | - *address* -- the address verges were sent to, or received from.
97 |
98 | - *category* -- will be generate, send, receive, or move.
99 |
100 | - *amount* -- amount of transaction.
101 |
102 | - *fee* -- Fee (if any) paid (only for send transactions).
103 |
104 | - *confirmations* -- number of confirmations (only for generate/send/receive).
105 |
106 | - *txid* -- transaction ID (only for generate/send/receive).
107 |
108 | - *otheraccount* -- account funds were moved to or from (only for move).
109 |
110 | - *message* -- message associated with transaction (only for send).
111 |
112 | - *to* -- message-to associated with transaction (only for send).
113 | """
114 |
115 |
116 | class AddressValidation(DStruct):
117 | """
118 | Information object returned by :func:`~vergerpc.connection.VERGEConnection.validateaddress`.
119 |
120 | - *isvalid* -- Validatity of address (:const:`True` or :const:`False`).
121 |
122 | - *ismine* -- :const:`True` if the address is in the server's wallet.
123 |
124 | - *address* -- VERGE address.
125 |
126 | """
127 |
128 |
129 | class WorkItem(DStruct):
130 | """
131 | Information object returned by :func:`~vergerpc.connection.VERGEConnection.getwork`.
132 |
133 | - *midstate* -- Precomputed hash state after hashing the first half of the data.
134 |
135 | - *data* -- Block data.
136 |
137 | - *hash1* -- Formatted hash buffer for second hash.
138 |
139 | - *target* -- Little endian hash target.
140 |
141 | """
142 |
143 |
144 | class MiningInfo(DStruct):
145 | """
146 | Information object returned by :func:`~vergerpc.connection.VERGEConnection.getmininginfo`.
147 |
148 | - *blocks* -- Number of blocks.
149 |
150 | - *currentblocksize* -- Size of current block.
151 |
152 | - *currentblocktx* -- Number of transactions in current block.
153 |
154 | - *difficulty* -- Current generating difficulty.
155 |
156 | - *errors* -- Number of errors.
157 |
158 | - *generate* -- True if generation enabled, False if not.
159 |
160 | - *genproclimit* -- Processor limit for generation.
161 |
162 | - *hashespersec* -- Number of hashes per second (if generation enabled).
163 |
164 | - *pooledtx* -- Number of pooled transactions.
165 |
166 | - *testnet* -- True if connected to testnet, False if on real network.
167 |
168 | """
169 |
--------------------------------------------------------------------------------
/src/vergerpc/exceptions.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2010 Witchspace
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy
4 | # of this software and associated documentation files (the "Software"), to deal
5 | # in the Software without restriction, including without limitation the rights
6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | # copies of the Software, and to permit persons to whom the Software is
8 | # furnished to do so, subject to the following conditions:
9 | #
10 | # The above copyright notice and this permission notice shall be included in
11 | # all copies or substantial portions of the Software.
12 | #
13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | # THE SOFTWARE.
20 | """
21 | Exception definitions.
22 | """
23 |
24 |
25 | class VERGEException(Exception):
26 | """
27 | Base class for exceptions received from VERGE server.
28 |
29 | - *code* -- Error code from ``verged``.
30 | """
31 | # Standard JSON-RPC 2.0 errors
32 | INVALID_REQUEST = -32600,
33 | METHOD_NOT_FOUND = -32601,
34 | INVALID_PARAMS = -32602,
35 | INTERNAL_ERROR = -32603,
36 | PARSE_ERROR = -32700,
37 |
38 | # General application defined errors
39 | MISC_ERROR = -1 # std::exception thrown in command handling
40 | FORBIDDEN_BY_SAFE_MODE = -2 # Server is in safe mode, and command is not allowed in safe mode
41 | TYPE_ERROR = -3 # Unexpected type was passed as parameter
42 | INVALID_ADDRESS_OR_KEY = -5 # Invalid address or key
43 | OUT_OF_MEMORY = -7 # Ran out of memory during operation
44 | INVALID_PARAMETER = -8 # Invalid, missing or duplicate parameter
45 | DATABASE_ERROR = -20 # Database error
46 | DESERIALIZATION_ERROR = -22 # Error parsing or validating structure in raw format
47 |
48 | # P2P client errors
49 | CLIENT_NOT_CONNECTED = -9 # VERGE is not connected
50 | CLIENT_IN_INITIAL_DOWNLOAD = -10 # Still downloading initial blocks
51 |
52 | # Wallet errors
53 | WALLET_ERROR = -4 # Unspecified problem with wallet (key not found etc.)
54 | WALLET_INSUFFICIENT_FUNDS = -6 # Not enough funds in wallet or account
55 | WALLET_INVALID_ACCOUNT_NAME = -11 # Invalid account name
56 | WALLET_KEYPOOL_RAN_OUT = -12 # Keypool ran out, call keypoolrefill first
57 | WALLET_UNLOCK_NEEDED = -13 # Enter the wallet passphrase with walletpassphrase first
58 | WALLET_PASSPHRASE_INCORRECT = -14 # The wallet passphrase entered was incorrect
59 | WALLET_WRONG_ENC_STATE = -15 # Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
60 | WALLET_ENCRYPTION_FAILED = -16 # Failed to encrypt the wallet
61 | WALLET_ALREADY_UNLOCKED = -17 # Wallet is already unlocked
62 |
63 | def __init__(self, error):
64 | Exception.__init__(self, error['message'])
65 | self.code = error['code']
66 |
67 |
68 | class TransportException(Exception):
69 | """
70 | Class to define transport-level failures.
71 | """
72 | def __init__(self, msg, code=None, protocol=None, raw_detail=None):
73 | self.msg = msg
74 | self.code = code
75 | self.protocol = protocol
76 | self.raw_detail = raw_detail
77 | self.s = """
78 | Transport-level failure: {msg}
79 | Code: {code}
80 | Protocol: {protocol}
81 | """.format(msg=msg, code=code, protocol=protocol)
82 |
83 | def __str__(self):
84 | return self.s
85 |
86 |
87 | ##### General application defined errors
88 | class SafeMode(VERGEException):
89 | """
90 | Operation denied in safe mode (run ``verged`` with ``-disablesafemode``).
91 | """
92 |
93 |
94 | class JSONTypeError(VERGEException):
95 | """
96 | Unexpected type was passed as parameter
97 | """
98 | InvalidAmount = JSONTypeError # Backwards compatibility
99 |
100 |
101 | class InvalidAddressOrKey(VERGEException):
102 | """
103 | Invalid address or key.
104 | """
105 | InvalidTransactionID = InvalidAddressOrKey # Backwards compatibility
106 |
107 |
108 | class OutOfMemory(VERGEException):
109 | """
110 | Out of memory during operation.
111 | """
112 |
113 |
114 | class InvalidParameter(VERGEException):
115 | """
116 | Invalid parameter provided to RPC call.
117 | """
118 |
119 |
120 | ##### Client errors
121 | class ClientException(VERGEException):
122 | """
123 | P2P network error.
124 | This exception is never raised but functions as a superclass
125 | for other P2P client exceptions.
126 | """
127 |
128 |
129 | class NotConnected(ClientException):
130 | """
131 | Not connected to any peers.
132 | """
133 |
134 |
135 | class DownloadingBlocks(ClientException):
136 | """
137 | Client is still downloading blocks.
138 | """
139 |
140 |
141 | ##### Wallet errors
142 | class WalletError(VERGEException):
143 | """
144 | Unspecified problem with wallet (key not found etc.)
145 | """
146 | SendError = WalletError # Backwards compatibility
147 |
148 |
149 | class InsufficientFunds(WalletError):
150 | """
151 | Insufficient funds to complete transaction in wallet or account
152 | """
153 |
154 |
155 | class InvalidAccountName(WalletError):
156 | """
157 | Invalid account name
158 | """
159 |
160 |
161 | class KeypoolRanOut(WalletError):
162 | """
163 | Keypool ran out, call keypoolrefill first
164 | """
165 |
166 |
167 | class WalletUnlockNeeded(WalletError):
168 | """
169 | Enter the wallet passphrase with walletpassphrase first
170 | """
171 |
172 |
173 | class WalletPassphraseIncorrect(WalletError):
174 | """
175 | The wallet passphrase entered was incorrect
176 | """
177 |
178 |
179 | class WalletWrongEncState(WalletError):
180 | """
181 | Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
182 | """
183 |
184 |
185 | class WalletEncryptionFailed(WalletError):
186 | """
187 | Failed to encrypt the wallet
188 | """
189 |
190 |
191 | class WalletAlreadyUnlocked(WalletError):
192 | """
193 | Wallet is already unlocked
194 | """
195 |
196 |
197 | # For convenience, we define more specific exception classes
198 | # for the more common errors.
199 | _exception_map = {
200 | VERGEException.FORBIDDEN_BY_SAFE_MODE: SafeMode,
201 | VERGEException.TYPE_ERROR: JSONTypeError,
202 | VERGEException.WALLET_ERROR: WalletError,
203 | VERGEException.INVALID_ADDRESS_OR_KEY: InvalidAddressOrKey,
204 | VERGEException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds,
205 | VERGEException.OUT_OF_MEMORY: OutOfMemory,
206 | VERGEException.INVALID_PARAMETER: InvalidParameter,
207 | VERGEException.CLIENT_NOT_CONNECTED: NotConnected,
208 | VERGEException.CLIENT_IN_INITIAL_DOWNLOAD: DownloadingBlocks,
209 | VERGEException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds,
210 | VERGEException.WALLET_INVALID_ACCOUNT_NAME: InvalidAccountName,
211 | VERGEException.WALLET_KEYPOOL_RAN_OUT: KeypoolRanOut,
212 | VERGEException.WALLET_UNLOCK_NEEDED: WalletUnlockNeeded,
213 | VERGEException.WALLET_PASSPHRASE_INCORRECT: WalletPassphraseIncorrect,
214 | VERGEException.WALLET_WRONG_ENC_STATE: WalletWrongEncState,
215 | VERGEException.WALLET_ENCRYPTION_FAILED: WalletEncryptionFailed,
216 | VERGEException.WALLET_ALREADY_UNLOCKED: WalletAlreadyUnlocked,
217 | }
218 |
219 |
220 | def wrap_exception(error):
221 | """
222 | Convert a JSON error object to a more specific VERGE exception.
223 | """
224 | # work around to temporarily fix https://github.com/bitcoin/bitcoin/issues/3007
225 | if error['code'] == VERGEException.WALLET_ERROR and error['message'] == u'Insufficient funds':
226 | error['code'] = VERGEException.WALLET_INSUFFICIENT_FUNDS
227 | return _exception_map.get(error['code'], VERGEException)(error)
228 |
--------------------------------------------------------------------------------
/src/vergerpc/proxy.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) 2007 Jan-Klaas Kollhof
3 | Copyright (c) 2011-2013 Jeff Garzik
4 | Copyright (c) 2013 Nikolay Belikov (nikolay@belikov.me)
5 |
6 |
7 | jsonrpc is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation; either version 2.1 of the License, or
10 | (at your option) any later version.
11 |
12 | This software is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU Lesser General Public License for more details.
16 |
17 | You should have received a copy of the GNU Lesser General Public License
18 | along with this software; if not, write to the Free Software
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 | """
21 |
22 | try:
23 | import http.client as httplib
24 | except ImportError:
25 | import httplib
26 | import base64
27 | import json
28 | import decimal
29 | try:
30 | import urllib.parse as urlparse
31 | except ImportError:
32 | import urlparse
33 | from collections import defaultdict, deque
34 | from vergerpc.exceptions import TransportException
35 |
36 | USER_AGENT = "AuthServiceProxy/0.1"
37 |
38 | HTTP_TIMEOUT = 30
39 |
40 |
41 | class JSONRPCException(Exception):
42 | def __init__(self, rpc_error):
43 | Exception.__init__(self)
44 | self.error = rpc_error
45 |
46 |
47 | class HTTPTransport(object):
48 | def __init__(self, service_url):
49 | self.service_url = service_url
50 | self.parsed_url = urlparse.urlparse(service_url)
51 | if self.parsed_url.port is None:
52 | port = 80
53 | else:
54 | port = self.parsed_url.port
55 | authpair = "%s:%s" % (self.parsed_url.username,
56 | self.parsed_url.password)
57 | authpair = authpair.encode('utf8')
58 | self.auth_header = "Basic ".encode('utf8') + base64.b64encode(authpair)
59 | if self.parsed_url.scheme == 'https':
60 | self.connection = httplib.HTTPSConnection(self.parsed_url.hostname,
61 | port, None, None, False,
62 | HTTP_TIMEOUT)
63 | else:
64 | self.connection = httplib.HTTPConnection(self.parsed_url.hostname,
65 | port, False, HTTP_TIMEOUT)
66 |
67 | def request(self, serialized_data):
68 | self.connection.request('POST', self.parsed_url.path, serialized_data,
69 | {'Host': self.parsed_url.hostname,
70 | 'User-Agent': USER_AGENT,
71 | 'Authorization': self.auth_header,
72 | 'Content-type': 'application/json'})
73 |
74 | httpresp = self.connection.getresponse()
75 | if httpresp is None:
76 | self._raise_exception({
77 | 'code': -342, 'message': 'missing HTTP response from server'})
78 | elif httpresp.status == httplib.FORBIDDEN:
79 | msg = "verged returns 403 Forbidden. Is your IP allowed?"
80 | raise TransportException(msg, code=403,
81 | protocol=self.parsed_url.scheme,
82 | raw_detail=httpresp)
83 |
84 | resp = httpresp.read()
85 | return resp.decode('utf8')
86 |
87 |
88 | class FakeTransport(object):
89 | """A simple testing facility."""
90 | def __init__(self):
91 | self._data = defaultdict(deque)
92 |
93 | def load_serialized(self, method_name, fixture):
94 | self._data[method_name].append(fixture)
95 |
96 | def load_raw(self, method_name, fixture):
97 | self._data[method_name].append(json.dumps(fixture))
98 |
99 | def request(self, serialized_data):
100 | data = json.loads(serialized_data, parse_float=decimal.Decimal)
101 | method_name = data['method']
102 | return self._data[method_name].popleft()
103 |
104 |
105 | class RPCMethod(object):
106 | def __init__(self, name, service_proxy):
107 | self._method_name = name
108 | self._service_proxy = service_proxy
109 |
110 | def __getattr__(self, name):
111 | new_name = '{}.{}'.format(self._method_name, name)
112 | return RPCMethod(new_name, self._service_proxy)
113 |
114 | def __call__(self, *args):
115 | self._service_proxy._id_counter += 1
116 | data = {'version': '1.1',
117 | 'method': self._method_name,
118 | 'params': args,
119 | 'id': self._service_proxy._id_counter}
120 | postdata = json.dumps(data)
121 | resp = self._service_proxy._transport.request(postdata)
122 | resp = json.loads(resp, parse_float=decimal.Decimal)
123 |
124 | if resp['error'] is not None:
125 | self._service_proxy._raise_exception(resp['error'])
126 | elif 'result' not in resp:
127 | self._service_proxy._raise_exception({
128 | 'code': -343, 'message': 'missing JSON-RPC result'})
129 | else:
130 | return resp['result']
131 |
132 | def __repr__(self):
133 | return ''.format(name=self._method_name)
134 |
135 |
136 | class AuthServiceProxy(object):
137 | """
138 | You can use custom transport to test your app's behavior without calling
139 | the remote service.
140 |
141 | exception_wrapper is a callable accepting a dictionary containing error
142 | code and message and returning a suitable exception object.
143 | """
144 | def __init__(self, service_url, transport=None, exception_wrapper=None):
145 | self._service_url = service_url
146 | self._id_counter = 0
147 | self._transport = (HTTPTransport(service_url) if transport is None
148 | else transport)
149 | self._exception_wrapper = exception_wrapper
150 |
151 | def __getattr__(self, name):
152 | return RPCMethod(name, self)
153 |
154 | def _get_method(self, name):
155 | """
156 | Get method instance when the name contains forbidden characters or
157 | already taken by internal attribute.
158 | """
159 | return RPCMethod(name, self)
160 |
161 | def _raise_exception(self, error):
162 | if self._exception_wrapper is None:
163 | raise JSONRPCException(error)
164 | else:
165 | raise self._exception_wrapper(error)
166 |
--------------------------------------------------------------------------------
/src/vergerpc/util.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2010 Witchspace
2 | #
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy
4 | # of this software and associated documentation files (the "Software"), to deal
5 | # in the Software without restriction, including without limitation the rights
6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | # copies of the Software, and to permit persons to whom the Software is
8 | # furnished to do so, subject to the following conditions:
9 | #
10 | # The above copyright notice and this permission notice shall be included in
11 | # all copies or substantial portions of the Software.
12 | #
13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | # THE SOFTWARE.
20 | """Generic utilities used by verge client library."""
21 | from copy import copy
22 |
23 |
24 | class DStruct(object):
25 | """
26 | Simple dynamic structure, like :const:`collections.namedtuple` but more flexible
27 | (and less memory-efficient)
28 | """
29 | # Default arguments. Defaults are *shallow copied*, to allow defaults such as [].
30 | _fields = []
31 | _defaults = {}
32 |
33 | def __init__(self, *args_t, **args_d):
34 | # order
35 | if len(args_t) > len(self._fields):
36 | raise TypeError("Number of arguments is larger than of predefined fields")
37 | # Copy default values
38 | for (k, v) in self._defaults.items():
39 | self.__dict__[k] = copy(v)
40 | # Set pass by value arguments
41 | self.__dict__.update(zip(self._fields, args_t))
42 | # dict
43 | self.__dict__.update(args_d)
44 |
45 | def __repr__(self):
46 | return '{module}.{classname}({slots})'.format(
47 | module=self.__class__.__module__, classname=self.__class__.__name__,
48 | slots=", ".join('{k}={v!r}'.format(k=k, v=v) for k, v in
49 | self.__dict__.items()))
50 |
--------------------------------------------------------------------------------
/tests/test.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | '''
3 | Test script
4 | *WARNING* Don't run this on a production verge server! *WARNING*
5 | Only on the test network.
6 | '''
7 | import argparse
8 | import sys
9 | sys.path.append('../src')
10 |
11 | import vergerpc
12 | from vergerpc.exceptions import VERGEException, InsufficientFunds
13 |
14 |
15 | from decimal import Decimal
16 |
17 | parser = argparse.ArgumentParser()
18 | parser.add_argument('--config', help="Specify configuration file")
19 | parser.add_argument('--nolocal', help="Don't use connect_to_local",
20 | action='store_true')
21 | parser.add_argument('--noremote', help="Don't use connect_to_remote",
22 | action='store_true')
23 | args = parser.parse_args()
24 |
25 | if __name__ == "__main__":
26 |
27 | if args.config:
28 | from vergerpc.config import read_config_file
29 | cfg = read_config_file(args.config)
30 | else:
31 | from vergerpc.config import read_default_config
32 | cfg = read_default_config(None)
33 | port = int(cfg.get('rpcport', '20102'))
34 | rpcuser = cfg.get('rpcuser', '')
35 |
36 | connections = []
37 | if not args.nolocal:
38 | local_conn = vergerpc.connect_to_local() # will use read_default_config
39 | connections.append(local_conn)
40 | if not args.noremote:
41 | remote_conn = vergerpc.connect_to_remote(
42 | user=rpcuser, password=cfg['rpcpassword'], host='localhost',
43 | port=port, use_https=False)
44 | connections.append(remote_conn)
45 |
46 | for conn in connections:
47 | assert(conn.getinfo().testnet) # don't test on prodnet
48 |
49 | assert(type(conn.getblockcount()) is int)
50 | assert(type(conn.getconnectioncount()) is int)
51 | assert(type(conn.getdifficulty()) is Decimal)
52 | assert(type(conn.getgenerate()) is bool)
53 | conn.setgenerate(True)
54 | conn.setgenerate(True, 2)
55 | conn.setgenerate(False)
56 | assert(type(conn.gethashespersec()) is int)
57 | account = "testaccount"
58 | account2 = "testaccount2"
59 | vergeaddress = conn.getnewaddress(account)
60 | conn.setaccount(vergeaddress, account)
61 | address = conn.getaccountaddress(account)
62 | address2 = conn.getaccountaddress(account2)
63 | assert(conn.getaccount(address) == account)
64 | addresses = conn.getaddressesbyaccount(account)
65 | assert(address in addresses)
66 | #conn.sendtoaddress(vergeaddress, amount, comment=None, comment_to=None)
67 | conn.getreceivedbyaddress(vergeaddress)
68 | conn.getreceivedbyaccount(account)
69 | conn.listreceivedbyaddress()
70 | conn.listreceivedbyaccount()
71 | #conn.backupwallet(destination)
72 | x = conn.validateaddress(address)
73 | assert(x.isvalid == True)
74 | x = conn.validateaddress("invalid")
75 | assert(x.isvalid == False)
76 | messages = ('Hello, world!', u'かたな')
77 | for message in messages:
78 | signature = conn.signmessage(vergeaddress, message)
79 | assert(conn.verifymessage(vergeaddress, signature, message) is True)
80 |
81 | for accid in conn.listaccounts(as_dict=True).iterkeys():
82 | tx = conn.listtransactions(accid)
83 | if len(tx) > 0:
84 | txid = tx[0].txid
85 | txdata = conn.gettransaction(txid)
86 | assert(txdata.txid == tx[0].txid)
87 |
88 | assert(type(conn.listunspent()) is list) # needs better testing
89 |
90 | try:
91 | conn.sendtoaddress(vergeaddress, 10000000)
92 | assert(0) # Should raise InsufficientFunds
93 | except InsufficientFunds:
94 | pass
95 |
96 | info = conn.getinfo()
97 | print "Blocks: %i" % info.blocks
98 | print "Connections: %i" % info.connections
99 | print "Difficulty: %f" % info.difficulty
100 |
101 | m_info = conn.getmininginfo()
102 | print ("Pooled Transactions: {pooledtx}\n"
103 | "Testnet: {testnet}\n"
104 | "Hash Rate: {hashes} H/s".format(pooledtx=m_info.pooledtx,
105 | testnet=m_info.testnet,
106 | hashes=m_info.hashespersec))
107 |
--------------------------------------------------------------------------------