<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alec Buda</title>
    <description>The latest articles on DEV Community by Alec Buda (@alecbuda).</description>
    <link>https://dev.to/alecbuda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F213121%2Fdb4e1549-dcad-4fad-81bc-57251de76760.jpeg</url>
      <title>DEV Community: Alec Buda</title>
      <link>https://dev.to/alecbuda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alecbuda"/>
    <language>en</language>
    <item>
      <title>Introduction to the Bitcoin Network Protocol using Python and TCP Sockets</title>
      <dc:creator>Alec Buda</dc:creator>
      <pubDate>Wed, 30 Oct 2019 07:02:47 +0000</pubDate>
      <link>https://dev.to/alecbuda/introduction-to-the-bitcoin-network-protocol-using-python-and-tcp-sockets-1le6</link>
      <guid>https://dev.to/alecbuda/introduction-to-the-bitcoin-network-protocol-using-python-and-tcp-sockets-1le6</guid>
      <description>&lt;p&gt;Blockchain technology is built around consensus algorithms which allow distributed nodes to share a common ledger. A fundamental dependency of these algorithms is a common network protocol to enable communication between participating nodes. Today, let's write a Python program from scratch to interact with a real Bitcoin node.&lt;/p&gt;

&lt;p&gt;This post will assume you're familiar with the fundamentals of blockchain technology. If you aren't, I would recommend checking out the &lt;a href="https://bitcoin.org/bitcoin.pdf" rel="noopener noreferrer"&gt;Bitcoin White Paper&lt;/a&gt; by Satoshi Nakamoto.&lt;/p&gt;

&lt;p&gt;Bitcoin nodes communicate with each other using the TCP protocol. Nodes will typically listen on port number 8333. For a detailed description of the bitcoin network protocol &lt;a href="https://en.bitcoin.it/wiki/Protocol_documentation" rel="noopener noreferrer"&gt;check out this resource&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today, we are going to write a Python program to connect to a Bitcoin node and fetch the details of a specific transaction. Here is a diagram of the message flow that will be developed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4b8fg9fpn3iyq871rxa1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4b8fg9fpn3iyq871rxa1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we start coding our program, we must make one point clear. Interacting with a Bitcoin node using raw TCP sockets is reinventing the wheel. This has already been done by python packages such as &lt;a href="https://github.com/petertodd/python-bitcoinlib" rel="noopener noreferrer"&gt;python-bitcoinlib&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to write sophisticated applications you should definitely use the correct tool for the job. With that said though, programming with TCP sockets is a great way to improve your low level understanding of a network protocol.&lt;/p&gt;

&lt;p&gt;To begin, let's import the dependencies our program will require.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python
&lt;/span&gt;
&lt;span class="c1"&gt;# Filename:                     bitcoin-network-tutorial.py
# Command to run the program:   python bitcoin-network-tutorial.py
&lt;/span&gt;
&lt;span class="c1"&gt;# Import dependencies
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;binascii&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's now define the methods required for constructing the "version" request message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Binary encode the sub-version
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_sub_version&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;sub_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/Satoshi:0.7.2/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\x0F&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sub_version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Binary encode the network addresses
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_network_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;network_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;8s16sH&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\x01&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nb"&gt;bytearray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromhex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;00000000000000000000ffff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inet_aton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Create the TCP request object
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;checksum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;L12sL4s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;magic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Create the "version" request payload
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_payload_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peer_ip_address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60002&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;addr_local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_network_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8333&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;addr_peer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_network_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peer_ip_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8333&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getrandbits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;start_height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;LQQ26s26sQ16sL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr_peer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;addr_local&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;create_sub_version&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;start_height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://docs.python.org/2/library/struct.html" rel="noopener noreferrer"&gt;struct&lt;/a&gt; module is used for packing binary data. The &lt;a href="https://docs.python.org/3/library/hashlib.html" rel="noopener noreferrer"&gt;hashlib&lt;/a&gt; module is used for generating message checksums. For a full understanding of the code, you'll need to cross reference the data encoding with the &lt;a href="https://en.bitcoin.it/wiki/Protocol_documentation" rel="noopener noreferrer"&gt;protocol documentation.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, let's add a method for creating the "verack" request message. The verack command name is derived from "version acknowledge".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create the "verack" request message
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_message_verack&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;bytearray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromhex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;f9beb4d976657261636b000000000000000000005df6e0e2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the mandatory messages out of the way, we may now create our "getdata" method for retrieving the details of a specific transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create the "getdata" request payload
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_payload_getdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;bytearray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromhex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;bb32s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note that not all nodes will be able to return arbitrary transaction data; some will prune their history to save disk space.&lt;/p&gt;

