88 "github.com/babylonlabs-io/babylon-benchmark/lib"
99 "github.com/docker/docker/api/types"
1010 "regexp"
11- "strconv "
11+ "strings "
1212 "time"
1313
1414 bbn "github.com/babylonlabs-io/babylon/types"
@@ -71,7 +71,7 @@ func NewManager() (mgr *Manager, err error) {
7171
7272func (m * Manager ) ExecBitcoindCliCmd (ctx context.Context , command []string ) (bytes.Buffer , bytes.Buffer , error ) {
7373 // this is currently hardcoded, as it will be the same for all tests
74- cmd := []string {"bitcoin-cli" , "-chain=regtest" , "-rpcuser=user" , "-rpcpassword=pass" }
74+ cmd := []string {"bitcoin-cli" , "-chain=regtest" , "-datadir=/data/.bitcoin" , "-rpcconnect=127.0.0.1" , "-rpcport=18443" , "- rpcuser=user" , "-rpcpassword=pass" }
7575 cmd = append (cmd , command ... )
7676 return m .ExecCmd (ctx , bitcoindContainerName , cmd )
7777}
@@ -85,21 +85,35 @@ func (m *Manager) ExecCmd(ctx context.Context, containerName string, command []s
8585 }
8686 containerId := m .resources [containerName ].Container .ID
8787
88- var (
89- outBuf bytes.Buffer
90- errBuf bytes.Buffer
91- )
88+ containerInfo , err := m .rawDcClient .ContainerInspect (ctx , containerId )
89+ if err != nil {
90+ fmt .Printf ("🚫 Failed to inspect container %s: %v\n " , containerName , err )
91+ return bytes.Buffer {}, bytes.Buffer {}, fmt .Errorf ("failed to inspect container: %v" , err )
92+ }
9293
93- timeout := 5 * time .Second
94+ fmt .Printf ("📊 Container %s status: %s, running: %v\n " , containerName , containerInfo .State .Status , containerInfo .State .Running )
95+
96+ if ! containerInfo .State .Running {
97+ return bytes.Buffer {}, bytes.Buffer {}, fmt .Errorf ("container %s is not running (status: %s)" , containerName , containerInfo .State .Status )
98+ }
99+
100+ timeout := 120 * time .Second
94101 innerCtx , cancel := context .WithTimeout (ctx , timeout )
95102 defer cancel ()
96103
97104 // We use the `require.Eventually` function because it is only allowed to do one transaction per block without
98105 // sequence numbers. For simplicity, we avoid keeping track of the sequence number and just use the `require.Eventually`.
99- var innerErr error
100- err := lib .Eventually (
106+ var (
107+ innerErr error
108+ outBuf bytes.Buffer
109+ errBuf bytes.Buffer
110+ )
111+ err = lib .Eventually (
101112 innerCtx ,
102113 func () bool {
114+ // Reset buffers for each retry attempt
115+ outBuf .Reset ()
116+ errBuf .Reset ()
103117 exec , err := m .pool .Client .CreateExec (docker.CreateExecOptions {
104118 Context : ctx ,
105119 AttachStdout : true ,
@@ -110,35 +124,61 @@ func (m *Manager) ExecCmd(ctx context.Context, containerName string, command []s
110124 })
111125
112126 if err != nil {
127+ fmt .Printf ("🚫 CreateExec failed with error: %v\n " , err )
113128 innerErr = fmt .Errorf ("failed to create exec: %v" , err )
114129 return false
115130 }
116131
132+ if exec == nil {
133+ fmt .Printf ("🚫 CreateExec returned nil exec object\n " )
134+ innerErr = fmt .Errorf ("CreateExec returned nil exec object" )
135+ return false
136+ }
137+
117138 err = m .pool .Client .StartExec (exec .ID , docker.StartExecOptions {
118139 Context : ctx ,
119140 Detach : false ,
120141 OutputStream : & outBuf ,
121142 ErrorStream : & errBuf ,
122143 })
123144 if err != nil {
124- innerErr = fmt .Errorf ( "failed to create exec : %v" , err )
125-
145+ fmt .Printf ( "🚫 StartExec failed with error : %v\n " , err )
146+ innerErr = fmt . Errorf ( "failed to start exec: %v" , err )
126147 return false
127148 }
128149
129150 errBufString := errBuf .String ()
151+ outBufString := outBuf .String ()
152+
153+ fmt .Printf ("🔍 Debug - stdout: %q, stderr: %q\n " , outBufString , errBufString )
154+
130155 // Note that this does not match all errors.
131156 // This only works if CLI outputs "Error" or "error"
132157 // to stderr.
158+ // Check for real errors vs temporary connection issues during startup
133159 if errRegex .MatchString (errBufString ) {
134- innerErr = fmt .Errorf ("failed to create exec: %v" , err )
160+ // Allow connection errors during startup - bitcoind process exists but RPC isn't ready
161+ if strings .Contains (errBufString , "Could not connect to the server" ) ||
162+ strings .Contains (errBufString , "timeout on transient error" ) {
163+ fmt .Printf ("⏳ Bitcoin RPC not ready yet, retrying...\n " )
164+ innerErr = fmt .Errorf ("bitcoin RPC not ready: %s" , errBufString )
165+ return false // retry
166+ }
167+ // Real errors that shouldn't be retried
168+ fmt .Printf ("🚫 Real error detected in stderr, treating as failure\n " )
169+ innerErr = fmt .Errorf ("bitcoin-cli error: %s" , errBufString )
135170 return false
136171 }
172+
173+ // Success case - RPC command worked
174+ if outBufString != "" || errBufString == "" {
175+ fmt .Printf ("✅ Bitcoin RPC command succeeded - stdout: %q\n " , outBufString )
176+ }
137177
138178 return true
139179 },
140180 timeout ,
141- 500 * time .Millisecond ,
181+ 2 * time .Second ,
142182 )
143183
144184 if err != nil {
@@ -176,11 +216,12 @@ func (m *Manager) RunBitcoindResource(
176216 "-rpcbind=0.0.0.0" ,
177217 "-zmqpubsequence=tcp://0.0.0.0:28333" ,
178218 "-fallbackfee=0.0002" ,
219+ "-datadir=/data/.bitcoin" ,
179220 },
180221 },
181222 func (config * docker.HostConfig ) {
182223 config .PortBindings = map [docker.Port ][]docker.PortBinding {
183- "18443/tcp" : {{HostIP : "" , HostPort : strconv . Itoa ( AllocateUniquePort ()) }}, // only expose what we need
224+ "18443/tcp" : {{HostIP : "" , HostPort : "18443" }}, // use static port mapping, empty HostIP binds to all interfaces
184225 }
185226 config .PublishAllPorts = false // because in dockerfile they already expose them
186227 },
0 commit comments