Crear blockchain privada de waves

in #waves7 years ago

Nuestro primer nodo

Me he decidido a escribir este tuto, después de pegarme con la instalación de una blockchain privada de waves para un proyecto interno y de tener muchos problemas con la documentación oficial, hay aspectos con los que he tenido que pegarme bastante para poder tener la blockchain privada funcionando tal como debería.

La mejor manera de probar si no tenemos máquinas disponibles es crear una cuenta de prueba gratuita en Google Cloud que actualmente regala un crédito de 300$ para gastar en un periodo de 12 meses, cómodo y con muy buen rendimiento.
El propósito de este tuto no es cubrir la instalación de SO tanto en Cloud como on premise, por internet hay mucho material que cubre estos aspectos.

Como SO para la blockchain he elegido Ubuntu, yo soy más de Centos, pero Waves tiene los paquetes preparados para Ubuntu, la versión que he puesto ha sido la 17.10.
Un vez que tengamos la máquina arrancada, lo primero que tenemos que hacer es instalar el JRE 1.8, procedemos de la siguiente manera

sudo add-apt-repository -y ppa:webupd8team/java
sudo apt-get update
sudo apt-get -y install oracle-java8-installer

Una vez instalado comprobamos que está correctamente instalado comprobando la versión de java con java -version

Después pasamos a instalar sbt
https://www.scala-sbt.org/download.html

echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823
sudo apt-get update
sudo apt-get install sbt

Una vez que tengamos instalados tanto el Java como el sbt, procedemos a clonar el git de waves en la ruta que elijamos:

git clone https://github.com/wavesplatform/Waves.git

Entramos en la carpeta Waves que nos ha creado el git, y editamos el fichero de ejemplo de creación del bloque de genesis (primer bloque de nuestra blockchain) src/test/resources/genesis.example.conf, en el que se definirá que Addresses tienen el saldo total de los tokens creados, en este caso serán waves, pero son nuestros propios waves.

vi src/test/resources/genesis.example.conf

Como se puede ver en la siguiente imagen tenemos un timestamp de creación del
Genesis, el comentario del fichero dice que se comente si se quiere el segundo actual, pero a mi me da fallo la creación de la información de genesis con esta línea comentada, por lo tanto lo mejor sería poner la fecha actual, para conocer que segundo es el actual podemos usar el comando date +%s , a lo que hay que añadir tres ceros al final 000, ya que el parámetro está en ms.

Una vez tengamos el archivo editado, pasamos a crear la info del génesis, para ello tenemos que ejecutar:

sbt "test:runMain tools.GenesisBlockGenerator src/test/resources/genesis.example.conf"

Esto, la primera vez que lo lancemos se descarga y compila un montón de jars, con algunos warnings sin importancia.
El proceso de generación del Genesis es un poco lento, paciencia.

Una vez terminado, nos tiene que dar como resultado de la generación, algo similar a esto:

Addresses:
(0):
Seed text: foo0
Seed: 3csAfH
Account seed: 58zgAnBg775J6NKd4qVtfeX3m5TBMeizHNY9STvm2N87
Private account key: FYLXp1ecxQ6WCPD4axTotHU9RVfPCBLfSeKx1XSCyvdT
Public account key: GbGEY3XVc2ohdv6hQBukVKSTQyqP8rjQ8Kigkj6bL57S
Account address: 3JfE6tjeT7PnpuDQKxiVNLn4TJUFhuMaaT5

Settings:
genesis {
average-block-delay: 60000ms
initial-base-target: 153722867
timestamp: 1500635421931
block-timestamp: 1500635421931
signature: "4xpkFL6TdaEwqZnDcuMVSei77rR5S8EpsEr3dkFMNoDCtxxhBVQCbzkeGwKLdyT5zcPumpNnqgybb3qeLV5QtEKv"
initial-balance: 10000000000000000
transactions = [
{recipient: "3JfE6tjeT7PnpuDQKxiVNLn4TJUFhuMaaT5", amount: 10000000000000}
]
}

Ahora tenemos que crear un fichero de configuración, por ejemplo waves-privada.conf y sustituir aquella información relevante de nuestro génesis en el, aquí hay un ejemplo del archivo con comentarios sobre donde tenemos que sustituir nuestra info:

waves {
  # Carpeta donde queramos tener los datos de la blockchain
  directory=/var/lib/waves-privada
  logging-level = DEBUG
  blockchain {
    type: CUSTOM
    custom {
      # Cambiar a la letra elegida para nuestra blockchain
      # tiene que ser la misma usada en la generación del Genesis
      address-scheme-character: "R"
      # various parameters of network consensus
     functionality {
        feature-check-blocks-period = 30
        blocks-for-feature-activation = 25
        allow-temporary-negative-until: 0
        allow-invalid-payment-transactions-by-timestamp: 0
        require-sorted-transactions-after: 0
        generation-balance-depth-from-50-to-1000-after-height: 0
        minimal-generating-balance-after: 0
        allow-transactions-from-future-until: 0
        allow-unissued-assets-until: 0
        require-payment-unique-id-after: 0
        allow-invalid-reissue-in-same-block-until-timestamp: 0
        allow-multiple-lease-cancel-transaction-until-timestamp: 0
        reset-effective-balances-at-height: 1
        allow-leased-balance-transfer-until: 0
        block-version-3-after-height: 0
        double-features-periods-after-height: 1000000000
        pre-activated-features = {
          2 = 0
        }
      }
    # Aquí tendremos que pegar el resultado de la generación del Genesis
    # Muy importante, comentar signature, de otro modo no arrancará nuestro nodo
      genesis {
        average-block-delay: 60s
        initial-base-target: 153722867
        timestamp: 1500635421931
        block-timestamp: 1500635421931
        #signature: "4xpkFL6TdaEwqZnDcuMVSei77rR5S8EpsEr3dkFMNoDCtxxhBVQCbzkeGwKLdyT5zcPumpNnqgybb3qeLV5QtEKv"
        initial-balance: 10000000000000000
        transactions = [
          {recipient: "3JfE6tjeT7PnpuDQKxiVNLn4TJUFhuMaaT5", amount: 10000000000000}
        ]
       }
    }
  }
 # Esta sección la usaremos después cuando añadamos nuestro nuevo nodo 
 network {
    bind-address = "0.0.0.0"
    port = 6860
    known-peers = []
    node-name = "L custom node 1"
    # Importante, si queremos usar otros nodos en red local/internet, debemos declarar la
    # IP que nos van a llamar el resto de nodos   
    declared-address = "10.24.0.1:6860"
  }
  wallet {
    #password que queramos usar para proteger el archivo de wallets
    password = "password"
    #Aquí tenemos que poner el seed que se ha generado con el Génesis
    seed = "3csAfH"
  }
  rest-api {
    enable = yes
    bind-address = "0.0.0.0"
    port = 6861
    #Este hash sirve para proteger las llamadas del API, luego veremos como actualizarlo
    api-key-hash = "Hash_actualizar"
  }
  miner {
    interval-after-last-block-then-generation-is-allowed = 999d
    quorum = 0
  }
}

Una vez que tenemos nuestro archivo creado, ejecutamos:

sbt "run waves-privada.conf"

Después de un buen rato, ya que en esta primera ejecución está generando el primer bloque y tarda bastante, tendremos nuestra blockchain privada corriendo.

Instalar Waves como servicio

Ya tenemos nuestro primer nodo funcionando, ahora podemos instalar el paquete de waves para poder arrancar nuestro nodo sin necesidad de usar sbt y poder dejarlo como un servicio en el servidor.
Primero desde https://github.com/wavesplatform/Waves/releases nos descargamos el paquete .deb de la red tesnet, ahora mismo es la versión 0.10.1 https://github.com/wavesplatform/Waves/releases/download/v0.10.1/waves-testnet_0.10.1_all.deb

Instalamos con

sudo dpkg -i waves.deb*

Una vez instalado tenemos que hacer varios cambios para lograr que el servicio waves arranque con nuestro archivo de configuración y nuestra blockchain privada. Lo primero es colocar nuestra configuración en el archivo que el servicio va a buscar waves.conf, que está en la carpeta /etc/waves-testnet.

cd /etc/waves-testnet
sudo mv waves.conf waves_testnet.conf
sudo cp /home/roberto/Waves/waves-privada.conf ./waves.conf

Ahora tenemos que editar el fichero /lib/systemd/system/waves-testnet.service para cambiar el directorio donde vamos a tener los datos de nuestra blockchain privada, editamos el parámetro Dwaves.directory y colocamos el directorio que hayamos elegido para guardar los datos.

sudo vi /lib/systemd/system/waves-testnet.service

También editamos el fichero application.ini que se encuentra también en el directorio /etc/waves-testnet

sudo vi application.ini

