3.5. Mạng Bitcoin
Cho đến nay, chúng ta đã thảo luận về khả năng những người tham gia xuất bản một giao dịch và chèn nó vào chuỗi khối như thể điều này xảy ra bởi phép thuật. Trên thực tế, nó xảy ra thông qua mạng Bitcoin, là một mạng ngang hàng kế thừa nhiều ý tưởng từ các mạng ngang hàng khác đã được đề xuất cho tất cả các mục đích khác. Trong mạng Bitcoin, tất cả các nút đều bình đẳng. Không có hệ thống phân cấp—không có nút đặc biệt hoặc nút chính. Nó chạy trên TCP và có cấu trúc liên kết ngẫu nhiên, nơi mỗi nút ngang hàng với các nút ngẫu nhiên khác. Các nút mới có thể tham gia bất kỳ lúc nào. Trên thực tế, bạn có thể tải xuống một ứng dụng khách Bitcoin ngay hôm nay, khởi tạo máy tính của bạn dưới dạng một nút và nó sẽ có các quyền và khả năng ngang bằng với mọi quyền và khả năng của mọi nút khác trên mạng Bitcoin.
Mạng thay đổi theo thời gian và khá năng động, bởi vì các nút đi vào và rời khỏi nó. Không có cách nào rõ ràng để rời khỏi mạng. Thay vào đó, nếu một nút không hoạt động trong một thời gian—3 giờ là thời lượng được mã hóa cứng cho các ứng dụng khách thông thường—các nút khác bắt đầu quên nút đó. Bằng cách này, mạng xử lý một cách suôn sẻ các nút trở nên ngoại tuyến.
Nhớ lại rằng các nút kết nối với các nút ngang hàng ngẫu nhiên và không tồn tại cấu trúc liên kết địa lý thuộc bất kỳ loại nào. Giả sử bạn khởi chạy một nút mới và muốn tham gia mạng. Bạn bắt đầu bằng một tin nhắn đơn giản tới một nút mà bạn biết. Đây thường được gọi là nút hạt giống (seed node) của bạn và có một số cách khác nhau để bạn có thể tra cứu danh sách các nút hạt giống để thử kết nối. Bạn gửi một tin nhắn đặc biệt, nói rằng, “Hãy cho tôi biết địa chỉ của tất cả các nút khác trong mạng mà bạn biết.” Bạn có thể lặp lại quá trình với các nút mới mà bạn tìm hiểu bao nhiêu lần tùy ý. Sau đó, bạn có thể chọn những nút để ngang hàng và bạn sẽ là một thành viên hoạt động đầy đủ của mạng Bitcoin. Một số bước khởi tạo liên quan đến tính ngẫu nhiên và kết quả lý tưởng là bạn được xem với một tập hợp các nút ngẫu nhiên. Để tham gia mạng, tất cả những gì bạn cần biết là cách liên hệ với một nút đã có trên mạng.
Mạng tốt cho điều gì? Tất nhiên là để duy trì chuỗi khối. Vì vậy, để xuất bản một giao dịch, chúng ta muốn toàn bộ mạng lưới nghe về nó. Điều này xảy ra thông qua một thuật toán ngập lụt (flooding) đơn giản, đôi khi được gọi là giao thức tin đồn (gossip protocol). Nếu Alice muốn trả cho Bob một số tiền, khách hàng của cô ấy sẽ tạo và nút của cô ấy sẽ gửi giao dịch này đến tất cả các nút mà nó được xem xét. Mỗi nút đó thực hiện một loạt các kiểm tra để xác định xem có chấp nhận và chuyển tiếp giao dịch hay không. Nếu các lần kiểm tra vượt qua, nút chấp nhận sẽ gửi nó đến tất cả các nút ngang hàng của nó. Các nút nghe về một giao dịch đưa nó vào một hàng đợi các giao dịch mà chúng đã nghe nói về nhưng giao dịch đó chưa có trong chuỗi khối. Nếu một nút nghe về một giao dịch đã có trong hàng đợi của nó, nó sẽ không phát đi nữa. Điều này đảm bảo rằng giao thức tràn ngập kết thúc và các giao dịch không lặp lại trên mạng mãi mãi. Hãy nhớ rằng mọi giao dịch được xác định duy nhất bởi hàm băm của nó, vì vậy, thật dễ dàng để tra cứu một giao dịch trong hàng đợi.
Khi các nút nghe về một giao dịch mới, làm cách nào để chúng quyết định xem chúng có nên lan truyền nó hay không? Có bốn kiểm tra. Kiểm tra đầu tiên và quan trọng nhất là xác thực giao dịch—giao dịch phải hợp lệ với chuỗi khối hiện tại. Các nút chạy tập lệnh cho mỗi đầu ra trước đó được mua lại và đảm bảo rằng các tập lệnh trả về true. Thứ hai, chúng kiểm tra xem các kết quả đầu ra được mua lại chưa được chi tiêu. Thứ ba, chúng sẽ không chuyển tiếp một giao dịch đã thấy, như đã đề cập trước đó. Thứ tư, theo mặc định, các nút chỉ chấp nhận và chuyển tiếp các tập lệnh tiêu chuẩn dựa trên một danh sách nhỏ các tập lệnh.
Tất cả những kiểm tra này chỉ là kiểm tra sự lành mạnh. Tất cả các nút hoạt động tốt đều triển khai những điều này để cố gắng giữ cho mạng khỏe mạnh và hoạt động bình thường, nhưng không có quy tắc nào nói rằng các nút phải tuân theo các bước cụ thể này. Vì đó là mạng ngang hàng và bất kỳ ai cũng có thể tham gia, luôn có khả năng một nút có thể chuyển tiếp chi tiêu gấp đôi, giao dịch không chuẩn hoặc giao dịch hoàn toàn không hợp lệ. Đó là lý do tại sao mỗi nút phải tự kiểm tra.
Vì mạng có độ trễ, có thể các nút sẽ kết thúc với các phiên bản khác nhau của hàng đợi giao dịch đang chờ xử lý. Điều này trở nên đặc biệt thú vị và quan trọng khi cố gắng chi tiêu gấp đôi. Giả sử Alice cố gắng trả cùng một số bitcoin cho cả Bob và Charlie, và cô ấy gửi hai giao dịch gần như cùng một lúc. Một số nút sẽ nghe về giao dịch Alice → Bob đầu tiên, trong khi những nút khác sẽ nghe về giao dịch Alice → Charlie trước tiên. Khi một nút nghe về một trong hai giao dịch, nó sẽ thêm giao dịch vào hàng đợi giao dịch của nó. Nếu nó nghe về cái kia sau đó, nút sẽ phát hiện ra một khoản chi tiêu gấp đôi. Sau đó, nút này bỏ giao dịch thứ hai và sẽ không chuyển tiếp hoặc thêm nó vào hàng đợi giao dịch của nó. Do đó, các nút sẽ tạm thời không thống nhất về việc giao dịch nào nên được đưa vào khối tiếp theo. Đây được gọi là “điều kiện cuộc đua” (race condition).
Điều đáng mừng là tình huống này có thể dễ dàng xử lý. Bất kỳ ai khai thác khối tiếp theo về cơ bản sẽ phá vỡ ràng buộc và quyết định giao dịch nào trong số hai giao dịch đang chờ xử lý đó sẽ được đưa vĩnh viễn vào một khối. Giả sử giao dịch Alice → Charlie đưa nó vào khối. Khi các nút có giao dịch Alice → Bob nghe về khối này, chúng sẽ loại bỏ giao dịch khỏi hàng đợi bộ nhớ của mình, vì đó là chi tiêu gấp đôi. Khi các nút có giao dịch Alice → Charlie nghe về khối này, chúng sẽ loại bỏ giao dịch đó khỏi hàng đợi bộ nhớ của mình, vì nó đã nằm trong chuỗi khối. Vì vậy, sẽ không có bất đồng nữa một khi khối này lan truyền qua mạng.
Vì hành vi mặc định là để các nút giữ lại bất cứ điều gì chúng nghe thấy đầu tiên, nên vị trí mạng rất quan trọng. Nếu hai giao dịch hoặc khối xung đột được thông báo ở hai vị trí khác nhau trong mạng, cả hai đều bắt đầu tràn ngập khắp mạng; giao dịch nào mà một nút nhìn thấy đầu tiên sẽ phụ thuộc vào vị trí của nó trong mạng.
Tất nhiên điều này giả định rằng mọi nút thực hiện logic này rằng nó giữ những gì nó nghe về đầu tiên. Nhưng không có cơ quan trung ương nào thực thi hành vi này và các nút có thể tự do thực hiện bất kỳ logic nào khác mà chúng muốn để chọn giao dịch nào sẽ giữ và có chuyển tiếp giao dịch hay không. Chúng ta sẽ xem xét kỹ hơn các ưu đãi dành cho người khai thác trong Chương 5.
Cho đến nay, chúng ta chủ yếu thảo luận về việc lan truyền các giao dịch. Logic để thông báo một khối mới, khi một người khai thác tìm thấy một khối, gần giống hệt như việc lan truyền một giao dịch mới và nó phải tuân theo các điều kiện cuộc đua giống nhau. Nếu hai khối hợp lệ được khai thác cùng một lúc, thì chỉ một trong số này có thể được đưa vào chuỗi đồng thuận dài hạn. Cuối cùng, khối nào trong số các khối này sẽ được đưa vào tùy thuộc vào khối nào mà các nút khác xây dựng trên đó và khối nào không lọt vào chuỗi đồng thuận sẽ bị mồ côi.
Xác thực một khối phức tạp hơn xác thực các giao dịch. Ngoài việc xác thực tiêu đề và đảm bảo rằng giá trị băm nằm trong phạm vi chấp nhận được, các nút phải xác thực mọi giao dịch có trong khối. Cuối cùng, một nút sẽ chuyển tiếp một khối chỉ khi nó được xây dựng trên nhánh dài nhất, dựa trên quan điểm của nó về chuỗi khối (thực sự là một cây các khối) trông như thế nào. Điều này tránh tích tụ fork (rẽ nhánh). Nhưng cũng giống như các giao dịch, các nút có thể triển khai các logic khác nhau—chúng có thể chuyển tiếp các khối không hợp lệ hoặc các khối xây dựng từ một điểm trước đó trong chuỗi khối. Hành động thứ hai dẫn đến một đợt fork, nhưng giao thức được thiết kế để chịu được các đợt fork nhỏ.
Giao dịch không xác nhận (Zero-Confirmation) và phí thay thế (Replace-by-Fee)
Trong Chương 2, chúng ta đã xem xét các giao dịch không xác nhận, trong đó người nhận chấp nhận giao dịch ngay khi nó được phát trên mạng. Điều này không được thiết kế để an toàn trước chi tiêu gấp đôi. Nhưng như chúng ta đã thấy, hành vi mặc định của các thợ đào trong trường hợp có các giao dịch xung đột là bao gồm giao dịch mà họ nhận được trước, điều này khiến việc chi tiêu gấp đôi so với các giao dịch không xác nhận trở nên khó khăn vừa phải. Do đó, và do sự tiện lợi của chúng, các giao dịch không xác nhận đã trở nên phổ biến.
Kể từ năm 2013, một số người tham gia đã thể hiện sự quan tâm đến việc thay đổi chính sách mặc định thành phí thay thế, theo đó các nút thay thế một giao dịch đang chờ xử lý trong hàng đợi của chúng nếu chúng nghe nói về một giao dịch xung đột bao gồm phí cao hơn. Đây là hành vi hợp lý cho các thợ đào, ít nhất là trong ngắn hạn, vì nó đảm bảo một khoản phí tốt hơn cho họ. Tuy nhiên, tính theo phí thay thế sẽ làm cho việc chi tiêu gấp đôi chống lại các cuộc tấn công không xác nhận dễ dàng hơn nhiều trong thực tế.
Do đó, tính phí thay thế đã thu hút nhiều tranh cãi, cả về câu hỏi kỹ thuật về việc liệu có thể ngăn chặn hoặc ngăn chặn chi tiêu gấp đôi trong một thế giới thay thế bằng phí hay không, và câu hỏi triết học về việc liệu Bitcoin có nên cố gắng hỗ trợ zero- xác nhận tốt nhất có thể, hoặc từ bỏ nó. Chúng ta sẽ không đi sâu vào cuộc tranh cãi kéo dài ở đây, nhưng Bitcoin gần đây đã áp dụng tính phí thay thế “chọn tham gia”, theo đó các giao dịch có thể tự đánh dấu (sử dụng trường số thứ tự) là đủ điều kiện để thay thế bằng các giao dịch mức phí cao hơn.
Độ trễ của thuật toán ngập lụt là gì? Hình 3.9 hiển thị thời gian trung bình để các khối mới truyền đến mọi nút trong mạng. Ba đường hiển thị thời gian lan truyền của khối phân vị thứ 25, 50 và 75. Như bạn thấy, thời gian lan truyền về cơ bản tỷ lệ thuận với kích thước của khối. Điều này là do băng thông mạng là điểm nghẽn. Các khối lớn hơn mất hơn 30 giây để truyền đến hầu hết các nút trong mạng. Vì vậy, giao thức không đặc biệt hiệu quả. Trên Internet, 30 giây là một khoảng thời gian khá dài. Trong thiết kế của Bitcoin, việc có một mạng lưới đơn giản với ít cấu trúc và trong đó các nút ngang nhau và có thể đến và đi bất cứ lúc nào được ưu tiên hơn tính hiệu quả. Vì vậy, một khối có thể cần phải đi qua nhiều nút trước khi nó đến các nút ở xa nhất trong mạng. Nếu thay vào đó, mạng được thiết kế từ trên xuống để đạt hiệu quả, nó sẽ đảm bảo rằng đường dẫn giữa hai nút bất kỳ là ngắn.
Kích thước của mạng
Rất khó để đo lường mức độ lớn của mạng lưới, vì nó năng động và không có cơ quan trung ương. Một số nhà nghiên cứu đã đưa ra các ước tính về kích thước. Trên cao cấp, một số ước tính rằng hơn 1 triệu địa chỉ IP trong một tháng nhất định sẽ hoạt động vào một thời điểm nào đó (ít nhất là tạm thời) như một nút Bitcoin. Ngược lại, chỉ có khoảng 5.000 đến 10.000 nút dường như được kết nối vĩnh viễn và hoàn toàn xác thực mọi giao dịch mà chúng nghe thấy. Đây có vẻ là một con số thấp đáng ngạc nhiên, nhưng tính đến năm 2015, không có bằng chứng nào chỉ ra rằng số lượng các nút xác thực đầy đủ đang tăng lên và trên thực tế, nó có thể đang giảm xuống.
HÌNH 3.9. Thời gian lan truyền khối. Biểu đồ này cho thấy thời gian trung bình cần một khối để đạt được các tỷ lệ phần trăm khác nhau của các nút trong mạng. Nguồn: Yonatan Sompolinsky và Aviv Zohar, “Tăng tốc xử lý giao dịch của Bitcoin,” năm 2014. Có tại https://eprint.iacr.org/2013/881.pdf. Dữ liệu do Yonatan Sompolinsky và Aviv Zohar cung cấp.
Yêu cầu lưu trữ
Các nút xác thực hoàn toàn phải được kết nối vĩnh viễn để nghe về tất cả các giao dịch Bitcoin. Một nút ngoại tuyến càng lâu thì càng phải bắt kịp nó khi nó tham gia lại mạng. Các nút như vậy cũng phải lưu trữ toàn bộ chuỗi khối và cần kết nối mạng tốt để có thể nghe mọi giao dịch mới và chuyển tiếp nó đến các nút ngang hàng. Yêu cầu lưu trữ hiện là hàng chục gigabyte (xem Hình 3.10), nằm trong khả năng của một máy tính để bàn hàng hóa.
Cuối cùng, các nút xác thực hoàn toàn phải duy trì toàn bộ tập hợp các đầu ra giao dịch chưa sử dụng, là những đồng tiền có sẵn để chi tiêu. Lý tưởng nhất là điều này nên được lưu trữ trong bộ nhớ thay vì trên đĩa, để khi nghe thấy một giao dịch được đề xuất mới trên mạng, nút có thể nhanh chóng tra cứu các kết quả giao dịch mà nó đang cố gắng xác nhận, chạy các tập lệnh, xem liệu các chữ ký có hợp lệ hay không và thêm giao dịch vào hàng đợi giao dịch. Tính đến giữa năm 2014, hơn 44 triệu giao dịch đã được thực hiện trên chuỗi khối, trong đó 12 triệu giao dịch chưa được sử dụng. May mắn thay, nó vẫn đủ nhỏ để vừa với bộ nhớ chưa đến gigabyte trong một cấu trúc dữ liệu hiệu quả.
HÌNH 3.10. Kích thước của chuỗi khối. Các nút xác thực hoàn toàn phải lưu trữ toàn bộ chuỗi khối, tính đến cuối năm 2015, là hơn 50 gigabyte.
Nút nhẹ (Lightweight Nodes)
Trái ngược với các nút xác thực hoàn toàn, có các nút nhẹ, còn được gọi là ứng dụng khách “mỏng” hoặc ứng dụng khách “Xác minh thanh toán được đơn giản hóa” (SPV). Trên thực tế, gần như tất cả các nút trên mạng Bitcoin đều là các nút nhẹ. Các nút này khác với các nút xác thực hoàn toàn ở chỗ chúng không lưu trữ toàn bộ chuỗi khối. Chúng chỉ lưu trữ các phần mà chúng cần để xác minh các giao dịch cụ thể liên quan đến chúng. Nếu bạn sử dụng một chương trình ví, nó thường kết hợp một nút SPV. Nút tải xuống các tiêu đề khối và các giao dịch đại diện cho các khoản thanh toán đến địa chỉ của bạn.
Một nút SPV không có mức độ bảo mật của một nút xác thực hoàn toàn. Vì nút có tiêu đề khối, nó có thể kiểm tra xem các khối có khó khai thác hay không, nhưng nó không thể kiểm tra xem mọi giao dịch được bao gồm trong một khối có thực sự hợp lệ hay không, vì nó không có lịch sử giao dịch và không biết tập hợp các đầu ra giao dịch chưa sử dụng. Các nút SPV chỉ có thể xác thực các giao dịch thực sự ảnh hưởng đến chúng. Vì vậy, về cơ bản chúng tin tưởng các nút xác thực hoàn toàn đã xác thực tất cả các giao dịch khác ngoài đó. Đây không phải là một sự đánh đổi bảo mật tồi. Các nút SPV giả định rằng các nút xác thực hoàn toàn tồn tại và đang thực hiện công việc khó khăn và nếu các thợ đào gặp khó khăn khi khai thác khối này (đó là một quá trình thực sự tốn kém), họ có thể cũng đã thực hiện một số xác thực để đảm bảo rằng khối sẽ không không bị từ chối.
Tiết kiệm chi phí khi trở thành một nút SPV là rất lớn. Các tiêu đề khối chỉ có kích thước khoảng 1 / 1.000 của chuỗi khối. Vì vậy, thay vì lưu trữ vài chục GB, nó chỉ là vài chục MB. Ngay cả một chiếc điện thoại thông minh cũng có thể dễ dàng hoạt động như một nút SPV trong mạng Bitcoin.
Vì Bitcoin dựa trên một giao thức mở, lý tưởng là nhiều cách triển khai khác nhau sẽ tương tác với nhau một cách liền mạch. Bằng cách đó, nếu có một lỗi xấu ở một, nó không có khả năng làm hỏng toàn bộ mạng. Tin tốt là giao thức đã được thực hiện lại thành công từ đầu. Tin xấu là hầu hết các nút trên mạng đang chạy thư viện bitcoind, được viết bằng C ++ và được duy trì như một phần của Bitcoin Core, triển khai tham chiếu của Bitcoin.