&lt;p&gt;We'll also create a method for printing TCP data to the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Print request/response data
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Command: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Request:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We may now add our main method which will connect to a bitcoin node and execute the desired message flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Set constants
&lt;/span&gt;    &lt;span class="n"&gt;magic_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xd9b4bef9&lt;/span&gt;
    &lt;span class="n"&gt;tx_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fc57704eff327aecfadb2cf3774edc919ba69aba624b836461ce2be9c00a0c20&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;peer_ip_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;104.199.184.15&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;peer_tcp_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8333&lt;/span&gt;
    &lt;span class="n"&gt;buffer_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;

    &lt;span class="c1"&gt;# Create Request Objects
&lt;/span&gt;    &lt;span class="n"&gt;version_payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_payload_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peer_ip_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;version_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;magic_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version_payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;verack_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_message_verack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;getdata_payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_payload_getdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;getdata_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;magic_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;getdata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getdata_payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Establish TCP Connection
&lt;/span&gt;    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;peer_ip_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peer_tcp_port&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# Send message "version"
&lt;/span&gt;    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Send message "verack"
&lt;/span&gt;    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verack_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verack&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verack_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Send message "getdata"
&lt;/span&gt;    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getdata_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;getdata&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getdata_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Close the TCP connection
&lt;/span&gt;    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We found the IP address of the node using &lt;a href="https://bitnodes.earn.com/nodes/" rel="noopener noreferrer"&gt;Bitnodes.&lt;/a&gt; Details of the transaction we elected to query can be found on a &lt;a href="https://www.blockchain.com/btc/tx/fc57704eff327aecfadb2cf3774edc919ba69aba624b836461ce2be9c00a0c20" rel="noopener noreferrer"&gt;block explorer.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Execute the program on a terminal with the command &lt;code&gt;python bitcoin-network-tutorial.py&lt;/code&gt;. A sample output is provided below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command: version
Request:
b'f9beb4d976657273696f6e000000000064000000f4de76b762ea00000100000000000000c8c6ae5d00000000010000000000000000000000000000000000ffff68c7b80f208d010000000000000000000000000000000000ffff7f000001208d0f2f736a397699b60f2f5361746f7368693a302e372e322f00000000'
Response:
b'f9beb4d976657273696f6e000000000066000000fe4aee167f1101000d04000000000000c2c6ae5d00000000010000000000000000000000000000000000ffff68c7b80f208d0d040000000000000000000000000000000000000000000000000b63185e17ebcdb3102f5361746f7368693a302e31382e302fbc29090001'

Command: verack
Request:
b'f9beb4d976657261636b000000000000000000005df6e0e2'
Response:
b'f9beb4d976657261636b000000000000000000005df6e0e2'

Command: getdata
Request:
b'f9beb4d9676574646174610000000000220000007b00a9b50101fc57704eff327aecfadb2cf3774edc919ba69aba624b836461ce2be9c00a0c20'
Response:
b'f9beb4d9616c65727400000000000000c0000000d2f50d9ef9beb4d9616c65727400000000000000a80000001bf9aaea60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That concludes the tutorial! Stay tuned for more.&lt;/p&gt;

&lt;h4&gt;
  
  
  ULTRA CONFIG GENERATOR
&lt;/h4&gt;

