Prueba de propiedades de nuestro codificador Base58Check con un Oracle externo

Recientemente, escribimos un codificador Base58Check para alimentar nuestro generador de direcciones públicas y claves privadas de Bitcoin. Siendo los desarrolladores diligentes que somos, agregamos una prueba unitaria para asegurarnos de que nuestro codificador funcionaba como esperábamos.

¿Pero fue suficiente?

Llámame cobarde, pero confiar en una prueba unitaria solitaria basada en un solo ejemplo extraído de un artículo wiki no infunde mucha confianza en nuestra solución.

¡Probemos a fondo nuestra solución con la ayuda de herramientas de prueba basadas en propiedades y un oráculo externo!

Oráculos y pruebas de propiedades

El algoritmo de codificación Base58Ch e ck ha sido implementado muchas veces por diferentes desarrolladores. ¿No sería fantástico si pudiéramos comparar automáticamente nuestra implementación con la de ellos?

¡Podemos!

En la lengua vernácula de pruebas basadas en propiedades, esto se conoce como usar un oráculo. Un oráculo es otra implementación de su solución que se sabe que es correcta bajo algún dominio de entradas.

Afortunadamente, tenemos un oráculo perfecto en forma de las herramientas CLI de Bitcoin Explorer. Bitcoin Explorer se envía con una utilidad base58check-encode que Base58Check codifica cualquier cadena Base16 con un byte de versión dado:

Dado este oráculo, podemos probar de manera completa y concisa nuestra implementación con una sola propiedad. La propiedad principal deseada de nuestra solución es que debe coincidir con la salida de bx base58check-encode para todas las entradas válidas.

Las pruebas de propiedades son simples en concepto, pero más difíciles en la práctica.

Es fácil decir que para cualquier binario y byte dado, la salida de nuestra solución debe coincidir con la salida de mi oráculo. En realidad, generar esas entradas y coordinar esas ejecuciones de prueba es un juego completamente diferente.

Afortunadamente, ya se han sentado las bases para nosotros y hay muchas herramientas de prueba de propiedades basadas en Elixir entre las que podemos elegir. Para este ejercicio, usemos StreamData.

Para mojarnos los pies, escribamos una prueba de propiedad simple usando StreamData que verifique la propiedad asociativa de la función de adición Kernel. + / 2 :

La palabra clave propiedad define nuestra nueva prueba de propiedad con una breve descripción de la propiedad bajo prueba.

El bloque comprobar todo nos permite definir nuestras entradas generadas automáticamente y un bloque de funciones que utilizará esas entradas para hacer afirmaciones sobre nuestra propiedad.

En pocas palabras, le estamos diciendo a StreamData que queremos tres enteros aleatorios: a , b y c . Para cada conjunto de a , b y c , queremos verificar que (a + b) + c es igual a a + (b + c) .

StreamData hace esto generando muchos (cien por defecto) conjuntos aleatorios de a , b y c y comparándolos con nuestra afirmaciones. Si alguna afirmación falla, StreamData intentará “reducir” el conjunto de entrada ( a , b y c , en este caso) al caso de prueba fallido más simple posible y preséntenoslo.

Afortunadamente, la adición es asociativa y nuestra prueba pasa.

Consultando el Oracle

Ahora quitemos las ruedas de entrenamiento y escribamos una prueba de propiedad para nuestro codificador Base58Check contra nuestro oráculo externo.

Primero, definiremos un nuevo bloque de prueba:

Dentro de nuestra prueba, generaremos dos variables aleatorias, clave y versión :

Le estamos diciendo a StreamData que la clave puede ser cualquier binario no vacío y que la versión puede ser cualquier byte.

Ahora que tenemos nuestro conjunto de datos de prueba, necesitaremos obtener el resultado de codificar clave con versión utilizando nuestra propia implementación del algoritmo de codificación Base58Check:

A continuación, usaremos System.cmd de Elixir para llamar a bx base58check-encode , pasando nuestra cadena key codificada en Base16 y nuestro versión byte:

Ahora todo lo que queda por hacer es verificar que nuestro resultado coincide con la salida de nuestro oráculo :

Si StreamData detecta alguna falla en esta afirmación, simplificará clave y versión al caso de falla más simple y nos informará la falla.

Pero afortunadamente, nuestra implementación del algoritmo de codificación Base58Check pasa la prueba:

Reflexiones finales

No pretendo ser un experto en pruebas de propiedades. Solo soy un tipo que ha leído algunos artículos y que se subió al tren del bombo publicitario. Dicho esto, las pruebas de propiedades fueron la herramienta perfecta para este trabajo y puedo ver que será una herramienta increíblemente útil en el futuro. Estoy emocionado de incorporarlo a mi arsenal de pruebas.

Si está interesado en las pruebas basadas en propiedades, le recomiendo que consulte las pruebas PropEr Testing de Fred Hebert y los artículos de Hillel Wayne sobre pruebas de hipótesis con funciones de Oracle y pruebas de propiedades con contratos.

Por último, si está interesado en el desarrollo de Bitcoin, le animo a que consulte Mastering Bitcoin de Andreas Antonopoulos.

Publicado originalmente en www.petecorey.com el 12 de febrero de 2018.