Y le añadimos la línea* -J-Dwaves.directory=/var/lib/waves-private/* con nuestro directorio.

Como hemos modificado el archivo de configuración del servicio waves-testnet tenemos que volver a cargar el demonio de servicios para que nos reconozca los cambios

sudo systemctl daemon-reload

Damos permisos al usuario waves-testnet en nuestro directorio de datos

sudo chown -R waves-testnet:waves-testnet /var/lib/waves-privada

Y arrancamos el servicio (si soy de la vieja escuela)

sudo service waves-testnet start

Si lo prefieres

sudo systemctl start waves.service

Puedes revisar el log del servicio para comprobar que todo está correcto y ha arrancado nuestra blockchain sin errores.

sudo tail -f /var/log/waves-testnet/waves.log

Acceso API de nuestro nodo

Bueno ya tenemos nuestro primer nodo privado funcionando, ya podemos hacerle queries al API para comprobar el estado y empezar a trabajar con él, el puerto como hemos configurado para el API en el ejemplo es el 6861 o aquel que hayamos elegido, tenemos que abrir el firewall para poder acceder al servicio, suponiendo que no está en nuestra red local o equipo propio.
Si estamos en Google Cloud, tenemos que añadir una regla donde indicamos el puerto y le añadimos una etiqueta de destino para después poder asignarla en nuestras VM.

Una vez que tengamos el nodo corriendo y el firewall abierto, en un navegador usamos la url
http://IP-Nodo:6861/api-docs/index.html#!/utils/hashSecure para acceder al API. ¿Por qué esta función exactamente? Para poder crear el api-key necesario para acceder a las funciones de administración del nodo que esta API-web nos ofrece.

Nos pide un message que vendría a ser en este caso cualquier alfanumérico que queremos usar como origen del hash que queramos usar, podemos usar cualquier cadena de caracteres que queramos para generar el hash. El resultado del hash será lo que tenemos que pegar en el parámetro api-key-hash de la sección rest-api de nuestro archivo de configuración
sudo vi /etc/waves-testnet/waves.conf

Después para acceder a las funciones privadas del API tendremos que pegarlo en la caja de texto api_key.

Reiniciamos el servicio waves-testnet para que tenga efecto el cambio.

sudo service waves-testnet restart

Añadir más nodos

Ahora lo que nos faltaría sería añadir otros nodos a nuestra red privada. Para ello, tenemos varias opciones, podemos seguir todos los pasos de nuevo para instalar los nuevos nodos, o aprovechar que estamos usando VM y hacer una copia exacta del nodo actual para después copiarla en uno o varios nodos más. Para ello paramos la instancia, y hacemos una instantánea del HD de la misma, una vez realizada la copia, podemos crear instancias en base a esa instantánea creada.

Arrancamos el nuevo nodo, y lo primero que hacemos es parar el servicio que estará corriendo para poder hacer cambios en la configuración.

sudo service waves-testnet stop

Ahora para tener un nodo totalmente diferente, tenemos que crear un nuevo wallet para este nuevo nodo, de otra manera los 2 nodos pensarían que son los dueños de la Address génesis y empezarían a minar bloques de manera separada y nunca tendríamos una blockchain única.
Para hacerlo yo he encontrado 2 opciones, una es, en el nuevo nodo, ejecutar el comando para crear el nodo génesis de nuevo y que nos devolverá una nueva Address con el seed del wallet. Como la máquina es una copia del nodo exacta, la configuración del archivo de generación de génesis src/test/resources/genesis.example.conf tiene que estar bien configurado con nuestra inicial de cadena elegida, recordad el network-type

sbt "test:runMain tools.GenesisBlockGenerator src/test/resources/genesis.example.conf"

Este comando nos devolverá el Address para la cuenta elegida, además de los parámetros para el nuevo bloque inicial, que ignoraremos.
Ya tenemos el nuevo seed que pondremos en la sección Wallet de nuestro archivo de configuración que está en /etc/waves-testnet/waves.conf.
Otra opción para la creación de esta nueva cuenta y wallet para el nuevo nodo implica usar la librería de Python, pywaves.
Lo primero que hay que hacer es instalar el pywaves para python, y si no han cambiado el master, hay que modificar el fichero * init.py* para poder trabajar con chains privadas.
Aquí hay un fork con los cambios necesarios, https://github.com/rccheca/PyWaves/blob/patch-1/init.py

A continuación os dejo el script https://github.com/rccheca/waves-python que debéis ejecutar para que os cree una nueva Address con el seed codificado. Recordad cambiar la inicial del Chain que elegisteis para vuestra blockchain privada, de otra forma os creara una Address no válida.

Una vez tengamos nuestro seed para el wallet, tenemos que editar el archivo de configuración para añadirlo además de también añadir el peer de nuestro primer Nodo, y nuestra IP en declared-address. Con esto ya tendríamos el segundo nodo configurado para funcionar en nuestra blockchain privada.
Una vez configurado lo arrancamos y si monitorizamos el log, vemos que se conecta con el nodo principal y empieza a sincronizar nuestra Blockchain privada, Yeyyy!!

sudo vi /etc/waves-testnet/waves.conf

Ahora vemos que este nuevo nodo no mina por si mismo, da un error en el log que nos indica que el saldo es insuficiente, esto se debe a que no tiene waves en la Address manejada por el monedero del nodo. Aquí podemos optar por darle unos cuantos waves desde la Address del nodo principal o bien por hacer un lease, “prestarle” , algunos waves desde la misma.
Aquí hay que recordar que Waves es Proof of Stake, con lo que si dejamos una dirección con 100.000.000 de waves y otra con 1.000 la segunda prácticamente no tiene ninguna oportunidad de minar nunca.
Una vez que la dirección del nodo tenga sus tokens, minará cuando le toque según el algoritmo de waves.

Ahora podemos añadir tantos nodos como queramos de la misma forma que hemos seguido para configurar este.

Gracias por llegar hasta aquí ;-).

Sort:  

Congratulations @rccheca! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

You published your First Post

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

Upvote this notification to help all Steemit users. Learn why here!

Woww!!! that's great. Thanks so much.

Resteemed your article. This article was resteemed because you are part of the New Steemians project. You can learn more about it here: https://steemit.com/introduceyourself/@gaman/new-steemians-project-launch

Muy interesante. Gracias