&lt;p&gt;Have you heard of &lt;a href="https://dev.to/ultra-config-generator/"&gt;Ultra Config Generator&lt;/a&gt;? If you haven't, I highly recommend you check it out.&lt;/p&gt;

&lt;p&gt;We designed the product to allow network engineers to generate and automate network configuration in a highly flexible, efficient and elegant manner. Our customers love the application and I hope that you will too.&lt;/p&gt;

&lt;p&gt;Take care until next time!&lt;/p&gt;

&lt;p&gt;Ultra Config&lt;/p&gt;

</description>
      <category>bitcoin</category>
      <category>python</category>
      <category>blockchain</category>
      <category>protocol</category>
    </item>
    <item>
      <title>Python Automation on Cisco Routers in 2019 - NETCONF, YANG &amp; Jinja2</title>
      <dc:creator>Alec Buda</dc:creator>
      <pubDate>Mon, 02 Sep 2019 00:38:19 +0000</pubDate>
      <link>https://dev.to/alecbuda/python-automation-on-cisco-routers-in-2019-netconf-yang-jinja2-52ho</link>
      <guid>https://dev.to/alecbuda/python-automation-on-cisco-routers-in-2019-netconf-yang-jinja2-52ho</guid>
      <description>&lt;p&gt;Before reading this post, I highly recommend that you check out our &lt;a href="https://dev.to/blog/introduction-to-netconf-and-juniper-yang-models/"&gt;first NETCONF post&lt;/a&gt; we did if you are new to this subject. In this post I explained the fundamentals of NETCONF and YANG models which make for great background knowledge before getting into Python automation.&lt;/p&gt;

&lt;p&gt;For todays exercise, we will write a Python program which will configure an interface on a Cisco CSR 1000v router. Our solution will use a Jinja template for the configuration data model and the NETCONF protocol for pushing our rendered configuration payload to the router - it is my hope that this post will shed light on how this technology can be implemented in a scalable manner by decoupling configuration templates from the python codebase.&lt;/p&gt;

&lt;p&gt;To begin, let's spin up a fresh Cisco CSR 1000v router. We'll then need to configure credentials and enable NETCONF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;conf t
!
username admin privilege 15 secret admin
!
netconf-yang
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We'll also configure an interface on the router for our NETCONF client to connect to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface GigabitEthernet1
 ip address 192.168.159.10 255.255.255.0
 no shut
 exit
!
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, &lt;a href="https://www.python.org/downloads/"&gt;install Python&lt;/a&gt; on your workstation if you don't already have it.&lt;/p&gt;

&lt;p&gt;With that done, let's open up a terminal and install the "ncclient" package. This package will provide us with a NETCONF client that we will use to manage our session with the router.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install ncclient
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We will now create a new file for our python program - we entitled ours "cisco-automation-tutorial.py". At the head of the file, import the dependencies our program will utilize.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Filename:                     cisco-automation-tutorial.py
# Command to run the program:   python cisco-automation-tutorial.py
&lt;/span&gt;
&lt;span class="c1"&gt;# Import the required dependencies
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ncclient&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;jinja2&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Template&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next up, we'll establish the NETCONF session to our router using the "connect" method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Establish our NETCONF Session
&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'192.168.159.10'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;830&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'csr'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to configure our device with NETCONF we will first have to understand how to structure the configuration data within our RPC payload. Data structures in NETCONF are defined by &lt;a href="https://tools.ietf.org/html/rfc6020"&gt;YANG&lt;/a&gt; models and the CSR router actually supports many different options to choose from. For example, &lt;a href="https://github.com/openconfig"&gt;OpenConfig models&lt;/a&gt; and &lt;a href="https://tools.ietf.org/html/rfc8343"&gt;IETF models&lt;/a&gt; are both compatible with the IOS-XE software family.&lt;/p&gt;

&lt;p&gt;For todays exercise, we will use the &lt;a href="https://github.com/YangModels/yang/tree/master/vendor/cisco/xe"&gt;IOS-XE native YANG model&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get a quick feel for the native model, add the python code below to your program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create a configuration filter
&lt;/span&gt;&lt;span class="n"&gt;interface_filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'''
  &amp;lt;filter&amp;gt;
      &amp;lt;native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"&amp;gt;
          &amp;lt;interface&amp;gt;
            &amp;lt;GigabitEthernet&amp;gt;
              &amp;lt;name&amp;gt;1&amp;lt;/name&amp;gt;
            &amp;lt;/GigabitEthernet&amp;gt;
          &amp;lt;/interface&amp;gt;
      &amp;lt;/native&amp;gt;
  &amp;lt;/filter&amp;gt;
'''&lt;/span&gt;

&lt;span class="c1"&gt;# Execute the get-config RPC
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'running'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interface_filter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code is essentially the same as the CLI command &lt;code&gt;"show running-config interface GigabitEthernet 1"&lt;/code&gt;. When we execute the program using &lt;code&gt;python cisco-automation-tutorial.py&lt;/code&gt; we get the output below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;rpc-reply&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:ietf:params:xml:ns:netconf:base:1.0"&lt;/span&gt; &lt;span class="na"&gt;message-id=&lt;/span&gt;&lt;span class="s"&gt;"urn:uuid:f4241f31-5098-475c-9d01-bcf34df25643"&lt;/span&gt; 
  &lt;span class="na"&gt;xmlns:nc=&lt;/span&gt;&lt;span class="s"&gt;"urn:ietf:params:xml:ns:netconf:base:1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;data&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;native&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://cisco.com/ns/yang/Cisco-IOS-XE-native"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;interface&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;GigabitEthernet&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;name&lt;/span&gt; &lt;span class="na"&gt;xmlns:nc=&lt;/span&gt;&lt;span class="s"&gt;'urn:ietf:params:xml:ns:netconf:base:1.0'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;ip&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;address&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;primary&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;address&amp;gt;&lt;/span&gt;192.168.159.10&lt;span class="nt"&gt;&amp;lt;/address&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;mask&amp;gt;&lt;/span&gt;255.255.255.0&lt;span class="nt"&gt;&amp;lt;/mask&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/primary&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/address&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/ip&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;mop&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;enabled&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/enabled&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;sysid&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/sysid&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/mop&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;negotiation&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://cisco.com/ns/yang/Cisco-IOS-XE-ethernet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;auto&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/auto&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/negotiation&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/GigabitEthernet&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/interface&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/native&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/data&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/rpc-reply&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can see from the RPC reply that we have now revealed the IOS-XE data structure of an interface.&lt;/p&gt;

&lt;p&gt;We may now go on to use this model as a template for configuring other interfaces. From the RPC reply, copy and paste everything inside the &lt;code&gt;config&lt;/code&gt; tag to a new file entitled "interface.xml". This will become our &lt;a href="https://jinja.palletsprojects.com/en/2.10.x/"&gt;Jinja template&lt;/a&gt;. Next, replace the IP address, subnet mask and interface index with Jinja variables using the double curly braces syntax. Once done, you should end up with a file like the one below. Ensure the file is placed in the same directory as your python program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;config&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;native&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://cisco.com/ns/yang/Cisco-IOS-XE-native"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;interface&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;GigabitEthernet&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;name&lt;/span&gt; &lt;span class="na"&gt;xmlns:nc=&lt;/span&gt;&lt;span class="s"&gt;'urn:ietf:params:xml:ns:netconf:base:1.0'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ INTERFACE_INDEX }}&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ip&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;address&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;primary&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;address&amp;gt;&lt;/span&gt;{{ IP_ADDRESS }}&lt;span class="nt"&gt;&amp;lt;/address&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;mask&amp;gt;&lt;/span&gt;{{ SUBNET_MASK }}&lt;span class="nt"&gt;&amp;lt;/mask&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/primary&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/address&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ip&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mop&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;enabled&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/enabled&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;sysid&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/sysid&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/mop&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;negotiation&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://cisco.com/ns/yang/Cisco-IOS-XE-ethernet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;auto&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/auto&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/negotiation&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/GigabitEthernet&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/interface&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/native&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Returning to our python program, we may now configure any interface on our router with two steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Template Rendering&lt;/strong&gt; - Render the Jinja template with desired variable values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NETCONF Transaction&lt;/strong&gt; - Send the rendered object as the payload of an &lt;code&gt;edit-config&lt;/code&gt; RPC.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To do this in our python program, add the code below. For our example, we are configuring the interface GigabitEthernet 2 with an address of 10.0.0.1/30.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Render our Jinja template
&lt;/span&gt;&lt;span class="n"&gt;interface_template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'interface.xml'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;interface_rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;interface_template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;INTERFACE_INDEX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;IP_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'10.0.0.1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;SUBNET_MASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'255.255.255.252'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Execute the edit-config RPC
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edit_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'running'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;interface_rendered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After the execution of the program, you should see and "ok" RPC reply from the router indicating that the transaction completed successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;rpc-reply&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"urn:ietf:params:xml:ns:netconf:base:1.0"&lt;/span&gt; &lt;span class="na"&gt;message-id=&lt;/span&gt;&lt;span class="s"&gt;"urn:uuid:2db17593-b51d-4ab2-be28-a268441d6af1"&lt;/span&gt; 
  &lt;span class="na"&gt;xmlns:nc=&lt;/span&gt;&lt;span class="s"&gt;"urn:ietf:params:xml:ns:netconf:base:1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ok/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/rpc-reply&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, verify that the configuration actually exists on the router with the familiar CLI command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Router#show running-config interface GigabitEthernet 2
Building configuration...

Current configuration : 129 bytes
!
interface GigabitEthernet2
 ip address 10.0.0.1 255.255.255.252
 shutdown
 negotiation auto
 no mop enabled
 no mop sysid
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Although the example we showed today was quite trivial, I hope it inspires you to think of the possibilities of how this technology can be scaled. For example, you could build an API back-end with atomic Jinja templates for configuring absolutely anything and everything on a network.&lt;/p&gt;

&lt;p&gt;Multiple front-end apps could then be built which consume this configuration service - these front end tools could be network orchestrators, change management software, order-to-activation tools, policy managers and much more. This technology truly does enable the digital transformation of companies part of the networking industry.&lt;/p&gt;

&lt;p&gt;Finally, if you haven't heard of &lt;a href="https://dev.to/ultra-config-generator/"&gt;Ultra Config Generator&lt;/a&gt; I would highly recommend that you check it out. It is essentially an out of the box solution for the technology we just discussed which allows companies to rapidly digitize their configuration processes. We designed the product to allow network engineers to generate network configuration in a highly flexible, efficient and elegant manner. Our customers love the application and I hope that you will too.&lt;/p&gt;

&lt;p&gt;Thank you very much for reading and if you like the content feel free to follow.&lt;/p&gt;

&lt;p&gt;Take care until next time!&lt;/p&gt;

&lt;p&gt;Alec&lt;/p&gt;

</description>
      <category>python</category>
      <category>netconf</category>
      <category>yang</category>
      <category>jinja</category>
    </item>
    <item>
      <title>Refusing to give up on your dreams, Storytime</title>
      <dc:creator>Alec Buda</dc:creator>
      <pubDate>Fri, 16 Aug 2019 04:04:39 +0000</pubDate>
      <link>https://dev.to/alecbuda/refusing-to-give-up-on-your-dreams-storytime-1na1</link>
      <guid>https://dev.to/alecbuda/refusing-to-give-up-on-your-dreams-storytime-1na1</guid>
      <description>&lt;p&gt;Everyone has innate dreams and passions - people just find them at different stages of their life. For me, it happened when I was 22 years old. I'll never forget that moment - not only did I discover what I wanted to do with my life, I also discovered my identity.&lt;/p&gt;

&lt;p&gt;Backtracking a few years earlier, I was always a pretty random guy. I got really into the guitar one year and jammed all day with friends. I spent a short period of time doing street magic. One month I'd have an emo fringe and the next a mohawk. So yeah - I was all over the place. The only consistency here was that I loved to be creative and learn new things.&lt;/p&gt;

&lt;p&gt;Study-wise I was doing a masters in electrical engineering and loved mathematics and problem solving as much as I loved creating and building. It wasn't until after my degree though that I connected the dots to entrepreneurship as my path.&lt;/p&gt;

&lt;p&gt;The day I connected the dots was within the same week I completed my degree. I was hanging out with my brother and his girlfriend at their house. I had a 3 month holiday ahead of me before starting a full time job as an Engineer.  At one point, we chatted about what I was going to get up to in the 3 months I had off before starting the job. I made a joke about starting a business to sell an electronics gadget I came up with in my last couple of months at uni. I didn't think much of it at the time, but when I was heading home that evening on the train, watching the sun set across some beautiful wheat fields, that I had the realisation. I knew how to design an electronics gadget from my degree - what's the worst that could happen if I actually tried to create this business? The more I thought about it, the more excited I got.&lt;/p&gt;

&lt;p&gt;Fast-forward 3 months and I'd created a prototype. Fast-forward another 3 months and I made my first sale on eBay.  Go forward another 2 years and the business became a fully established online store with an annual profit on par with a full-time salary.&lt;/p&gt;

&lt;p&gt;The story doesn't end there, unfortunately. You see, I never quit my full time job. And the truth is, I don't find fulfilment at all from my full time job. Entrepreneurs out there might know what I mean - some people just can't find fulfilment as an employee, irrespective of the job. In my opinion, there is nothing wrong with this, just as there is nothing wrong with someone who does find peace as an employee. It is just is the way things are.&lt;/p&gt;

&lt;p&gt;With that said, I haven't quit my full time job because of money. Without getting into the details, I know that my first business won't provide the same profit in the long term that it does at present. It simply can't be the business that I go all in on. Also, money is a pretty big factor in my life as the cost of living in my city is high. I won't be able to provide for my family in the same way that my parents did for me without a good income. So, in order to achieve my dream as a full time entrepreneur, I had to start all over again from scratch. Outside of the 40 hours working on my full time job and the 10 hours working on my first business, I started working an additional 20 hours a week building a second business.&lt;/p&gt;

&lt;p&gt;This is when I began studying ReactJS, MongoDB, ExpressJS and GatsbyJS. I had a grip on HTML, CSS and JavaScript but I had no experience with these modern frameworks when I began. On the first day of deciding I needed to build a second business I completed the famous ReactJS tutorial and was hooked. I developed a passion for the MERN stack and spent every night studying and coding a full stack software application. Jump one year forward and I launched the software application on AWS along with a website to market it on. For anyone whoever doubts their ability to become a great software developer, please don't. I myself am definitely not a professional coder by any means but I was still able to make it through perseverance, passion and a determined commitment to never give up on my dreams. I'll throw in a Jack Ma quote here that I love from 1999 in the early days of Alibaba.&lt;/p&gt;

&lt;p&gt;"All of our brains are just as good as theirs. This is the reason we dare to compete with Americans. If we are a good team and know what we want to do, one of us can defeat ten of them. We can beat government agencies and big famous companies because of our innovative spirit. Otherwise, what is the difference between us and them?"&lt;/p&gt;

&lt;p&gt;I haven't reached my dream yet. My new business is still in the early days of marketing. I can say with confidence, however, that it will succeed one day. It might not be this year or next year, but one day it will. I will not stop until it does.&lt;/p&gt;

&lt;p&gt;That will be it for today! Thanks so much for reading. If you are interested in checking out the UI of my new website I'll link it below. I hope that if you have the desire to build your own website it will inspire you as one person truly can do so much.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ultraconfig.com.au"&gt;https://ultraconfig.com.au&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take care!&lt;/p&gt;

&lt;p&gt;Alec&lt;/p&gt;

</description>
      <category>storytime</category>
      <category>entrepreneurship</category>
      <category>motivation</category>
      <category>react</category>
    </item>
  </channel>
</rss>
